From 6105413ada3d3e16a48d28397f04d3ce4af6f29a Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Tue, 6 Dec 2022 20:33:48 +0100 Subject: [PATCH 01/41] :bookmark: 0.20.1-SNAPSHOT --- core/pom.xml | 2 +- core/src/main/resources/plugin.yml | 4 ++-- dist/pom.xml | 2 +- pom.xml | 4 ++-- v1_12_R1/pom.xml | 2 +- v1_15_R1/pom.xml | 2 +- v1_16_R1/pom.xml | 2 +- v1_16_R2/pom.xml | 2 +- v1_16_R3/pom.xml | 2 +- v1_17_R1/pom.xml | 2 +- v1_18_R1/pom.xml | 2 +- v1_18_R2/pom.xml | 2 +- v1_19_R1/pom.xml | 2 +- v1_9_R1/pom.xml | 2 +- v1_9_R2/pom.xml | 2 +- 15 files changed, 17 insertions(+), 17 deletions(-) diff --git a/core/pom.xml b/core/pom.xml index 282d4d95..c819500e 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -8,7 +8,7 @@ fr.skytasul beautyquests-parent - 0.20.0 + 0.20.1-SNAPSHOT diff --git a/core/src/main/resources/plugin.yml b/core/src/main/resources/plugin.yml index 69b0acd1..82bce6ab 100644 --- a/core/src/main/resources/plugin.yml +++ b/core/src/main/resources/plugin.yml @@ -1,7 +1,7 @@ name: BeautyQuests author: SkytAsul -#version: "${human.version}_BUILD${build.number}" -version: "${human.version}" +version: "${human.version}_BUILD${build.number}" +#version: "${human.version}" description: Quests system with a simple graphical interface. website: https://www.spigotmc.org/resources/beautyquests.39255/ api-version: 1.13 diff --git a/dist/pom.xml b/dist/pom.xml index 8f6401fb..21e66311 100644 --- a/dist/pom.xml +++ b/dist/pom.xml @@ -7,7 +7,7 @@ fr.skytasul beautyquests-parent - 0.20.0 + 0.20.1-SNAPSHOT diff --git a/pom.xml b/pom.xml index c1397d0d..1d2aabd1 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ fr.skytasul beautyquests-parent - 0.20.0 + 0.20.1-SNAPSHOT pom beautyquests @@ -18,7 +18,7 @@ 1.8 true unknown - 0.20 + 0.20.1 diff --git a/v1_12_R1/pom.xml b/v1_12_R1/pom.xml index a7e5d278..fa748964 100644 --- a/v1_12_R1/pom.xml +++ b/v1_12_R1/pom.xml @@ -7,7 +7,7 @@ fr.skytasul beautyquests-parent - 0.20.0 + 0.20.1-SNAPSHOT true diff --git a/v1_15_R1/pom.xml b/v1_15_R1/pom.xml index 2f7c5226..7fb6f879 100644 --- a/v1_15_R1/pom.xml +++ b/v1_15_R1/pom.xml @@ -7,7 +7,7 @@ fr.skytasul beautyquests-parent - 0.20.0 + 0.20.1-SNAPSHOT true diff --git a/v1_16_R1/pom.xml b/v1_16_R1/pom.xml index 974aa11a..f17c325c 100644 --- a/v1_16_R1/pom.xml +++ b/v1_16_R1/pom.xml @@ -7,7 +7,7 @@ fr.skytasul beautyquests-parent - 0.20.0 + 0.20.1-SNAPSHOT true diff --git a/v1_16_R2/pom.xml b/v1_16_R2/pom.xml index 69774e5b..ed232025 100644 --- a/v1_16_R2/pom.xml +++ b/v1_16_R2/pom.xml @@ -7,7 +7,7 @@ fr.skytasul beautyquests-parent - 0.20.0 + 0.20.1-SNAPSHOT true diff --git a/v1_16_R3/pom.xml b/v1_16_R3/pom.xml index 636a5263..6e556d1a 100644 --- a/v1_16_R3/pom.xml +++ b/v1_16_R3/pom.xml @@ -7,7 +7,7 @@ fr.skytasul beautyquests-parent - 0.20.0 + 0.20.1-SNAPSHOT true diff --git a/v1_17_R1/pom.xml b/v1_17_R1/pom.xml index c1c895d0..d4b05b90 100644 --- a/v1_17_R1/pom.xml +++ b/v1_17_R1/pom.xml @@ -8,7 +8,7 @@ fr.skytasul beautyquests-parent - 0.20.0 + 0.20.1-SNAPSHOT diff --git a/v1_18_R1/pom.xml b/v1_18_R1/pom.xml index 9aaaeb9e..4014bee2 100644 --- a/v1_18_R1/pom.xml +++ b/v1_18_R1/pom.xml @@ -8,7 +8,7 @@ fr.skytasul beautyquests-parent - 0.20.0 + 0.20.1-SNAPSHOT diff --git a/v1_18_R2/pom.xml b/v1_18_R2/pom.xml index c2ca518b..83602c9f 100644 --- a/v1_18_R2/pom.xml +++ b/v1_18_R2/pom.xml @@ -8,7 +8,7 @@ fr.skytasul beautyquests-parent - 0.20.0 + 0.20.1-SNAPSHOT diff --git a/v1_19_R1/pom.xml b/v1_19_R1/pom.xml index 6270765e..1258ea96 100644 --- a/v1_19_R1/pom.xml +++ b/v1_19_R1/pom.xml @@ -8,7 +8,7 @@ fr.skytasul beautyquests-parent - 0.20.0 + 0.20.1-SNAPSHOT diff --git a/v1_9_R1/pom.xml b/v1_9_R1/pom.xml index b6060706..dd30aa1d 100644 --- a/v1_9_R1/pom.xml +++ b/v1_9_R1/pom.xml @@ -7,7 +7,7 @@ fr.skytasul beautyquests-parent - 0.20.0 + 0.20.1-SNAPSHOT true diff --git a/v1_9_R2/pom.xml b/v1_9_R2/pom.xml index a5904118..30cf75ce 100644 --- a/v1_9_R2/pom.xml +++ b/v1_9_R2/pom.xml @@ -7,7 +7,7 @@ fr.skytasul beautyquests-parent - 0.20.0 + 0.20.1-SNAPSHOT true From 1620cfd59c708ef63f5f6c27af1695d34ac3977b Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Tue, 6 Dec 2022 20:36:22 +0100 Subject: [PATCH 02/41] :bug: Fixed an issue with BQLocation on 1.8 --- .../quests/utils/types/BQLocation.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/fr/skytasul/quests/utils/types/BQLocation.java b/core/src/main/java/fr/skytasul/quests/utils/types/BQLocation.java index 6b8c3887..a4adc1b4 100644 --- a/core/src/main/java/fr/skytasul/quests/utils/types/BQLocation.java +++ b/core/src/main/java/fr/skytasul/quests/utils/types/BQLocation.java @@ -1,5 +1,6 @@ package fr.skytasul.quests.utils.types; +import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.regex.Pattern; @@ -131,10 +132,23 @@ public int hashCode() { @Override public Map serialize() { - Map map = super.serialize(); + Map map = new HashMap<>(); - if (!map.containsKey("world")) + if (getWorld() == null) { map.put("pattern", worldPattern.pattern()); + } else { + map.put("world", getWorld().getName()); + } + + // we cannot use Location#serialize() to add the following values + // because on 1.8 it will throw an NPE if the world is null + + map.put("x", getX()); + map.put("y", getY()); + map.put("z", getZ()); + + map.put("yaw", getYaw()); + map.put("pitch", getPitch()); return map; } From 8d244b974d93bff50a99180b362e6b43f2b9901a Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Sat, 10 Dec 2022 11:19:26 +0100 Subject: [PATCH 03/41] :arrow_up: Added support for Minecraft 1.19.3 --- dist/pom.xml | 7 ++ pom.xml | 1 + v1_19_R1/dependency-reduced-pom.xml | 4 +- v1_19_R2/dependency-reduced-pom.xml | 93 +++++++++++++++ v1_19_R2/pom.xml | 106 ++++++++++++++++++ .../skytasul/quests/utils/nms/v1_19_R2.java | 57 ++++++++++ 6 files changed, 266 insertions(+), 2 deletions(-) create mode 100644 v1_19_R2/dependency-reduced-pom.xml create mode 100644 v1_19_R2/pom.xml create mode 100644 v1_19_R2/src/main/java/fr/skytasul/quests/utils/nms/v1_19_R2.java diff --git a/dist/pom.xml b/dist/pom.xml index 21e66311..a544314c 100644 --- a/dist/pom.xml +++ b/dist/pom.xml @@ -121,5 +121,12 @@ jar compile + + ${project.groupId} + beautyquests-v1_19_R2 + ${project.version} + jar + compile + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 1d2aabd1..2c4f3611 100644 --- a/pom.xml +++ b/pom.xml @@ -41,6 +41,7 @@ v1_18_R1 v1_18_R2 v1_19_R1 + v1_19_R2 dist diff --git a/v1_19_R1/dependency-reduced-pom.xml b/v1_19_R1/dependency-reduced-pom.xml index db9d80ad..abe2f9b3 100644 --- a/v1_19_R1/dependency-reduced-pom.xml +++ b/v1_19_R1/dependency-reduced-pom.xml @@ -3,7 +3,7 @@ beautyquests-parent fr.skytasul - 0.20.0 + 0.20.1-SNAPSHOT 4.0.0 beautyquests-v1_19_R1 @@ -74,7 +74,7 @@ fr.skytasul beautyquests-core - 0.20.0 + 0.20.1-SNAPSHOT provided diff --git a/v1_19_R2/dependency-reduced-pom.xml b/v1_19_R2/dependency-reduced-pom.xml new file mode 100644 index 00000000..d9d31370 --- /dev/null +++ b/v1_19_R2/dependency-reduced-pom.xml @@ -0,0 +1,93 @@ + + + + beautyquests-parent + fr.skytasul + 0.20.1-SNAPSHOT + + 4.0.0 + beautyquests-v1_19_R2 + + + + net.md-5 + specialsource-maven-plugin + 1.2.4 + + + remap-obf + package + + remap + + + org.spigotmc:minecraft-server:1.19.3-R0.1-SNAPSHOT:txt:maps-mojang + true + org.spigotmc:spigot:1.19.3-R0.1-SNAPSHOT:jar:remapped-mojang + true + remapped-obf + + + + remap-spigot + package + + remap + + + ${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar + org.spigotmc:minecraft-server:1.19.3-R0.1-SNAPSHOT:csrg:maps-spigot + org.spigotmc:spigot:1.19.3-R0.1-SNAPSHOT:jar:remapped-obf + + + + + + maven-shade-plugin + 3.3.0 + + + package + + shade + + + + + + + revxrsal.commands + fr.skytasul.quests.commands.revxrsal + + + + + + + + + jitpack.io + https://jitpack.io + + + + + fr.skytasul + beautyquests-core + 0.20.1-SNAPSHOT + provided + + + org.spigotmc + spigot + 1.19.3-R0.1-SNAPSHOT + remapped-mojang + provided + + + + 17 + 17 + true + + diff --git a/v1_19_R2/pom.xml b/v1_19_R2/pom.xml new file mode 100644 index 00000000..eb77cc86 --- /dev/null +++ b/v1_19_R2/pom.xml @@ -0,0 +1,106 @@ + + + 4.0.0 + jar + beautyquests-v1_19_R2 + + fr.skytasul + beautyquests-parent + 0.20.1-SNAPSHOT + + + + true + 17 + 17 + + + + + jitpack.io + https://jitpack.io + + + + + + fr.skytasul + beautyquests-core + ${project.version} + provided + + + org.spigotmc + spigot + 1.19.3-R0.1-SNAPSHOT + remapped-mojang + provided + + + com.github.Revxrsal.Lamp + paper-internal-dont-use + d72483065c + + + + + + + net.md-5 + specialsource-maven-plugin + 1.2.4 + + + package + + remap + + remap-obf + + org.spigotmc:minecraft-server:1.19.3-R0.1-SNAPSHOT:txt:maps-mojang + true + org.spigotmc:spigot:1.19.3-R0.1-SNAPSHOT:jar:remapped-mojang + true + remapped-obf + + + + package + + remap + + remap-spigot + + ${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar + org.spigotmc:minecraft-server:1.19.3-R0.1-SNAPSHOT:csrg:maps-spigot + org.spigotmc:spigot:1.19.3-R0.1-SNAPSHOT:jar:remapped-obf + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.3.0 + + + + revxrsal.commands + fr.skytasul.quests.commands.revxrsal + + + + + + package + + shade + + + + + + + diff --git a/v1_19_R2/src/main/java/fr/skytasul/quests/utils/nms/v1_19_R2.java b/v1_19_R2/src/main/java/fr/skytasul/quests/utils/nms/v1_19_R2.java new file mode 100644 index 00000000..6ef950ce --- /dev/null +++ b/v1_19_R2/src/main/java/fr/skytasul/quests/utils/nms/v1_19_R2.java @@ -0,0 +1,57 @@ +package fr.skytasul.quests.utils.nms; + +import java.util.List; +import org.apache.commons.lang.Validate; +import org.bukkit.Material; +import org.bukkit.craftbukkit.v1_19_R2.entity.CraftPlayer; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import net.minecraft.core.Holder.Reference; +import net.minecraft.core.HolderLookup.RegistryLookup; +import net.minecraft.core.registries.Registries; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientboundOpenBookPacket; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.Property; +import io.netty.buffer.ByteBuf; + +public class v1_19_R2 extends NMS{ + + @Override + public Object bookPacket(ByteBuf buf){ + return new ClientboundOpenBookPacket(InteractionHand.MAIN_HAND); + } + + @Override + public void sendPacket(Player p, Object packet){ + Validate.isTrue(packet instanceof Packet, "The object specified is not a packet."); + ((CraftPlayer) p).getHandle().connection.send((Packet) packet); + } + + @Override + public double entityNameplateHeight(Entity en) { + return en.getHeight(); + } + + @Override + public List getAvailableBlockProperties(Material material) { + RegistryLookup blockRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BLOCK); + Reference block = blockRegistry + .getOrThrow(ResourceKey.create(Registries.BLOCK, new ResourceLocation(material.getKey().getKey()))); + StateDefinition stateList = block.value().getStateDefinition(); + return stateList.getProperties().stream().map(Property::getName).toList(); + } + + @Override + public List getAvailableBlockTags() { + return MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BLOCK).listTags() + .map(x -> x.key().location().toString()).toList(); + } + +} \ No newline at end of file From 6d9c98f9eed4347b911c3dcf066f5c5e14977380 Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Sat, 10 Dec 2022 11:30:32 +0100 Subject: [PATCH 04/41] :bug: Fixed "quests limit" feature not working correctly --- core/src/main/java/fr/skytasul/quests/structure/Quest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/fr/skytasul/quests/structure/Quest.java b/core/src/main/java/fr/skytasul/quests/structure/Quest.java index 76c7cd0a..0c916e60 100644 --- a/core/src/main/java/fr/skytasul/quests/structure/Quest.java +++ b/core/src/main/java/fr/skytasul/quests/structure/Quest.java @@ -249,7 +249,7 @@ public boolean testRequirements(Player p, PlayerAccount acc, boolean sendMessage } public boolean testQuestLimit(Player p, PlayerAccount acc, boolean sendMessage) { - if (Boolean.FALSE.equals(getOptionValueOrDef(OptionBypassLimit.class))) + if (Boolean.TRUE.equals(getOptionValueOrDef(OptionBypassLimit.class))) return true; int playerMaxLaunchedQuest; OptionalInt playerMaxLaunchedQuestOpt = p.getEffectivePermissions().stream() From d00cbd2e49a69ba60ee0e3a84e64a97e85e43c0b Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Sun, 11 Dec 2022 18:51:13 +0100 Subject: [PATCH 05/41] :bug: Fixed issues with Quest Stop Reward --- .../fr/skytasul/quests/rewards/QuestStopReward.java | 13 +++++++------ .../skytasul/quests/structure/BranchesManager.java | 4 +--- .../java/fr/skytasul/quests/structure/Quest.java | 1 + .../fr/skytasul/quests/structure/QuestBranch.java | 4 +--- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/core/src/main/java/fr/skytasul/quests/rewards/QuestStopReward.java b/core/src/main/java/fr/skytasul/quests/rewards/QuestStopReward.java index 8e4def64..5ceca874 100644 --- a/core/src/main/java/fr/skytasul/quests/rewards/QuestStopReward.java +++ b/core/src/main/java/fr/skytasul/quests/rewards/QuestStopReward.java @@ -1,13 +1,11 @@ package fr.skytasul.quests.rewards; import java.util.List; - import org.bukkit.entity.Player; - import fr.skytasul.quests.api.objects.QuestObjectClickEvent; import fr.skytasul.quests.api.rewards.AbstractReward; import fr.skytasul.quests.players.PlayersManager; -import fr.skytasul.quests.structure.Quest; +import fr.skytasul.quests.utils.DebugUtils; public class QuestStopReward extends AbstractReward { @@ -18,14 +16,17 @@ public void itemClick(QuestObjectClickEvent event) {} @Override public List give(Player p) { - Quest quest = getAttachedQuest(); - if (quest != null) quest.cancelPlayer(PlayersManager.getPlayerAccount(p)); + if (getAttachedQuest() == null) { + DebugUtils.logMessage("No attached quest for " + debugName()); + } else { + getAttachedQuest().cancelPlayer(PlayersManager.getPlayerAccount(p)); + } return null; } @Override public AbstractReward clone() { - return this; + return new QuestStopReward(); } } diff --git a/core/src/main/java/fr/skytasul/quests/structure/BranchesManager.java b/core/src/main/java/fr/skytasul/quests/structure/BranchesManager.java index b65fb97e..db942f25 100644 --- a/core/src/main/java/fr/skytasul/quests/structure/BranchesManager.java +++ b/core/src/main/java/fr/skytasul/quests/structure/BranchesManager.java @@ -7,11 +7,9 @@ import java.util.Map; import java.util.Map.Entry; import java.util.stream.Collectors; - import org.apache.commons.lang.Validate; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; - import fr.skytasul.quests.BeautyQuests; import fr.skytasul.quests.api.QuestsAPI; import fr.skytasul.quests.players.PlayerAccount; @@ -21,7 +19,7 @@ public class BranchesManager{ private Map branches = new LinkedHashMap<>(); - private Quest quest; + private final Quest quest; public BranchesManager(Quest quest){ this.quest = quest; diff --git a/core/src/main/java/fr/skytasul/quests/structure/Quest.java b/core/src/main/java/fr/skytasul/quests/structure/Quest.java index 0c916e60..e45ea582 100644 --- a/core/src/main/java/fr/skytasul/quests/structure/Quest.java +++ b/core/src/main/java/fr/skytasul/quests/structure/Quest.java @@ -203,6 +203,7 @@ public boolean cancelPlayer(PlayerAccount acc) { if (datas == null || !datas.hasStarted()) return false; + DebugUtils.logMessage("Cancelling quest " + id + " for player " + acc.getNameAndID()); manager.remove(acc); QuestsAPI.propagateQuestsHandlers(handler -> handler.questReset(acc, this)); Bukkit.getPluginManager().callEvent(new PlayerQuestResetEvent(acc, this)); diff --git a/core/src/main/java/fr/skytasul/quests/structure/QuestBranch.java b/core/src/main/java/fr/skytasul/quests/structure/QuestBranch.java index c84d6541..9cf48027 100644 --- a/core/src/main/java/fr/skytasul/quests/structure/QuestBranch.java +++ b/core/src/main/java/fr/skytasul/quests/structure/QuestBranch.java @@ -8,12 +8,10 @@ import java.util.Map; import java.util.Map.Entry; 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 fr.skytasul.quests.BeautyQuests; import fr.skytasul.quests.QuestsConfiguration; import fr.skytasul.quests.api.events.PlayerSetStageEvent; @@ -34,7 +32,7 @@ public class QuestBranch { private List asyncReward = new ArrayList<>(5); - private BranchesManager manager; + private final BranchesManager manager; public QuestBranch(BranchesManager manager){ this.manager = manager; From f79710092f905fb9f070cdbc4321daada27bd8d9 Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Sun, 11 Dec 2022 19:16:03 +0100 Subject: [PATCH 06/41] :bug: "region exit" stage is now working with WorldGuard 7 --- .../fr/skytasul/quests/stages/StageArea.java | 21 ++++++++++-- .../worldguard/BQWorldGuard.java | 3 -- .../worldguard/WorldGuardEntryHandler.java | 8 ++--- .../worldguard/WorldGuardExitEvent.java | 33 +++++++++++++++++++ 4 files changed, 55 insertions(+), 10 deletions(-) create mode 100644 core/src/main/java/fr/skytasul/quests/utils/compatibility/worldguard/WorldGuardExitEvent.java diff --git a/core/src/main/java/fr/skytasul/quests/stages/StageArea.java b/core/src/main/java/fr/skytasul/quests/stages/StageArea.java index 37aa8be8..14f5935f 100644 --- a/core/src/main/java/fr/skytasul/quests/stages/StageArea.java +++ b/core/src/main/java/fr/skytasul/quests/stages/StageArea.java @@ -8,11 +8,9 @@ import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.player.PlayerMoveEvent; - import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion; import com.sk89q.worldguard.protection.regions.ProtectedRegion; - import fr.skytasul.quests.api.stages.AbstractStage; import fr.skytasul.quests.api.stages.StageCreation; import fr.skytasul.quests.api.stages.types.Locatable; @@ -30,6 +28,7 @@ import fr.skytasul.quests.utils.XMaterial; import fr.skytasul.quests.utils.compatibility.worldguard.BQWorldGuard; import fr.skytasul.quests.utils.compatibility.worldguard.WorldGuardEntryEvent; +import fr.skytasul.quests.utils.compatibility.worldguard.WorldGuardExitEvent; @LocatableType (types = LocatedType.OTHER) public class StageArea extends AbstractStage implements Locatable.PreciseLocatable { @@ -62,7 +61,7 @@ public void onPlayerMove(PlayerMoveEvent e){ if (BQWorldGuard.getInstance().doHandleEntry()) return; // on WG 7.0 or higher if (e.getFrom().getBlockX() == e.getTo().getBlockX() && e.getFrom().getBlockY() == e.getTo().getBlockY() && e.getFrom().getBlockZ() == e.getTo().getBlockZ()) return; if (hasStarted(e.getPlayer()) && canUpdate(e.getPlayer())) { - if (BQWorldGuard.getInstance().isInRegion(region, e.getTo()) == !exit) { + if (world.equals(e.getTo().getWorld()) && BQWorldGuard.getInstance().isInRegion(region, e.getTo()) == !exit) { finishStage(e.getPlayer()); } } @@ -70,6 +69,8 @@ public void onPlayerMove(PlayerMoveEvent e){ @EventHandler public void onRegionEntry(WorldGuardEntryEvent e) { + if (exit) + return; if (region == null) { DebugUtils.printError("No region for " + toString(), "area" + toString(), 5); return; @@ -79,6 +80,20 @@ public void onRegionEntry(WorldGuardEntryEvent e) { } } + @EventHandler + public void onRegionExit(WorldGuardExitEvent e) { + if (!exit) + return; + if (region == null) { + DebugUtils.printError("No region for " + toString(), "area" + toString(), 5); + return; + } + if (e.getRegionsExited().stream().anyMatch(eventRegion -> eventRegion.getId().equals(region.getId()))) { + if (hasStarted(e.getPlayer()) && canUpdate(e.getPlayer())) + finishStage(e.getPlayer()); + } + } + @Override public String descriptionLine(PlayerAccount acc, Source source){ return Utils.format(Lang.SCOREBOARD_REG.toString(), region.getId()); diff --git a/core/src/main/java/fr/skytasul/quests/utils/compatibility/worldguard/BQWorldGuard.java b/core/src/main/java/fr/skytasul/quests/utils/compatibility/worldguard/BQWorldGuard.java index 96bd0afb..d6ec34e8 100644 --- a/core/src/main/java/fr/skytasul/quests/utils/compatibility/worldguard/BQWorldGuard.java +++ b/core/src/main/java/fr/skytasul/quests/utils/compatibility/worldguard/BQWorldGuard.java @@ -2,17 +2,14 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; - import org.apache.commons.lang.Validate; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; - import com.sk89q.worldguard.bukkit.WorldGuardPlugin; import com.sk89q.worldguard.protection.managers.RegionManager; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import com.sk89q.worldguard.session.SessionManager; - import fr.skytasul.quests.api.QuestsAPI; import fr.skytasul.quests.api.requirements.RequirementCreator; import fr.skytasul.quests.api.stages.StageType; diff --git a/core/src/main/java/fr/skytasul/quests/utils/compatibility/worldguard/WorldGuardEntryHandler.java b/core/src/main/java/fr/skytasul/quests/utils/compatibility/worldguard/WorldGuardEntryHandler.java index 630aee7c..bbcb5a1e 100644 --- a/core/src/main/java/fr/skytasul/quests/utils/compatibility/worldguard/WorldGuardEntryHandler.java +++ b/core/src/main/java/fr/skytasul/quests/utils/compatibility/worldguard/WorldGuardEntryHandler.java @@ -1,10 +1,8 @@ package fr.skytasul.quests.utils.compatibility.worldguard; import java.util.Set; - import org.bukkit.Bukkit; import org.bukkit.entity.Player; - import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.util.Location; import com.sk89q.worldguard.LocalPlayer; @@ -16,7 +14,6 @@ import com.sk89q.worldguard.session.Session; import com.sk89q.worldguard.session.SessionManager; import com.sk89q.worldguard.session.handler.Handler; - import fr.skytasul.quests.api.QuestsAPI; public class WorldGuardEntryHandler extends Handler { @@ -56,7 +53,10 @@ public WorldGuardEntryHandler(Session session) { @Override public boolean onCrossBoundary(LocalPlayer player, Location from, Location to, ApplicableRegionSet toSet, Set entered, Set exited, MoveType moveType) { Player bukkitPlayer = BukkitAdapter.adapt(player); - if (!QuestsAPI.getNPCsManager().isNPC(bukkitPlayer)) Bukkit.getPluginManager().callEvent(new WorldGuardEntryEvent(bukkitPlayer, entered)); + if (!QuestsAPI.getNPCsManager().isNPC(bukkitPlayer)) { + Bukkit.getPluginManager().callEvent(new WorldGuardEntryEvent(bukkitPlayer, entered)); + Bukkit.getPluginManager().callEvent(new WorldGuardExitEvent(bukkitPlayer, exited)); + } return super.onCrossBoundary(player, from, to, toSet, entered, exited, moveType); } diff --git a/core/src/main/java/fr/skytasul/quests/utils/compatibility/worldguard/WorldGuardExitEvent.java b/core/src/main/java/fr/skytasul/quests/utils/compatibility/worldguard/WorldGuardExitEvent.java new file mode 100644 index 00000000..ba64685c --- /dev/null +++ b/core/src/main/java/fr/skytasul/quests/utils/compatibility/worldguard/WorldGuardExitEvent.java @@ -0,0 +1,33 @@ +package fr.skytasul.quests.utils.compatibility.worldguard; + +import java.util.Set; +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; +import com.sk89q.worldguard.protection.regions.ProtectedRegion; + +public class WorldGuardExitEvent extends PlayerEvent { + + private final Set exited; + + WorldGuardExitEvent(Player who, Set exited) { + super(who); + this.exited = exited; + } + + public Set getRegionsExited() { + return exited; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } + + private static final HandlerList handlers = new HandlerList(); + +} From 5520198aa7f2516b209ca7a313419b4868cd1576 Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Fri, 16 Dec 2022 19:25:20 +0100 Subject: [PATCH 07/41] :arrow_up: Updated Lamp command framework to 3.1.1 --- core/pom.xml | 4 +- .../java/fr/skytasul/quests/BeautyQuests.java | 3 +- .../quests/commands/CommandsManager.java | 11 +-- v1_19_R1/dependency-reduced-pom.xml | 93 ------------------- v1_19_R1/pom.xml | 26 ------ v1_19_R2/dependency-reduced-pom.xml | 93 ------------------- v1_19_R2/pom.xml | 26 ------ 7 files changed, 9 insertions(+), 247 deletions(-) delete mode 100644 v1_19_R1/dependency-reduced-pom.xml delete mode 100644 v1_19_R2/dependency-reduced-pom.xml diff --git a/core/pom.xml b/core/pom.xml index c819500e..4024c16e 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -298,12 +298,12 @@ com.github.Revxrsal.Lamp bukkit - d72483065c + 3.1.1 com.github.Revxrsal.Lamp common - d72483065c + 3.1.1 com.zaxxer diff --git a/core/src/main/java/fr/skytasul/quests/BeautyQuests.java b/core/src/main/java/fr/skytasul/quests/BeautyQuests.java index 2b5aeac6..11943d95 100644 --- a/core/src/main/java/fr/skytasul/quests/BeautyQuests.java +++ b/core/src/main/java/fr/skytasul/quests/BeautyQuests.java @@ -249,6 +249,7 @@ private void checkPaper() { private void registerCommands(){ command = new CommandsManager(); command.initializeCommands(); + command.lockCommands(); // we are obligated to register Brigadier during plugin initialization... } private void launchSaveCycle(){ @@ -425,7 +426,7 @@ private void loadDataFile() throws LoadingException { private void loadAllDatas() throws Throwable { if (disable) return; dependencies.lockDependencies(); - command.lockCommands(); + // command.lockCommands(); we cannot register Brigadier after plugin initialization... if (scoreboards == null && QuestsConfiguration.showScoreboards()) { File scFile = new File(getDataFolder(), "scoreboard.yml"); diff --git a/core/src/main/java/fr/skytasul/quests/commands/CommandsManager.java b/core/src/main/java/fr/skytasul/quests/commands/CommandsManager.java index fb70b22e..d5e2a1bc 100644 --- a/core/src/main/java/fr/skytasul/quests/commands/CommandsManager.java +++ b/core/src/main/java/fr/skytasul/quests/commands/CommandsManager.java @@ -3,11 +3,9 @@ import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; - import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Unmodifiable; - import fr.skytasul.quests.BeautyQuests; import fr.skytasul.quests.QuestsConfiguration; import fr.skytasul.quests.api.QuestsAPI; @@ -19,7 +17,6 @@ import fr.skytasul.quests.structure.pools.QuestPool; import fr.skytasul.quests.utils.DebugUtils; import fr.skytasul.quests.utils.Lang; - import revxrsal.commands.autocomplete.SuggestionProvider; import revxrsal.commands.bukkit.BukkitCommandActor; import revxrsal.commands.bukkit.BukkitCommandHandler; @@ -127,14 +124,16 @@ public void registerCommands(String subpath, OrphanCommand... commands) { path = Orphans.path(Arrays.stream(COMMAND_ALIASES).map(x -> x + " " + subpath).toArray(String[]::new)); } handler.register(Arrays.stream(commands).map(path::handler).toArray()); - if (locked) BeautyQuests.logger.warning("Registered commands after final locking."); + // if (locked) BeautyQuests.logger.warning("Registered commands after final locking."); } public void lockCommands() { if (locked) return; locked = true; - handler.registerBrigadier(); - if (handler.isBrigadierSupported()) DebugUtils.logMessage("Brigadier supported!"); + handler.getBrigadier().ifPresent(brigadier -> { + brigadier.register(); + DebugUtils.logMessage("Brigadier registered!"); + }); } public void unload() { diff --git a/v1_19_R1/dependency-reduced-pom.xml b/v1_19_R1/dependency-reduced-pom.xml deleted file mode 100644 index abe2f9b3..00000000 --- a/v1_19_R1/dependency-reduced-pom.xml +++ /dev/null @@ -1,93 +0,0 @@ - - - - beautyquests-parent - fr.skytasul - 0.20.1-SNAPSHOT - - 4.0.0 - beautyquests-v1_19_R1 - - - - net.md-5 - specialsource-maven-plugin - 1.2.4 - - - remap-obf - package - - remap - - - org.spigotmc:minecraft-server:1.19.2-R0.1-SNAPSHOT:txt:maps-mojang - true - org.spigotmc:spigot:1.19.2-R0.1-SNAPSHOT:jar:remapped-mojang - true - remapped-obf - - - - remap-spigot - package - - remap - - - ${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar - org.spigotmc:minecraft-server:1.19.2-R0.1-SNAPSHOT:csrg:maps-spigot - org.spigotmc:spigot:1.19.2-R0.1-SNAPSHOT:jar:remapped-obf - - - - - - maven-shade-plugin - 3.3.0 - - - package - - shade - - - - - - - revxrsal.commands - fr.skytasul.quests.commands.revxrsal - - - - - - - - - jitpack.io - https://jitpack.io - - - - - fr.skytasul - beautyquests-core - 0.20.1-SNAPSHOT - provided - - - org.spigotmc - spigot - 1.19.2-R0.1-SNAPSHOT - remapped-mojang - provided - - - - 17 - 17 - true - - diff --git a/v1_19_R1/pom.xml b/v1_19_R1/pom.xml index 1258ea96..dcebbb82 100644 --- a/v1_19_R1/pom.xml +++ b/v1_19_R1/pom.xml @@ -38,11 +38,6 @@ remapped-mojang provided - - com.github.Revxrsal.Lamp - paper-internal-dont-use - d72483065c - @@ -80,27 +75,6 @@ - - org.apache.maven.plugins - maven-shade-plugin - 3.3.0 - - - - revxrsal.commands - fr.skytasul.quests.commands.revxrsal - - - - - - package - - shade - - - - diff --git a/v1_19_R2/dependency-reduced-pom.xml b/v1_19_R2/dependency-reduced-pom.xml deleted file mode 100644 index d9d31370..00000000 --- a/v1_19_R2/dependency-reduced-pom.xml +++ /dev/null @@ -1,93 +0,0 @@ - - - - beautyquests-parent - fr.skytasul - 0.20.1-SNAPSHOT - - 4.0.0 - beautyquests-v1_19_R2 - - - - net.md-5 - specialsource-maven-plugin - 1.2.4 - - - remap-obf - package - - remap - - - org.spigotmc:minecraft-server:1.19.3-R0.1-SNAPSHOT:txt:maps-mojang - true - org.spigotmc:spigot:1.19.3-R0.1-SNAPSHOT:jar:remapped-mojang - true - remapped-obf - - - - remap-spigot - package - - remap - - - ${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar - org.spigotmc:minecraft-server:1.19.3-R0.1-SNAPSHOT:csrg:maps-spigot - org.spigotmc:spigot:1.19.3-R0.1-SNAPSHOT:jar:remapped-obf - - - - - - maven-shade-plugin - 3.3.0 - - - package - - shade - - - - - - - revxrsal.commands - fr.skytasul.quests.commands.revxrsal - - - - - - - - - jitpack.io - https://jitpack.io - - - - - fr.skytasul - beautyquests-core - 0.20.1-SNAPSHOT - provided - - - org.spigotmc - spigot - 1.19.3-R0.1-SNAPSHOT - remapped-mojang - provided - - - - 17 - 17 - true - - diff --git a/v1_19_R2/pom.xml b/v1_19_R2/pom.xml index eb77cc86..bfff0290 100644 --- a/v1_19_R2/pom.xml +++ b/v1_19_R2/pom.xml @@ -38,11 +38,6 @@ remapped-mojang provided - - com.github.Revxrsal.Lamp - paper-internal-dont-use - d72483065c - @@ -80,27 +75,6 @@ - - org.apache.maven.plugins - maven-shade-plugin - 3.3.0 - - - - revxrsal.commands - fr.skytasul.quests.commands.revxrsal - - - - - - package - - shade - - - - From 93003c01c19b6b91bcadf43925512e392d5e5145 Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Fri, 16 Dec 2022 19:25:44 +0100 Subject: [PATCH 08/41] :bug: Fix for WildStacker and 1.8 --- .../main/java/fr/skytasul/quests/utils/MinecraftNames.java | 7 +++---- .../quests/utils/compatibility/mobs/BQWildStacker.java | 3 ++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/fr/skytasul/quests/utils/MinecraftNames.java b/core/src/main/java/fr/skytasul/quests/utils/MinecraftNames.java index 36f7db51..a4ca2f36 100644 --- a/core/src/main/java/fr/skytasul/quests/utils/MinecraftNames.java +++ b/core/src/main/java/fr/skytasul/quests/utils/MinecraftNames.java @@ -5,16 +5,14 @@ import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; - 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 com.google.gson.GsonBuilder; - import fr.skytasul.quests.BeautyQuests; +import fr.skytasul.quests.utils.nms.NMS; public class MinecraftNames { @@ -84,7 +82,8 @@ public static String getEntityName(EntityType type) { public static String getMaterialName(ItemStack item) { XMaterial type = XMaterial.matchXMaterial(item); - if (type == XMaterial.POTION || type == XMaterial.LINGERING_POTION || type == XMaterial.SPLASH_POTION) { + if (NMS.getMCVersion() > 8 + && (type == XMaterial.POTION || type == XMaterial.LINGERING_POTION || type == XMaterial.SPLASH_POTION)) { PotionMeta meta = (PotionMeta) item.getItemMeta(); try { PotionData basePotion = meta.getBasePotionData(); diff --git a/core/src/main/java/fr/skytasul/quests/utils/compatibility/mobs/BQWildStacker.java b/core/src/main/java/fr/skytasul/quests/utils/compatibility/mobs/BQWildStacker.java index bc3a8150..b9c6a18d 100644 --- a/core/src/main/java/fr/skytasul/quests/utils/compatibility/mobs/BQWildStacker.java +++ b/core/src/main/java/fr/skytasul/quests/utils/compatibility/mobs/BQWildStacker.java @@ -1,6 +1,7 @@ package fr.skytasul.quests.utils.compatibility.mobs; import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; import org.bukkit.event.Listener; import com.bgsoftware.wildstacker.api.WildStackerAPI; import fr.skytasul.quests.api.QuestsAPI; @@ -11,7 +12,7 @@ private BQWildStacker() {} public static void initialize() { QuestsAPI.registerMobStacker(entity -> { - if (entity instanceof LivingEntity) + if (entity instanceof LivingEntity && !(entity instanceof Player)) return WildStackerAPI.getEntityAmount((LivingEntity) entity); return 1; }); From 9663e8a572a1036f7288f9a0c80f89db2f917c3a Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Fri, 23 Dec 2022 17:45:17 +0100 Subject: [PATCH 09/41] :bug: :recycle: Fix for Quest Stop reward --- README.md | 1 + .../quests/api/rewards/AbstractReward.java | 4 +-- .../rewards/InterruptingBranchException.java | 7 +++++ .../quests/rewards/CheckpointReward.java | 10 +++++-- .../quests/rewards/QuestStopReward.java | 4 ++- .../rewards/RequirementDependentReward.java | 5 ++-- .../fr/skytasul/quests/structure/Quest.java | 18 ++++++++++-- .../quests/structure/QuestBranch.java | 29 ++++++++++++++----- .../java/fr/skytasul/quests/utils/Utils.java | 14 ++++++++- 9 files changed, 70 insertions(+), 22 deletions(-) create mode 100644 core/src/main/java/fr/skytasul/quests/api/rewards/InterruptingBranchException.java diff --git a/README.md b/README.md index e5e5404e..b09a554b 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ ![bStats Servers](https://img.shields.io/bstats/servers/7460) ![bStats Players](https://img.shields.io/bstats/players/7460) [![Discord](https://ptb.discordapp.com/api/guilds/482632781395132416/widget.png)](https://discord.gg/H8fXrkD) +[![Gitmoji](https://img.shields.io/badge/gitmoji-%20😜%20😍-FFDD67.svg?style=flat-square)](https://gitmoji.dev) # BeautyQuests What is **BeautyQuests**? diff --git a/core/src/main/java/fr/skytasul/quests/api/rewards/AbstractReward.java b/core/src/main/java/fr/skytasul/quests/api/rewards/AbstractReward.java index c3c6dd34..f08fb49b 100644 --- a/core/src/main/java/fr/skytasul/quests/api/rewards/AbstractReward.java +++ b/core/src/main/java/fr/skytasul/quests/api/rewards/AbstractReward.java @@ -2,9 +2,7 @@ import java.util.List; import java.util.Map; - import org.bukkit.entity.Player; - import fr.skytasul.quests.api.QuestsAPI; import fr.skytasul.quests.api.objects.QuestObject; @@ -24,7 +22,7 @@ public RewardCreator getCreator() { * @param p Player to give the reward * @return title of all the subsequent reward (for instance : "4 gold") */ - public abstract List give(Player p); + public abstract List give(Player p) throws InterruptingBranchException; @Override public abstract AbstractReward clone(); diff --git a/core/src/main/java/fr/skytasul/quests/api/rewards/InterruptingBranchException.java b/core/src/main/java/fr/skytasul/quests/api/rewards/InterruptingBranchException.java new file mode 100644 index 00000000..d9a73326 --- /dev/null +++ b/core/src/main/java/fr/skytasul/quests/api/rewards/InterruptingBranchException.java @@ -0,0 +1,7 @@ +package fr.skytasul.quests.api.rewards; + +public class InterruptingBranchException extends Exception { + + private static final long serialVersionUID = -3679486008714615356L; + +} diff --git a/core/src/main/java/fr/skytasul/quests/rewards/CheckpointReward.java b/core/src/main/java/fr/skytasul/quests/rewards/CheckpointReward.java index 4e393d7f..e933a75b 100644 --- a/core/src/main/java/fr/skytasul/quests/rewards/CheckpointReward.java +++ b/core/src/main/java/fr/skytasul/quests/rewards/CheckpointReward.java @@ -2,15 +2,15 @@ import java.util.ArrayList; import java.util.List; - import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; - +import fr.skytasul.quests.BeautyQuests; import fr.skytasul.quests.api.QuestsAPI; import fr.skytasul.quests.api.objects.QuestObjectClickEvent; import fr.skytasul.quests.api.objects.QuestObjectLocation; import fr.skytasul.quests.api.options.QuestOption; import fr.skytasul.quests.api.rewards.AbstractReward; +import fr.skytasul.quests.api.rewards.InterruptingBranchException; import fr.skytasul.quests.api.serializable.SerializableObject; import fr.skytasul.quests.structure.Quest; import fr.skytasul.quests.utils.Lang; @@ -47,7 +47,11 @@ public List give(Player p) { } public void applies(Player p) { - Utils.giveRewards(p, actions); + try { + Utils.giveRewards(p, actions); + } catch (InterruptingBranchException e) { + BeautyQuests.logger.warning("Trying to interrupt branching in a checkpoint reward (useless). " + toString()); + } } @Override diff --git a/core/src/main/java/fr/skytasul/quests/rewards/QuestStopReward.java b/core/src/main/java/fr/skytasul/quests/rewards/QuestStopReward.java index 5ceca874..2436074d 100644 --- a/core/src/main/java/fr/skytasul/quests/rewards/QuestStopReward.java +++ b/core/src/main/java/fr/skytasul/quests/rewards/QuestStopReward.java @@ -4,6 +4,7 @@ import org.bukkit.entity.Player; import fr.skytasul.quests.api.objects.QuestObjectClickEvent; import fr.skytasul.quests.api.rewards.AbstractReward; +import fr.skytasul.quests.api.rewards.InterruptingBranchException; import fr.skytasul.quests.players.PlayersManager; import fr.skytasul.quests.utils.DebugUtils; @@ -15,11 +16,12 @@ public QuestStopReward() {} public void itemClick(QuestObjectClickEvent event) {} @Override - public List give(Player p) { + public List give(Player p) throws InterruptingBranchException { if (getAttachedQuest() == null) { DebugUtils.logMessage("No attached quest for " + debugName()); } else { getAttachedQuest().cancelPlayer(PlayersManager.getPlayerAccount(p)); + throw new InterruptingBranchException(); } return null; } diff --git a/core/src/main/java/fr/skytasul/quests/rewards/RequirementDependentReward.java b/core/src/main/java/fr/skytasul/quests/rewards/RequirementDependentReward.java index 6055e1e5..344e72df 100644 --- a/core/src/main/java/fr/skytasul/quests/rewards/RequirementDependentReward.java +++ b/core/src/main/java/fr/skytasul/quests/rewards/RequirementDependentReward.java @@ -4,7 +4,6 @@ import java.util.List; import java.util.Objects; import java.util.stream.Collectors; - import org.bukkit.Bukkit; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; @@ -12,13 +11,13 @@ import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; - import fr.skytasul.quests.api.QuestsAPI; import fr.skytasul.quests.api.objects.QuestObjectClickEvent; import fr.skytasul.quests.api.objects.QuestObjectLocation; import fr.skytasul.quests.api.options.QuestOption; import fr.skytasul.quests.api.requirements.AbstractRequirement; import fr.skytasul.quests.api.rewards.AbstractReward; +import fr.skytasul.quests.api.rewards.InterruptingBranchException; import fr.skytasul.quests.api.serializable.SerializableObject; import fr.skytasul.quests.gui.CustomInventory; import fr.skytasul.quests.gui.Inventories; @@ -57,7 +56,7 @@ public void detach() { } @Override - public List give(Player p) { + public List give(Player p) throws InterruptingBranchException { if (requirements.stream().allMatch(requirement -> requirement.test(p))) return Utils.giveRewards(p, rewards); return null; } diff --git a/core/src/main/java/fr/skytasul/quests/structure/Quest.java b/core/src/main/java/fr/skytasul/quests/structure/Quest.java index e45ea582..10493abf 100644 --- a/core/src/main/java/fr/skytasul/quests/structure/Quest.java +++ b/core/src/main/java/fr/skytasul/quests/structure/Quest.java @@ -7,6 +7,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; +import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.OptionalInt; @@ -31,6 +32,7 @@ import fr.skytasul.quests.api.options.description.QuestDescriptionProvider; import fr.skytasul.quests.api.requirements.AbstractRequirement; import fr.skytasul.quests.api.requirements.Actionnable; +import fr.skytasul.quests.api.rewards.InterruptingBranchException; import fr.skytasul.quests.gui.Inventories; import fr.skytasul.quests.gui.misc.ConfirmGUI; import fr.skytasul.quests.gui.quests.PlayerListGUI.Category; @@ -208,8 +210,13 @@ public boolean cancelPlayer(PlayerAccount acc) { QuestsAPI.propagateQuestsHandlers(handler -> handler.questReset(acc, this)); Bukkit.getPluginManager().callEvent(new PlayerQuestResetEvent(acc, this)); - if (acc.isCurrent()) - Utils.giveRewards(acc.getPlayer(), getOptionValueOrDef(OptionCancelRewards.class)); + if (acc.isCurrent()) { + try { + Utils.giveRewards(acc.getPlayer(), getOptionValueOrDef(OptionCancelRewards.class)); + } catch (InterruptingBranchException ex) { + BeautyQuests.logger.warning("Trying to interrupt branching in a cancel reward (useless). " + toString()); + } + } return true; } @@ -362,7 +369,12 @@ public void start(Player p, boolean silently) { } Runnable run = () -> { - List msg = Utils.giveRewards(p, getOptionValueOrDef(OptionStartRewards.class)); + List msg = Collections.emptyList(); + try { + msg = Utils.giveRewards(p, getOptionValueOrDef(OptionStartRewards.class)); + } catch (InterruptingBranchException ex) { + BeautyQuests.logger.warning("Trying to interrupt branching in a starting reward (useless). " + toString()); + } getOptionValueOrDef(OptionRequirements.class).stream().filter(Actionnable.class::isInstance).map(Actionnable.class::cast).forEach(x -> x.trigger(p)); if (!silently && !msg.isEmpty()) Utils.sendMessage(p, Lang.FINISHED_OBTAIN.format(Utils.itemsToFormattedString(msg.toArray(new String[0])))); if (asyncStart != null) asyncStart.remove(p); diff --git a/core/src/main/java/fr/skytasul/quests/structure/QuestBranch.java b/core/src/main/java/fr/skytasul/quests/structure/QuestBranch.java index 9cf48027..a099f2dd 100644 --- a/core/src/main/java/fr/skytasul/quests/structure/QuestBranch.java +++ b/core/src/main/java/fr/skytasul/quests/structure/QuestBranch.java @@ -16,6 +16,7 @@ import fr.skytasul.quests.QuestsConfiguration; import fr.skytasul.quests.api.events.PlayerSetStageEvent; import fr.skytasul.quests.api.requirements.Actionnable; +import fr.skytasul.quests.api.rewards.InterruptingBranchException; import fr.skytasul.quests.api.stages.AbstractStage; import fr.skytasul.quests.players.AdminMode; import fr.skytasul.quests.players.PlayerAccount; @@ -169,10 +170,11 @@ public void finishStage(Player p, AbstractStage stage){ if (end != stage) end.end(acc); } } + datas.setStage(-1); endStage(acc, stage, () -> { if (!manager.getQuest().hasStarted(acc)) return; if (regularStages.contains(stage)){ // not ending stage - continue the branch or finish the quest - int newId = datas.getStage() + 1; + int newId = stage.getID() + 1; if (newId == regularStages.size()){ if (endStages.isEmpty()){ remove(acc, false); @@ -196,7 +198,7 @@ public void finishStage(Player p, AbstractStage stage){ }); } - public void endStage(PlayerAccount acc, AbstractStage stage, Runnable runAfter) { + private void endStage(PlayerAccount acc, AbstractStage stage, Runnable runAfter) { if (acc.isCurrent()){ Player p = acc.getPlayer(); stage.end(acc); @@ -208,19 +210,30 @@ public void endStage(PlayerAccount acc, AbstractStage stage, Runnable runAfter) try { List given = Utils.giveRewards(p, stage.getRewards()); if (!given.isEmpty() && QuestsConfiguration.hasStageEndRewardsMessage()) Lang.FINISHED_OBTAIN.send(p, Utils.itemsToFormattedString(given.toArray(new String[0]))); + } catch (InterruptingBranchException ex) { + DebugUtils.logMessage( + "Interrupted branching in async stage end for " + p.getName() + " via " + ex.toString()); + return; }catch (Exception e) { Lang.ERROR_OCCURED.send(p, "giving async rewards"); BeautyQuests.logger.severe("An error occurred while giving stage async end rewards.", e); + } finally { + // by using the try-catch, we ensure that "asyncReward#remove" is called + // otherwise, the player would be completely stuck + asyncReward.remove(acc); } - // by using the try-catch, we ensure that "asyncReward#remove" is called - // otherwise, the player would be completely stuck - asyncReward.remove(acc); Utils.runSync(runAfter); }, "BQ async stage end " + p.getName()).start(); }else{ - List given = Utils.giveRewards(p, stage.getRewards()); - if (!given.isEmpty() && QuestsConfiguration.hasStageEndRewardsMessage()) Lang.FINISHED_OBTAIN.send(p, Utils.itemsToFormattedString(given.toArray(new String[0]))); - runAfter.run(); + try { + List given = Utils.giveRewards(p, stage.getRewards()); + if (!given.isEmpty() && QuestsConfiguration.hasStageEndRewardsMessage()) + Lang.FINISHED_OBTAIN.send(p, Utils.itemsToFormattedString(given.toArray(new String[0]))); + runAfter.run(); + } catch (InterruptingBranchException ex) { + DebugUtils.logMessage( + "Interrupted branching in async stage end for " + p.getName() + " via " + ex.toString()); + } } }else { stage.end(acc); diff --git a/core/src/main/java/fr/skytasul/quests/utils/Utils.java b/core/src/main/java/fr/skytasul/quests/utils/Utils.java index e82cbd08..88d3b939 100644 --- a/core/src/main/java/fr/skytasul/quests/utils/Utils.java +++ b/core/src/main/java/fr/skytasul/quests/utils/Utils.java @@ -45,6 +45,7 @@ import fr.skytasul.quests.BeautyQuests; import fr.skytasul.quests.QuestsConfiguration; import fr.skytasul.quests.api.rewards.AbstractReward; +import fr.skytasul.quests.api.rewards.InterruptingBranchException; import fr.skytasul.quests.gui.ItemUtils; import fr.skytasul.quests.structure.QuestBranch.Source; import fr.skytasul.quests.utils.compatibility.DependenciesManager; @@ -95,16 +96,27 @@ public static void spawnFirework(Location lc, FireworkMeta meta) { }); } - public static List giveRewards(Player p, List rewards) { + public static List giveRewards(Player p, List rewards) throws InterruptingBranchException { + InterruptingBranchException interrupting = null; + List msg = new ArrayList<>(); for (AbstractReward rew : rewards) { try { List messages = rew.give(p); if (messages != null) msg.addAll(messages); + } catch (InterruptingBranchException ex) { + if (interrupting != null) { + BeautyQuests.logger.warning("Interrupting the same branch via rewards twice!"); + } else { + interrupting = ex; + } } catch (Throwable e) { BeautyQuests.logger.severe("Error when giving reward " + rew.getName() + " to " + p.getName(), e); } } + + if (interrupting != null) + throw interrupting; return msg; } From c5646d8e8dc3dfb90e0e6dc91f5611f14c19e907 Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Sun, 25 Dec 2022 00:02:56 +0100 Subject: [PATCH 10/41] :loud_sound: Added more debug logs for player data loading --- .../java/fr/skytasul/quests/QuestsListener.java | 5 ++++- .../fr/skytasul/quests/players/PlayersManager.java | 11 ++++++++++- .../skytasul/quests/players/PlayersManagerYAML.java | 1 + .../java/fr/skytasul/quests/utils/DebugUtils.java | 13 ++++++------- 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/fr/skytasul/quests/QuestsListener.java b/core/src/main/java/fr/skytasul/quests/QuestsListener.java index 34b3b6c7..f542b51a 100644 --- a/core/src/main/java/fr/skytasul/quests/QuestsListener.java +++ b/core/src/main/java/fr/skytasul/quests/QuestsListener.java @@ -145,6 +145,7 @@ public void onOpen(InventoryOpenEvent e) { @EventHandler (priority = EventPriority.LOWEST) public void onJoin(PlayerJoinEvent e){ Player player = e.getPlayer(); + DebugUtils.logMessage(player.getName() + " joined the server"); // for timing purpose if (BeautyQuests.loaded && !QuestsConfiguration.hookAccounts()) { PlayersManager.loadPlayer(player); } @@ -152,8 +153,10 @@ public void onJoin(PlayerJoinEvent e){ @EventHandler public void onQuit(PlayerQuitEvent e) { + Player player = e.getPlayer(); + DebugUtils.logMessage(player.getName() + " left the server"); // for timing purpose if (!QuestsConfiguration.hookAccounts()) { - PlayersManager.unloadPlayer(e.getPlayer()); + PlayersManager.unloadPlayer(player); } } diff --git a/core/src/main/java/fr/skytasul/quests/players/PlayersManager.java b/core/src/main/java/fr/skytasul/quests/players/PlayersManager.java index c42af2ae..d3078b42 100644 --- a/core/src/main/java/fr/skytasul/quests/players/PlayersManager.java +++ b/core/src/main/java/fr/skytasul/quests/players/PlayersManager.java @@ -135,6 +135,12 @@ public static synchronized void loadPlayer(Player p) { while (i > 0) { i--; try { + if (!p.isOnline()) { + BeautyQuests.logger.warning("Player " + p.getName() + + " has quit the server while loading its datas. This may be a bug."); + return; + } + AccountFetchRequest request = new AccountFetchRequest(p, time, true, true); manager.load(request); @@ -194,7 +200,10 @@ public static synchronized void unloadPlayer(Player p) { public static PlayerAccount getPlayerAccount(Player p) { if (QuestsAPI.getNPCsManager().isNPC(p)) return null; - if (!p.isOnline()) BeautyQuests.logger.severe("Trying to fetch the account of an offline player (" + p.getName() + ")"); + if (!p.isOnline()) { + BeautyQuests.logger.severe("Trying to fetch the account of an offline player (" + p.getName() + ")"); + DebugUtils.logMessage("(via " + DebugUtils.stackTraces(2, 5) + ")"); + } return cachedAccounts.get(p); } diff --git a/core/src/main/java/fr/skytasul/quests/players/PlayersManagerYAML.java b/core/src/main/java/fr/skytasul/quests/players/PlayersManagerYAML.java index 61662dcd..f9eb6378 100644 --- a/core/src/main/java/fr/skytasul/quests/players/PlayersManagerYAML.java +++ b/core/src/main/java/fr/skytasul/quests/players/PlayersManagerYAML.java @@ -221,6 +221,7 @@ public void debugDuplicate() { } private synchronized void addAccount(PlayerAccount acc) { + Validate.notNull(acc); loadedAccounts.put(acc.index, acc); identifiersIndex.put(acc.index, acc.abstractAcc.getIdentifier()); if (acc.index >= lastAccountID) lastAccountID = acc.index; diff --git a/core/src/main/java/fr/skytasul/quests/utils/DebugUtils.java b/core/src/main/java/fr/skytasul/quests/utils/DebugUtils.java index 3ed9de98..00b74ebe 100644 --- a/core/src/main/java/fr/skytasul/quests/utils/DebugUtils.java +++ b/core/src/main/java/fr/skytasul/quests/utils/DebugUtils.java @@ -2,7 +2,7 @@ import java.util.HashMap; import java.util.Map; - +import java.util.StringJoiner; import fr.skytasul.quests.BeautyQuests; public class DebugUtils { @@ -16,14 +16,13 @@ public static void logMessage(String msg){ } public static String stackTraces(int from, int to){ - from++; - - String s = ""; + StringJoiner joiner = new StringJoiner(" -> "); StackTraceElement[] stack = Thread.currentThread().getStackTrace(); - for (;from <= to; from++) { - s = s + stack[from].getClassName().replace("fr.skytasul.quests", "f.s.q") + "." + stack[from].getMethodName() + " " + stack[from].getLineNumber() + "; "; + for (int i = from + 1; i <= to && i < stack.length; i++) { + joiner.add(stack[from].getClassName().replace("fr.skytasul.quests", "f.s.q") + "." + stack[from].getMethodName() + + " " + stack[from].getLineNumber()); } - return s; + return joiner.toString(); } public static void printError(String errorMsg, String typeID, int seconds) { From e4c6851f045209d354736e05032e0d77fc51d4e9 Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Sun, 25 Dec 2022 00:04:10 +0100 Subject: [PATCH 11/41] :bug: Fixed a bug with "fill buckets" stage < 1.17 --- .../quests/gui/creation/BucketTypeGUI.java | 7 ++++--- .../fr/skytasul/quests/stages/StageBucket.java | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/fr/skytasul/quests/gui/creation/BucketTypeGUI.java b/core/src/main/java/fr/skytasul/quests/gui/creation/BucketTypeGUI.java index dc64a0aa..a085e708 100644 --- a/core/src/main/java/fr/skytasul/quests/gui/creation/BucketTypeGUI.java +++ b/core/src/main/java/fr/skytasul/quests/gui/creation/BucketTypeGUI.java @@ -2,11 +2,9 @@ import java.util.Arrays; import java.util.function.Consumer; - import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; - import fr.skytasul.quests.gui.ItemUtils; import fr.skytasul.quests.gui.templates.ChooseGUI; import fr.skytasul.quests.stages.StageBucket.BucketType; @@ -19,19 +17,22 @@ public class BucketTypeGUI extends ChooseGUI{ private Consumer end; public BucketTypeGUI(Runnable cancel, Consumer end) { - super(Arrays.asList(BucketType.values())); + super(Arrays.asList(BucketType.getAvailable())); this.cancel = cancel; this.end = end; } + @Override public String name(){ return Lang.INVENTORY_BUCKETS.toString(); } + @Override public ItemStack getItemStack(BucketType object){ return ItemUtils.item(object.getMaterial(), object.getName()); } + @Override public void finish(BucketType object){ end.accept(object); } 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 105f54bc..0124c798 100644 --- a/core/src/main/java/fr/skytasul/quests/stages/StageBucket.java +++ b/core/src/main/java/fr/skytasul/quests/stages/StageBucket.java @@ -2,14 +2,12 @@ import java.util.Map; import java.util.function.Supplier; - import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.player.PlayerBucketFillEvent; import org.bukkit.inventory.ItemStack; - import fr.skytasul.quests.QuestsConfiguration; import fr.skytasul.quests.api.stages.AbstractStage; import fr.skytasul.quests.api.stages.StageCreation; @@ -25,6 +23,7 @@ import fr.skytasul.quests.utils.Lang; import fr.skytasul.quests.utils.Utils; import fr.skytasul.quests.utils.XMaterial; +import fr.skytasul.quests.utils.nms.NMS; public class StageBucket extends AbstractStage { @@ -97,6 +96,8 @@ public enum BucketType { SNOW(Lang.BucketSnow, XMaterial.POWDER_SNOW_BUCKET) ; + private static BucketType[] AVAILABLE; + private Lang name; private XMaterial type; @@ -119,6 +120,15 @@ public static BucketType fromMaterial(XMaterial type) { } throw new IllegalArgumentException(type.name() + " does not correspond to any bucket type"); } + + public static BucketType[] getAvailable() { + if (AVAILABLE == null) { + AVAILABLE = NMS.getMCVersion() >= 17 ? values() : new BucketType[] {WATER, LAVA, MILK}; + // inefficient? yes. But it's christmas and I don't want to work on this anymore, plus there will + // probably not be more bucket types in the future + } + return AVAILABLE; + } } public static class Creator extends StageCreation { From b5ffa14fe0cafed5e349c03953688f3e8561a9a5 Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Sun, 8 Jan 2023 14:03:47 +0100 Subject: [PATCH 12/41] :sparkles: Added "skip npc gui if only one quest" config option --- .../java/fr/skytasul/quests/QuestsConfiguration.java | 6 ++++++ .../main/java/fr/skytasul/quests/QuestsListener.java | 4 ++-- .../main/java/fr/skytasul/quests/gui/Inventories.java | 6 +++--- .../fr/skytasul/quests/gui/quests/ChooseQuestGUI.java | 11 ++++++++--- core/src/main/resources/config.yml | 2 ++ 5 files changed, 21 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/fr/skytasul/quests/QuestsConfiguration.java b/core/src/main/java/fr/skytasul/quests/QuestsConfiguration.java index 14195d54..88b140d3 100644 --- a/core/src/main/java/fr/skytasul/quests/QuestsConfiguration.java +++ b/core/src/main/java/fr/skytasul/quests/QuestsConfiguration.java @@ -61,6 +61,7 @@ public class QuestsConfiguration { private static boolean stageStart = true; private static boolean questConfirmGUI = false; private static Collection npcClicks = Arrays.asList(ClickType.RIGHT, ClickType.SHIFT_RIGHT); + private static boolean skipNpcGuiIfOnlyOneQuest = true; private static String dSetName = "Quests"; private static String dIcon = "bookshelf"; private static int dMinZoom = 0; @@ -179,6 +180,7 @@ void init() { }catch (IllegalArgumentException ex) { BeautyQuests.logger.warning("Unknown click type " + config.get("npcClick") + " for config entry \"npcClick\""); } + skipNpcGuiIfOnlyOneQuest = config.getBoolean("skip npc gui if only one quest"); enablePrefix = config.getBoolean("enablePrefix"); disableTextHologram = config.getBoolean("disableTextHologram"); showCustomHologramName = config.getBoolean("showCustomHologramName"); @@ -319,6 +321,10 @@ public static Collection getNPCClicks() { return npcClicks; } + public static boolean skipNpcGuiIfOnlyOneQuest() { + return skipNpcGuiIfOnlyOneQuest; + } + public static boolean handleGPS(){ return gps; } diff --git a/core/src/main/java/fr/skytasul/quests/QuestsListener.java b/core/src/main/java/fr/skytasul/quests/QuestsListener.java index f542b51a..25315d38 100644 --- a/core/src/main/java/fr/skytasul/quests/QuestsListener.java +++ b/core/src/main/java/fr/skytasul/quests/QuestsListener.java @@ -99,10 +99,10 @@ public void onNPCClick(BQNPCClickEvent e) { return; } } - ChooseQuestGUI gui = new ChooseQuestGUI(launcheable, (quest) -> { + ChooseQuestGUI gui = new ChooseQuestGUI(launcheable, quest -> { if (quest == null) return; quest.clickNPC(p); - }); + }, true); gui.setValidate(__ -> { new PlayerListGUI(acc).create(p); }, ItemUtils.item(XMaterial.BOOKSHELF, Lang.questMenu.toString(), QuestOption.formatDescription(Lang.questMenuLore.toString()))); diff --git a/core/src/main/java/fr/skytasul/quests/gui/Inventories.java b/core/src/main/java/fr/skytasul/quests/gui/Inventories.java index 5ccfe3e6..af6665dd 100644 --- a/core/src/main/java/fr/skytasul/quests/gui/Inventories.java +++ b/core/src/main/java/fr/skytasul/quests/gui/Inventories.java @@ -3,7 +3,6 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Map; - import org.bukkit.Material; import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; @@ -16,9 +15,9 @@ import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.scheduler.BukkitRunnable; - import fr.skytasul.quests.BeautyQuests; import fr.skytasul.quests.gui.misc.ConfirmGUI; +import fr.skytasul.quests.utils.DebugUtils; import fr.skytasul.quests.utils.Lang; import fr.skytasul.quests.utils.types.Pair; @@ -43,11 +42,12 @@ public static Inventory createGetInv(Player p, CustomInventory inv){ public static T create(Player p, T inv) { closeWithoutExit(p); try { + DebugUtils.logMessage(p.getName() + " has opened inventory " + inv.getClass().getName() + "."); Inventory tinv = inv.open(p); if (tinv == null) return inv; put(p, inv, tinv); return inv; - }catch (Throwable ex) { + } catch (Exception ex) { BeautyQuests.logger.severe("Cannot open inventory " + inv.getClass().getSimpleName() + " to player " + p.getName(), ex); closeAndExit(p); return null; diff --git a/core/src/main/java/fr/skytasul/quests/gui/quests/ChooseQuestGUI.java b/core/src/main/java/fr/skytasul/quests/gui/quests/ChooseQuestGUI.java index 4de2c05f..273754b0 100644 --- a/core/src/main/java/fr/skytasul/quests/gui/quests/ChooseQuestGUI.java +++ b/core/src/main/java/fr/skytasul/quests/gui/quests/ChooseQuestGUI.java @@ -3,7 +3,6 @@ import java.util.Collection; import java.util.Comparator; import java.util.function.Consumer; - import org.apache.commons.lang.Validate; import org.bukkit.ChatColor; import org.bukkit.DyeColor; @@ -11,7 +10,7 @@ import org.bukkit.event.inventory.ClickType; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; - +import fr.skytasul.quests.QuestsConfiguration; import fr.skytasul.quests.gui.CustomInventory; import fr.skytasul.quests.gui.Inventories; import fr.skytasul.quests.gui.ItemUtils; @@ -22,6 +21,7 @@ public class ChooseQuestGUI extends PagedGUI { private Consumer run; + private boolean canSkip; public CustomInventory openLastInv(Player p) { p.openInventory(inv); @@ -29,11 +29,16 @@ public CustomInventory openLastInv(Player p) { } public ChooseQuestGUI(Collection quests, Consumer run) { + this(quests, run, false); + } + + public ChooseQuestGUI(Collection quests, Consumer run, boolean canSkip) { super(Lang.INVENTORY_CHOOSE.toString(), DyeColor.MAGENTA, quests); Validate.notNull(run, "Runnable cannot be null"); super.objects.sort(Comparator.naturalOrder()); this.run = run; + this.canSkip = canSkip; } @Override @@ -41,7 +46,7 @@ public Inventory open(Player p){ if (objects.size() == 0) { run.accept(null); return null; - }else if (objects.size() == 1) { + } else if (objects.size() == 1 && canSkip && QuestsConfiguration.skipNpcGuiIfOnlyOneQuest()) { run.accept(objects.get(0)); return null; } diff --git a/core/src/main/resources/config.yml b/core/src/main/resources/config.yml index aab4579a..9f4d7765 100644 --- a/core/src/main/resources/config.yml +++ b/core/src/main/resources/config.yml @@ -56,6 +56,8 @@ progressBarTimeoutSeconds: 15 # Which clicks are acceptable for a player to do on the NPC in order to start a quest, follow a dialog... # (can be: RIGHT, LEFT, SHIFT_RIGHT, SHIFT_LEFT) npcClick: [RIGHT, SHIFT_RIGHT] +# If enabled, the "choose a quest from this NPC" GUI will not open if there is only 1 quest attached to the NPC +skip npc gui if only one quest: true # Default item shown for a quest in the menus item: BOOK # Page item material From 4ed5f95bebf17fede15742dd9331f97f4adf0b64 Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Thu, 12 Jan 2023 18:53:13 +0100 Subject: [PATCH 13/41] :sparkles: Added "hide unknown quest placeholders" scoreboard config parameter --- .../quests/scoreboards/Scoreboard.java | 28 +++++++++++++++---- .../quests/scoreboards/ScoreboardManager.java | 17 +++++++---- core/src/main/resources/scoreboard.yml | 4 +++ 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/fr/skytasul/quests/scoreboards/Scoreboard.java b/core/src/main/java/fr/skytasul/quests/scoreboards/Scoreboard.java index fd216c72..8f5a5362 100644 --- a/core/src/main/java/fr/skytasul/quests/scoreboards/Scoreboard.java +++ b/core/src/main/java/fr/skytasul/quests/scoreboards/Scoreboard.java @@ -1,6 +1,7 @@ package fr.skytasul.quests.scoreboards; import java.util.ArrayList; +import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Optional; @@ -298,12 +299,21 @@ private boolean tryRefresh(boolean time) { String text = getValue(); if (hasQuestPlaceholders) text = formatQuestPlaceholders(text); - text = Utils.finalFormat(p, text, true); - if (text.equals(lastValue)) return false; - - lines = ChatUtils.wordWrap(text, param.getMaxLength() == 0 ? 30 : param.getMaxLength(), maxLength); - - lastValue = text; + + if (text == null) { + // in this case, the line must not be displayed + + lines = Collections.emptyList(); + lastValue = null; + } else { + text = Utils.finalFormat(p, text, true); + if (text.equals(lastValue)) + return false; + + lines = ChatUtils.wordWrap(text, param.getMaxLength() == 0 ? 30 : param.getMaxLength(), maxLength); + + lastValue = text; + } return true; } if (time) timeLeft--; @@ -353,6 +363,12 @@ private String formatQuestPlaceholders(String text) { shown, acc, PlayerListGUI.Category.IN_PROGRESS, Source.SCOREBOARD); replacement = String.join("\n", optionalDescription.get().provideDescription(lazyContext)); } else { + if (manager.hideUnknownQuestPlaceholders()) { + // early return as there is no point continuing processing placeholders + // as this line won't be displayed + return null; + } + replacement = descriptionId; } } diff --git a/core/src/main/java/fr/skytasul/quests/scoreboards/ScoreboardManager.java b/core/src/main/java/fr/skytasul/quests/scoreboards/ScoreboardManager.java index 39daefa7..e28cb0c0 100644 --- a/core/src/main/java/fr/skytasul/quests/scoreboards/ScoreboardManager.java +++ b/core/src/main/java/fr/skytasul/quests/scoreboards/ScoreboardManager.java @@ -7,8 +7,8 @@ import java.util.Map; import java.util.UUID; import java.util.function.Consumer; - import org.bukkit.Bukkit; +import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -16,7 +16,6 @@ import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerChangedWorldEvent; - import fr.mrmicky.fastboard.FastBoard; import fr.skytasul.quests.BeautyQuests; import fr.skytasul.quests.QuestsConfiguration; @@ -39,6 +38,7 @@ public class ScoreboardManager implements Listener, QuestsHandler { private int changeTime; private boolean hide; private boolean refreshLines; + private boolean hideUnknownQuestPlaceholders; private List worldsFilter; private boolean isWorldAllowList; @@ -63,6 +63,10 @@ public boolean refreshLines(){ return refreshLines; } + public boolean hideUnknownQuestPlaceholders() { + return hideUnknownQuestPlaceholders; + } + public List getWorldsFilter() { return worldsFilter; } @@ -109,10 +113,13 @@ public void load() { }catch (NullPointerException ex) {} // as we pass a null player to initialize, it will throw NPE YamlConfiguration config = YamlConfiguration.loadConfiguration(file); - changeTime = config.getInt("quests.changeTime", 11); - hide = config.getBoolean("quests.hideIfEmpty", true); - refreshLines = config.getBoolean("quests.refreshLines", true); + ConfigurationSection questsSection = config.getConfigurationSection("quests"); + changeTime = questsSection.getInt("changeTime", 11); + hide = questsSection.getBoolean("hideIfEmpty", true); + refreshLines = questsSection.getBoolean("refreshLines", true); + hideUnknownQuestPlaceholders = questsSection.getBoolean("hide unknown quest placeholders"); + worldsFilter = config.getStringList("worlds.filterList"); isWorldAllowList = config.getBoolean("worlds.isAllowList"); diff --git a/core/src/main/resources/scoreboard.yml b/core/src/main/resources/scoreboard.yml index 9f0249f9..d4fe32b9 100644 --- a/core/src/main/resources/scoreboard.yml +++ b/core/src/main/resources/scoreboard.yml @@ -8,6 +8,10 @@ quests: # If enabled, scoreboard lines containing a {quest_xxx} placeholder # will be automatically refreshed whenever the quest tracker is updated refreshLines: true + # If enabled, lines containing quest placeholders which relies on context + # (such as {quest_time_left} in the expansion) that are not available for the + # currently displayed quest will not be shown. + hide unknown quest placeholders: false worlds: # List of worlds to filter From 5ce7231bcb71e1be9eccd2c55ddd84a875aa1a5a Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Sun, 15 Jan 2023 20:26:59 +0100 Subject: [PATCH 14/41] :sparkles: Made block type name customizable for Mine/Place blocks stages --- .../quests/gui/blocks/SelectBlockGUI.java | 39 ++++++++++----- .../skytasul/quests/stages/StageInteract.java | 2 +- .../java/fr/skytasul/quests/utils/Lang.java | 1 + .../quests/utils/compatibility/Post1_13.java | 23 +++++---- .../skytasul/quests/utils/types/BQBlock.java | 49 +++++++++++++++---- core/src/main/resources/locales/en_US.yml | 1 + 6 files changed, 79 insertions(+), 36 deletions(-) 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 07b35ff3..fba5aba0 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,9 +1,7 @@ package fr.skytasul.quests.gui.blocks; import static fr.skytasul.quests.gui.ItemUtils.item; - import java.util.function.BiConsumer; - import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.NamespacedKey; @@ -12,7 +10,6 @@ import org.bukkit.event.inventory.ClickType; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; - import fr.skytasul.quests.api.options.QuestOption; import fr.skytasul.quests.editors.TextEditor; import fr.skytasul.quests.editors.checkers.MaterialParser; @@ -28,9 +25,12 @@ public class SelectBlockGUI implements CustomInventory{ - private static final int TYPE_SLOT = 3; - private static final int DATA_SLOT = 4; - private static final int TAG_SLOT = 5; + private static final int AMOUNT_SLOT = 1; + private static final int NAME_SLOT = 2; + private static final int TYPE_SLOT = 4; + private static final int DATA_SLOT = 5; + private static final int TAG_SLOT = 6; + private static final int FINISH_SLOT = 8; private ItemStack done = item(XMaterial.DIAMOND, Lang.done.toString()); @@ -40,6 +40,7 @@ public class SelectBlockGUI implements CustomInventory{ public Inventory inv; private XMaterial type = XMaterial.STONE; + private String customName = null; private String blockData = null; private String tag = null; private int amount = 1; @@ -62,10 +63,13 @@ public CustomInventory openLastInv(Player p) { public Inventory open(Player p){ inv = Bukkit.createInventory(null, 9, name()); - if (allowAmount) inv.setItem(1, item(XMaterial.REDSTONE, Lang.Amount.format(amount))); + if (allowAmount) + inv.setItem(AMOUNT_SLOT, item(XMaterial.REDSTONE, Lang.Amount.format(amount))); + inv.setItem(NAME_SLOT, + item(XMaterial.NAME_TAG, Lang.blockName.toString(), QuestOption.formatNullableValue(null, true))); if (NMS.getMCVersion() >= 13) inv.setItem(DATA_SLOT, item(XMaterial.COMMAND_BLOCK, Lang.blockData.toString(), Lang.NotSet.toString())); if (NMS.getMCVersion() >= 13) inv.setItem(TAG_SLOT, item(XMaterial.FILLED_MAP, Lang.blockTag.toString(), QuestOption.formatDescription(Lang.blockTagLore.toString()), "", Lang.NotSet.toString())); - inv.setItem(8, done.clone()); + inv.setItem(FINISH_SLOT, done.clone()); updateTypeItem(); return inv = p.openInventory(inv).getTopInventory(); @@ -102,7 +106,7 @@ public boolean onClick(Player p, Inventory inv, ItemStack current, int slot, Cli default: break; - case 1: + case AMOUNT_SLOT: Lang.BLOCKS_AMOUNT.send(p); new TextEditor<>(p, () -> openLastInv(p), obj -> { amount = obj; @@ -111,6 +115,15 @@ public boolean onClick(Player p, Inventory inv, ItemStack current, int slot, Cli }, NumberParser.INTEGER_PARSER_STRICT_POSITIVE).enter(); break; + case NAME_SLOT: + Lang.BLOCK_NAME.send(p); + new TextEditor(p, () -> openLastInv(p), obj -> { + customName = obj; + ItemUtils.lore(current, QuestOption.formatNullableValue(customName, customName == null)); + openLastInv(p); + }).passNullIntoEndConsumer().enter(); + break; + case TYPE_SLOT: Lang.BLOCK_NAME.send(p); new TextEditor<>(p, () -> openLastInv(p), type -> { @@ -170,15 +183,15 @@ public boolean onClick(Player p, Inventory inv, ItemStack current, int slot, Cli }).useStrippedMessage().enter(); break; - case 8: + case FINISH_SLOT: Inventories.closeAndExit(p); BQBlock block; if (blockData != null) { - block = new Post1_13.BQBlockData(Bukkit.createBlockData(type.parseMaterial(), blockData)); + block = new Post1_13.BQBlockData(customName, Bukkit.createBlockData(type.parseMaterial(), blockData)); }else if (tag != null) { - block = new Post1_13.BQBlockTag(tag); + block = new Post1_13.BQBlockTag(customName, tag); }else { - block = new BQBlock.BQBlockMaterial(type); + block = new BQBlock.BQBlockMaterial(customName, type); } run.accept(block, amount); break; diff --git a/core/src/main/java/fr/skytasul/quests/stages/StageInteract.java b/core/src/main/java/fr/skytasul/quests/stages/StageInteract.java index 51ff5015..d0601ea4 100644 --- a/core/src/main/java/fr/skytasul/quests/stages/StageInteract.java +++ b/core/src/main/java/fr/skytasul/quests/stages/StageInteract.java @@ -137,7 +137,7 @@ public static StageInteract deserialize(ConfigurationSection section, QuestBranc }else { BQBlock block; if (section.contains("material")) { - block = new BQBlock.BQBlockMaterial(XMaterial.valueOf(section.getString("material"))); + block = new BQBlock.BQBlockMaterial(null, XMaterial.valueOf(section.getString("material"))); }else { block = BQBlock.fromString(section.getString("block")); } diff --git a/core/src/main/java/fr/skytasul/quests/utils/Lang.java b/core/src/main/java/fr/skytasul/quests/utils/Lang.java index 446bbddd..002cd9d7 100644 --- a/core/src/main/java/fr/skytasul/quests/utils/Lang.java +++ b/core/src/main/java/fr/skytasul/quests/utils/Lang.java @@ -591,6 +591,7 @@ public enum Lang implements Locale { INVENTORY_BLOCK("inv.block.name"), materialName("inv.block.material"), materialNotItemLore("inv.block.materialNotItemLore"), // 0: block id + blockName("inv.block.blockName"), blockData("inv.block.blockData"), blockTag("inv.block.blockTag"), blockTagLore("inv.block.blockTagLore"), diff --git a/core/src/main/java/fr/skytasul/quests/utils/compatibility/Post1_13.java b/core/src/main/java/fr/skytasul/quests/utils/compatibility/Post1_13.java index 5b9d71f8..2d6a4718 100644 --- a/core/src/main/java/fr/skytasul/quests/utils/compatibility/Post1_13.java +++ b/core/src/main/java/fr/skytasul/quests/utils/compatibility/Post1_13.java @@ -1,7 +1,6 @@ package fr.skytasul.quests.utils.compatibility; import java.util.Set; - import org.bukkit.Bukkit; import org.bukkit.Color; import org.bukkit.Material; @@ -10,7 +9,6 @@ import org.bukkit.Tag; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; - import fr.skytasul.quests.utils.XMaterial; import fr.skytasul.quests.utils.types.BQBlock; @@ -40,11 +38,12 @@ public static class BQBlockData extends BQBlock { private final BlockData data; - public BQBlockData(String stringData) { - this.data = Bukkit.createBlockData(stringData); + public BQBlockData(String customName, String stringData) { + this(customName, Bukkit.createBlockData(stringData)); } - public BQBlockData(BlockData data) { + public BQBlockData(String customName, BlockData data) { + super(customName); this.data = data; } @@ -59,7 +58,7 @@ public XMaterial retrieveMaterial() { } @Override - public String getAsString() { + public String getDataString() { return BQBlock.BLOCKDATA_HEADER + data.getAsString(true); } @@ -70,12 +69,12 @@ public static class BQBlockTag extends BQBlock { private final Tag tag; private final String tagKey; - public BQBlockTag(String stringData) { - this.tagKey = stringData; - this.tag = Bukkit.getTag(Tag.REGISTRY_BLOCKS, NamespacedKey.fromString(stringData), Material.class); + public BQBlockTag(String customName, String stringData) { + this(customName, Bukkit.getTag(Tag.REGISTRY_BLOCKS, NamespacedKey.fromString(stringData), Material.class)); } - public BQBlockTag(Tag tag) { + public BQBlockTag(String customName, Tag tag) { + super(customName); this.tagKey = tag.getKey().toString(); this.tag = tag; } @@ -95,12 +94,12 @@ public XMaterial retrieveMaterial() { } @Override - public String getName() { + public String getDefaultName() { return tag == null ? tagKey : tag.getKey().getKey(); } @Override - public String getAsString() { + public String getDataString() { return BQBlock.TAG_HEADER + tagKey; } diff --git a/core/src/main/java/fr/skytasul/quests/utils/types/BQBlock.java b/core/src/main/java/fr/skytasul/quests/utils/types/BQBlock.java index 9730e0e6..3f0a0bb8 100644 --- a/core/src/main/java/fr/skytasul/quests/utils/types/BQBlock.java +++ b/core/src/main/java/fr/skytasul/quests/utils/types/BQBlock.java @@ -5,9 +5,7 @@ import java.util.NoSuchElementException; import java.util.Spliterator; import java.util.Spliterators; - import org.bukkit.block.Block; - import fr.skytasul.quests.api.stages.types.Locatable; import fr.skytasul.quests.api.stages.types.Locatable.Located; import fr.skytasul.quests.api.stages.types.Locatable.Located.LocatedBlock; @@ -21,10 +19,18 @@ public abstract class BQBlock { public static final String BLOCKDATA_HEADER = "blockdata:"; public static final String TAG_HEADER = "tag:"; + public static final String CUSTOM_NAME_FOOTER = "|customname:"; + private final String customName; + private XMaterial cachedMaterial; + private String cachedName; - public abstract String getAsString(); + protected BQBlock(String customName) { + this.customName = customName; + } + + protected abstract String getDataString(); public abstract boolean applies(Block block); @@ -35,19 +41,41 @@ public final XMaterial getMaterial() { return cachedMaterial; } - public String getName() { + public String getDefaultName() { return MinecraftNames.getMaterialName(getMaterial()); } + + public final String getName() { + if (cachedName == null) + cachedName = customName == null ? getDefaultName() : customName; + + return cachedName; + } + + public final String getAsString() { + return getDataString() + getFooter(); + } + private String getFooter() { + return customName == null ? "" : CUSTOM_NAME_FOOTER + customName; + } + @Override public String toString() { return "BQBlock{" + getAsString() + "}"; } - + public static BQBlock fromString(String string) { - if (string.startsWith(BLOCKDATA_HEADER)) return new Post1_13.BQBlockData(string.substring(BLOCKDATA_HEADER.length())); - if (string.startsWith(TAG_HEADER)) return new Post1_13.BQBlockTag(string.substring(TAG_HEADER.length())); - return new BQBlockMaterial(XMaterial.valueOf(string)); + int nameIndex = string.lastIndexOf(CUSTOM_NAME_FOOTER); + String customName = nameIndex == -1 ? null : string.substring(nameIndex + CUSTOM_NAME_FOOTER.length()); + + int dataEnd = nameIndex == -1 ? string.length() : nameIndex; + + if (string.startsWith(BLOCKDATA_HEADER)) + return new Post1_13.BQBlockData(customName, string.substring(BLOCKDATA_HEADER.length(), dataEnd)); + if (string.startsWith(TAG_HEADER)) + return new Post1_13.BQBlockTag(customName, string.substring(TAG_HEADER.length(), dataEnd)); + return new BQBlockMaterial(customName, XMaterial.valueOf(string.substring(0, dataEnd))); } public static Spliterator getNearbyBlocks(Locatable.MultipleLocatable.NearbyFetcher fetcher, Collection types) { @@ -115,7 +143,8 @@ public static class BQBlockMaterial extends BQBlock { private final XMaterial material; - public BQBlockMaterial(XMaterial material) { + public BQBlockMaterial(String customName, XMaterial material) { + super(customName); this.material = material; } @@ -130,7 +159,7 @@ public boolean applies(Block block) { } @Override - public String getAsString() { + public String getDataString() { return material.name(); } diff --git a/core/src/main/resources/locales/en_US.yml b/core/src/main/resources/locales/en_US.yml index 7f86d124..28516b74 100644 --- a/core/src/main/resources/locales/en_US.yml +++ b/core/src/main/resources/locales/en_US.yml @@ -631,6 +631,7 @@ inv: name: Choose block material: '§eMaterial: {0}' materialNotItemLore: 'The block chosen cannot be displayed as an item. It is still correctly stored as {0}.' + blockName: '§bCustom block name' blockData: '§dBlockdata (advanced)' blockTag: '§dTag (advanced)' blockTagLore: 'Choose a tag which describes a list of possible blocks. From 93a8578f90768f1fcd9d684b328228c8349f8997 Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Sun, 15 Jan 2023 20:27:34 +0100 Subject: [PATCH 15/41] :bug: Fixed issues when having multiple countable stage objects of the same type --- .../stages/types/AbstractCountableStage.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/fr/skytasul/quests/api/stages/types/AbstractCountableStage.java b/core/src/main/java/fr/skytasul/quests/api/stages/types/AbstractCountableStage.java index 3a6b6395..d24fc310 100644 --- a/core/src/main/java/fr/skytasul/quests/api/stages/types/AbstractCountableStage.java +++ b/core/src/main/java/fr/skytasul/quests/api/stages/types/AbstractCountableStage.java @@ -5,14 +5,12 @@ import java.util.Map; import java.util.Map.Entry; import java.util.function.Supplier; - import org.bukkit.Bukkit; import org.bukkit.boss.BarColor; import org.bukkit.boss.BarStyle; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitTask; - import fr.skytasul.quests.BeautyQuests; import fr.skytasul.quests.QuestsConfiguration; import fr.skytasul.quests.api.QuestsAPI; @@ -99,14 +97,14 @@ protected void initPlayerDatas(PlayerAccount acc, Map datas) { } /** - * When called, this will test the player datas for the passed object. - * If found, the remaining amount will be lowered. - * If no remaining items are found, the stage will complete. + * When called, this will test the player datas for the passed object. If found, the remaining + * amount will be lowered. If no remaining items are found, the stage will complete. + * * @param acc player account * @param p player * @param object object of the event * @param amount amount completed - * @return false if there is no need to call this method again in the same game tick. + * @return true if there is no need to call this method again in the same game tick. */ public boolean event(PlayerAccount acc, Player p, Object object, int amount) { if (amount < 0) throw new IllegalArgumentException("Event amount must be positive (" + amount + ")"); @@ -120,8 +118,10 @@ public boolean event(PlayerAccount acc, Player p, Object object, int amount) { int playerAmount = playerAmounts.get(id); if (playerAmount <= amount) { playerAmounts.remove(id); - }else playerAmounts.put(id, playerAmount -= amount); - } + } else + playerAmounts.put(id, playerAmount - amount); + } else + continue; if (playerAmounts.isEmpty()) { finishStage(p); @@ -138,7 +138,7 @@ public boolean event(PlayerAccount acc, Player p, Object object, int amount) { } } } - return true; + return false; } @Override From d5b0a42373cb5b9adde1954649d50d546011ae58 Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Sun, 15 Jan 2023 20:32:00 +0100 Subject: [PATCH 16/41] :globe_with_meridians: Updated DE, ES, FR, HU, IT and RU translations --- core/src/main/resources/locales/de_DE.yml | 15 ++++----- core/src/main/resources/locales/es_ES.yml | 37 ++++++++++++++++++++--- core/src/main/resources/locales/fr_FR.yml | 1 + core/src/main/resources/locales/hu_HU.yml | 15 +++++++++ core/src/main/resources/locales/it_IT.yml | 11 +++++-- core/src/main/resources/locales/ru_RU.yml | 8 ++--- 6 files changed, 68 insertions(+), 19 deletions(-) diff --git a/core/src/main/resources/locales/de_DE.yml b/core/src/main/resources/locales/de_DE.yml index 7b9cd019..d78f5ec0 100644 --- a/core/src/main/resources/locales/de_DE.yml +++ b/core/src/main/resources/locales/de_DE.yml @@ -27,6 +27,7 @@ msg: questItem: drop: '§cDu kannst einen Questgegenstand nicht fallen lassen!' craft: '§cDu kannst keinen Questgegenstand zum Craften verwenden!' + eat: Du kannst Quest Items nicht Essen! stageMobs: noMobs: '§cDer Schritt beinhaltet nicht das Töten von Mobs.' listMobs: '§aDu musst {0} töten.' @@ -82,11 +83,12 @@ msg: playerNeverConnected: '§cKann keine Informationen über den Spieler {0} finden.' playerNotOnline: '§cDer Spieler {0} ist offline.' versionRequired: 'Benötigte Version: §l{0}' + dialogs: + skipped: 'Dialog übersprungen.' command: downloadTranslations: syntax: "§cDu musst eine Sprache auswählen zum downloaden.\nBeispiel: \"/quests downloadTranslations en_US\"." notFound: '§cSprache {0} nicht gefunden für die Version {1}.' - exists: '§cDie Datei {0} existiert bereits. Hänge "true" an deinen Befehl an, um sie zu überschreiben. (/quests downloadTranslations true)' downloaded: '§aSprache {0} wurde heruntergeladen! §7Du musst nun die Datei "/plugins/BeautyQuests/config.yml" bearbeiten, um den Wert von §ominecraftTranslationsFile§7 mit {0} zu ändern. Der Server muss anschliessend neu gestartet werden.' checkpoint: noCheckpoint: '§cKein Checkpoint für die Quest {0} gefunden.' @@ -116,7 +118,6 @@ msg: remover: '§6{0} Questinformation(en) von {1} wurde(n) gelöscht.' resetQuest: '§6Quest Daten wurden für {0} Spieler entfernt.' startQuest: '§6Du hast den Start der Quest {0} erzwungen. (Spieler‐UUID: {1})' - startQuestNoRequirements: '§cDer Spieler erfüllt nicht die Anforderungen für die Quest {0}... Füge "true" am Ende deines Befehls an, um die Überprüfung der Anforderungen zu umgehen.' cancelQuest: '§6Du hast die Quest {0} abgebrochen.' cancelQuestUnavailable: '§cDie Quest {0} kann nicht abgebrochen werden.' backupCreated: '§6Du hast erfolgreich Sicherungen aller Quests und Spielerinformationen erstellt.' @@ -135,6 +136,8 @@ msg: resetAll: '§6Du hast das Scoreboard des Spielers {0} erfolgreich zurückgesetzt.' hidden: '§6Das Scoreboard des Spielers {0} wurde versteckt.' shown: '§6Das Scoreboard des Spielers {0} wurde angezeigt.' + own: + shown: Dein Scoreboard wird wieder angezeigt. help: header: '§6§lBeautyQuests — Hilfe' create: '§6/{0} create: §eErstelle eine Quest.' @@ -239,7 +242,6 @@ msg: list: '§aEine Liste aller Mythic Mobs:' isntMythicMob: '§cDieser Mythic Mob existiert nicht.' disabled: '§cMythicMob ist deaktiviert.' - epicBossDoesntExist: '§cDieser Epic Boss exisitert nicht.' textList: syntax: '§cKorrekte Syntax: ' added: '§aText "§7{0}§a" hinzugefügt.' @@ -251,7 +253,6 @@ msg: list: '§6list: §eSieh dir alle hinzugefügten Texte an.' close: '§6close: §eBestätige die hinzugefügten Texte.' noSuchElement: '§cDieses Element existiert nicht. Erlaubte Elemente sind: §e{0}' - comparisonType: '§aWähle eine folgender Vergleichsarten aus: {0}. Der Standard ist: §e§lgreater or equals§r§a. Benutze §onull§r§a um dies zu nutzen.' scoreboardObjectiveNotFound: '§cUnbekanntes Scoreboard Ziel.' pool: hologramText: 'Schreibe den benutzerdefinierten Hologramm-Text für diese Gruppe (oder "null", wenn du den Standardtext möchtest).' @@ -264,6 +265,9 @@ msg: fadeIn: 'Schreibe die "Einblende"-Dauer, in Ticks (20 ticks = 1 Sekunde).' stay: 'Schreibe die "Bleibe"-Dauer, in Ticks (20 Ticks = 1 Sekunde).' fadeOut: 'Schreibe die "Ausblende"-Dauer, in Ticks (20 ticks = 1 Sekunde).' + firework: + invalidHand: 'Du musst ein Feuerwerk in deiner Main Hand halten.' + edited: 'Feuerwerk Quest bearbeitet!' writeCommandDelay: '§aGebe die gewünschte Befehl Verzögerung in Ticks an.' advancement: finished: Abgeschlossen @@ -362,8 +366,6 @@ inv: startableFromGUILore: Ermöglicht dem Spieler, die Quest aus dem Quest-Menü zu starten. scoreboardItem: Scoreboard aktivieren scoreboardItemLore: Wenn deaktiviert, wird die Quest nicht über das Scoreboard verfolgt. - hideItem: Menü und Dynmap verstecken - hideItemLore: Wenn aktiviert, wird die Quest weder auf der Dynmap, noch im Quest-Menü angezeigt. hideNoRequirementsItem: Verstecken, wenn die Anforderungen nicht erfüllt sind hideNoRequirementsItemLore: Wenn aktiviert, wird die Quest nicht im Questmenü angezeigt, wenn die Anforderungen nicht erfüllt sind. bypassLimit: Questlimit nicht zählen @@ -620,7 +622,6 @@ scoreboard: craft: '§eStelle §6{0} §eher' bucket: '§eBefülle §6{0}' location: '§eGehe zu: §6{0}§e, §6{1}§e, §6{2}§e in §6{3}' - playTime: '§eSpiele §6{0} Spielsticks' breed: '§eZüchte §6{0}' tame: '§eZähme §6{0}' indication: diff --git a/core/src/main/resources/locales/es_ES.yml b/core/src/main/resources/locales/es_ES.yml index 01ee910b..bc6c9501 100644 --- a/core/src/main/resources/locales/es_ES.yml +++ b/core/src/main/resources/locales/es_ES.yml @@ -13,6 +13,7 @@ msg: invalidID: '§cLa misión con la id {0} no existe.' invalidPoolID: '§cEl grupo {0} 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 {0} Misiones al mismo tiempo...' nopStep: '§cEsta misión no tiene ningún paso.' @@ -94,7 +95,7 @@ msg: downloadTranslations: syntax: '§cDebes especificar un idioma para descargar. Ejemplo: "/quests downloadTranslations en_US".' notFound: '§cIdioma {0} no encontrado para la versión {1}.' - exists: '§cEl archivo {0} ya existe. Añade "true" a tu comando para sobrescribirlo. (/quests downloadTranslations true)' + exists: '§cEl archivo {0} ya existe. Añade "-overwrite" a tu comando para sobrescribirlo. (/quests downloadTranslations -overwrite)' downloaded: '§a¡El idioma {0} ha sido descargado! §7Ahora debes editar el archivo "/plugins/BeautyQuests/config.yml" para cambiar el valor de §ominecraftTranslationsFile§7 con {0}, y luego reiniciar el servidor.' checkpoint: noCheckpoint: '§cNo se ha encontrado ningún punto de control para la misión {0}.' @@ -129,7 +130,7 @@ msg: remover: '§6{0} información de {1} ha sido eliminado.' resetQuest: '§6Removida información de misiones de {0} jugadores.' startQuest: '§6Obligaste a empezar la misión {0} (UUID de Jugador: {1}).' - startQuestNoRequirements: '§cEl jugador no cumple con los requisitos para la misión {0}... Añade "verdadero" al final de tu comando para evitar la comprobación de los requisitos.' + startQuestNoRequirements: '§cEl jugador no cumple con los requisitos para la misión {0}... Añade "-overrideRequirements" al final de tu comando para evitar la comprobación de requisitos.' cancelQuest: '§6Cancelaste la misión {0}.' cancelQuestUnavailable: '&cLa misión {0} no puede ser cancelada.' backupCreated: '&6Creaste correctamente copias de seguridad de misiones e información.' @@ -178,6 +179,7 @@ msg: blockData: '§aEscribe los datos de bloque (datos de bloques disponibles: {0}):' blockTag: '§aEscribe la etiqueta de bloque (etiquetas disponibles: §7{0}§a):' typeBucketAmount: '§aEscribe la cantidad de cubos a rellenar:' + typeDamageAmount: 'Escribe la cantidad de daño que tiene que hacer el jugador:' goToLocation: '§aVe a la ubicación deseada para la etapa y click a la esmeralda.' typeLocationRadius: '§aEscribe la distancia requerida de la ubicación:' typeGameTicks: '§aEscribe los ticks requeridos:' @@ -265,7 +267,7 @@ msg: list: '&aToda la lista de "Mythic Mobs":' isntMythicMob: '§cEste Mob Mítico no existe.' disabled: '§cMythicMob está deshabilitado.' - epicBossDoesntExist: '§cEste Epic Boss no existe.' + advancedSpawnersMob: 'Escribe el nombre del spawner personalizado para matar:' textList: syntax: '§cSintaxis correcta: ' added: '§aTexto "§7{0}§a" añadido.' @@ -338,6 +340,8 @@ inv: breedAnimals: '§aReproducir Animales' tameAnimals: '§aDomesticar animales' death: '§cMuerte' + dealDamage: '§cInflige daño a los mobs' + eatDrink: '§aIngiere o bebe alimentos o pociones' NPCText: '§eEditar dialogo' dialogLines: '{0} líneas' NPCSelect: '§eElegir o crear NPC' @@ -380,6 +384,11 @@ inv: causes: '§aEstablecer causas de muerte §d(AVANZADO)' anyCause: Cualquier causa de muerte setCauses: '{0} causa(s) de muerte' + dealDamage: + damage: '§eDaño para infligir' + targetMobs: '§cMobs para dañar' + eatDrink: + items: '§eEditar items para comer o beber' stages: name: Crear etapas nextPage: '§eSiguiente página' @@ -411,8 +420,6 @@ inv: startableFromGUILore: Permite al jugador comenzar la misión desde el Menú de Misiones. scoreboardItem: Habilitar el scoreboard scoreboardItemLore: Si está desactivado, la misión no será rastreada a través del marcador. - hideItem: Ocultar menú y dynmap - hideItemLore: Si está activado, la misión no se mostrará en el mapa ni en el menú de misiones. 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. bypassLimit: No cuente el límite de misiones @@ -469,6 +476,8 @@ inv: firework: '§dFuego artificial de finalización' fireworkLore: Fuegos artificiales lanzados cuando el jugador termine la misión fireworkLoreDrop: Arrastra aquí tu fuego artificial personalizado + 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. keepDatas: Conservar datos de los jugadores keepDatasLore: |- Forzar el plugin para preservar los datos de los jugadores, aunque las etapas han sido editadas. @@ -510,6 +519,7 @@ inv: §a§lHaz clic izquierdo§a para editar la cantidad. §a§l§nShift§l + clic izquierdo§l para editar el nombre del ratón. §c§lHaz clic derecho§c para eliminar. + setLevel: Nivel mínimo mobSelect: name: Seleccionar tipo de mob bukkitEntityType: '§eSeleccionar tipo de entidad' @@ -621,6 +631,8 @@ inv: poolRedo: '§8Puede rehacer misiones completadas: §7{0}' poolTime: '§8Tiempo entre misiones: §7{0}' poolHologram: '§8Texto del Holograma: §7{0}' + poolAvoidDuplicates: '§8Evitar duplicados: §7{0}' + poolQuestsList: '§7{0} §8Misión(s): §7{1}' create: '§aCrear conjunto de misiones' edit: '§e> §6§oEditar el conjunto... §e<' choose: '§e> §6§oElige este grupo §e<' @@ -670,6 +682,14 @@ inv: name: Causa de daño damageCausesList: name: Lista de causas de daño + visibility: + name: Visibilidad de la misión + notStarted: 'Pestaña de menú: "No iniciado"' + inProgress: 'Pestaña de menú: "En progreso"' + finished: 'Pestaña de menú: "Finalizado"' + maps: 'Mapas (como dynmap o BlueMap)' + equipmentSlots: + name: Ranuras de equipamiento scoreboard: name: '§6§lMisión' noLaunched: '§cNo hay misiones en curso.' @@ -697,6 +717,10 @@ scoreboard: breed: '§eReproducir §6{0}' tame: '§eDomar §6{0}' die: '§cMuerte' + dealDamage: + any: '§cCausa {0} de daño' + mobs: '§cCausa {0} de daño a {1}' + eatDrink: '§eConsumir §6{0}' indication: startQuest: '§7Quieres iniciar la misión {0}?' closeInventory: '§7¿Estás seguro de que quieres cerrar la GUI?' @@ -745,6 +769,8 @@ misc: breedAnimals: Reproducir Animales tameAnimals: Domar animales die: Morir + dealDamage: Inflige daño. + eatDrink: Comer o beber comparison: equals: igual a {0} different: diferente a {0} @@ -767,6 +793,7 @@ misc: quest: '§aMisión requerida' mcMMOSkillLevel: '§dNivel de habilidad requerida' money: '§dDinero requerido' + equipment: '§eEquipamiento requerido' bucket: water: Balde de agua lava: Balde de lava diff --git a/core/src/main/resources/locales/fr_FR.yml b/core/src/main/resources/locales/fr_FR.yml index 09084eac..11f48ac2 100644 --- a/core/src/main/resources/locales/fr_FR.yml +++ b/core/src/main/resources/locales/fr_FR.yml @@ -595,6 +595,7 @@ inv: name: Choisir un bloc material: '§eType de bloc : {0}' materialNotItemLore: 'Le bloc choisi ne peut pas être affiché comme un item. Il est toujours correctement sauvegardé comme {0}.' + blockName: '§bNom de bloc personnalisé' blockData: '§dBlockdata (avancé)' blockTag: '§dTag (avancé)' blockTagLore: 'Choisissez un tag qui décrit une liste de blocs possibles. Les tags peuvent être personnalisés en utilisant des datapacks. Vous pouvez trouver une liste des tags sur le Minecraft Wiki.' diff --git a/core/src/main/resources/locales/hu_HU.yml b/core/src/main/resources/locales/hu_HU.yml index 9a589549..d88f43f1 100644 --- a/core/src/main/resources/locales/hu_HU.yml +++ b/core/src/main/resources/locales/hu_HU.yml @@ -271,17 +271,27 @@ scoreboard: indication: cancelQuest: '§7Biztos vagy benne, hogy megakarod szakítani ezt a küldetést {0}?' removeQuest: '§7Biztos vagy benne, hogy elakarod távolítani ezt a küldetést {0}?' +description: + requirement: + level: 'Szint {0}' misc: format: prefix: '§6<§e§lKüldetések§r§6> §r' npcText: '§6[{2}/{3}] §e§l{0}: §r§e {1}' selfText: '§6[{2}/{3}] §e§l{0}:§r§e {1}' + time: + weeks: '{0} hét' + days: '{0} nap' + hours: '{0} óra' + minutes: '{0} perc' + lessThanAMinute: 'kisebb mint egy perc' stageType: region: Találd meg a helyet npc: Találd meg őt items: Hozz vissza tárgyakat mobs: Ölj meg szörnyeket mine: Törj blokkokat + placeBlocks: Tegyél le egy blokkot chat: Írj chatbe interact: Lépj interakcióba blokkokal Fish: Fogj halakat @@ -304,6 +314,11 @@ misc: water: Vizes vödör lava: Lávás vödör milk: Tejes vödör + click: + right: Jobb klikk + left: Bal klikk + shift-right: Shift+Jobb klikk + shift-left: Shift+Bal klikk questItemLore: '§e§o Küldetés Tárgy' hologramText: '§7§lKüldetés NPC' mobsProgression: '§6§l{0}: §r§e{1}/{2}' diff --git a/core/src/main/resources/locales/it_IT.yml b/core/src/main/resources/locales/it_IT.yml index 3dde7be8..06a8d932 100644 --- a/core/src/main/resources/locales/it_IT.yml +++ b/core/src/main/resources/locales/it_IT.yml @@ -13,6 +13,7 @@ msg: invalidID: '§ cLa quest con id {0} non esiste.' invalidPoolID: '§cLa piscina {0} Non esiste' alreadyStarted: '§cHai già iniziato la missione!' + notStarted: '§cNon stai facendo questa missione attualmente.' quests: maxLaunched: '§cTu non puoi averne più di {0} quest(s) allo stesso momento...' nopStep: '§cQuesta missione non ha alcun obbiettivo.' @@ -27,6 +28,7 @@ msg: questItem: drop: Non puoi buttare un oggetto necessario per la missione! craft: '§cNon puoi usare un oggetto della missione per caftare!' + eat: '§cNon puoi mangiare un oggetto della missione!' stageMobs: noMobs: '§questa fase non ha bisogno di alcun mob da uccidere.' listMobs: '§aDevi uccidere {0}.' @@ -36,6 +38,10 @@ msg: writeMobAmount: '§aScrivi la quantità di mob da uccidere:' writeMobName: '§aScrivi il nome personalizzato del mob da uccidere:' writeChatMessage: '§aScrivi il messaggio richiesto: (Aggiungi "{SLASH}" all''inizio se vuoi usare un comando.)' + writeMessage: '§aScrivi il messaggio che verrà inviato al giocatore' + writeStartMessage: '§aScrivi il messaggio che verrà inviato all''inizio della missione, "null" se vuoi quello predefinito o "none" se non vuoi:' + writeEndMsg: '§aScrivi il messaggio che verrà inviato alla fine della missione, "null" se vuoi quello predefinito o "nessuno" se vuoi nessuno. È possibile utilizzare "{0}" che verrà sostituito con i premi ottenuti.' + writeEndSound: '§aScrivi il nome del suono che verrà riprodotto al giocatore alla fine della missione, "null" se vuoi quello predefinito o "none" se non vuoi:' writeDescriptionText: '§aScrivi il testo che descrive l''obiettivo della fase:' writeStageText: '§aScrivi il testo che verrà inviato al giocatore all''inizio della fase:' moveToTeleportPoint: '§aVai alla posizione di teletrasporto desiderata.' @@ -55,6 +61,7 @@ msg: skill: '§cIl tuo livello per l''abilità §e{1}§c deve essere {0}!' combatLevel: '§cIl tuo livello di combattimento deve essere {0}!' money: '§cDevi avere {0}!' + waitTime: '§cDevi aspettare {0} minuto(i) prima di poter riavviare questa missione!' experience: edited: '§aHai cambiato l''esperienza guadagnata da {0} a {1} punti.' selectNPCToKill: '§aSeleziona il NPC da uccidere.' @@ -68,10 +75,12 @@ msg: negative: '§cDevi inserire un numero positivo!' zero: '§cDevi inserire un numero diverso da 0!' invalid: '§c{0} non è un numero valido.' + notInBounds: Il valore di entrata deve essere compreso fra {0} e {1} errorOccurred: '§cSi è verificato un errore, contatta un amministratore! §4§lCodice di errore: {0}' commandsDisabled: '§cAttualmente non sei autorizzato a eseguire comandi!' indexOutOfBounds: '§cIl numero {0} è fuori dai limiti! Deve essere compreso tra {1} e {2}.' invalidBlockData: '§cIl blockdata {0} non è valido o incompatibile con il blocco {1}.' + invalidBlockTag: '§cTag blocco {0} non disponibile.' bringBackObjects: Riportami {0}. inventoryFull: '§cIl tuo inventario è pieno, l''oggetto è stato droppato sul pavimento.' playerNeverConnected: '§cImpossibile trovare informazioni sul giocatore {0}.' @@ -204,7 +213,6 @@ msg: list: '§aUn elenco di tutti i Mythic Mobs:' isntMythicMob: '§cQuesto Mythic Mob non esiste.' disabled: '§cMythicMob è disabilitato.' - epicBossDoesntExist: '§cQuesto Epic Boss non esiste.' textList: syntax: '§cSintassi corretta: ' help: @@ -291,7 +299,6 @@ inv: itemLore: "La missione può essere \navviata più volte?" cancellable: Annullabile dal giocatore scoreboardItem: Abilita scoreboard - hideItem: Nascondi menu e dynmap bypassLimit: Non contare il limite della quest questName: '§a§lModifica il nome della quest' setItemsRewards: '§eModifica ricompense' diff --git a/core/src/main/resources/locales/ru_RU.yml b/core/src/main/resources/locales/ru_RU.yml index f6424705..0903da63 100644 --- a/core/src/main/resources/locales/ru_RU.yml +++ b/core/src/main/resources/locales/ru_RU.yml @@ -13,6 +13,7 @@ msg: invalidID: '§cКвест под номером {0}, не найден.' invalidPoolID: '§cВетка {0} не существует.' alreadyStarted: '§cВы уже начали квест!' + notStarted: '§cВ данный момент вы не выполняете этот квест.' quests: maxLaunched: '§cВы не можете взять больше {0} задания(й) одновременно...' nopStep: '§cУ этого квеста нету каких либо этапов.' @@ -87,11 +88,12 @@ msg: playerDataNotFound: '§cДанные игрока {0} не найдены.' versionRequired: 'Требуемая версия: §l{0}' restartServer: '§7Перезагрузите сервер, чтобы увидеть изменения.' + dialogs: + skipped: '§8§o Диалог пропущен.' command: downloadTranslations: syntax: '§cНеобходимо указать язык для загрузки. Пример: "/quests downloadTranslations ru_RU".' notFound: '§cЯзык {0} не найден для версии {1}.' - exists: '§cФайл {0} уже существует. Добавьте "true" к команде для его перезаписи. (/quests downloads true)' downloaded: '§aЯзык {0} загружен! §7Вы должны отредактировать файл "/plugins/BeautyQuests/config.yml", чтобы изменить значение §ominecraftTranslationsFile§7 с {0}, а затем перезапустить сервер.' checkpoint: noCheckpoint: '§cКонтрольная точка для задания {0} не найдена.' @@ -121,7 +123,6 @@ msg: remover: '§6{0} Данные о квесте(ах) {1} удалены.' resetQuest: '§6Удалены данные квеста для {0} игроков.' startQuest: '§6Вы принудительно начали задание {0} (UUID игрока: {1}).' - startQuestNoRequirements: '§cИгрок не выполнил требования для задания {0}... Добавьте "true" в конце команды, чтобы пропустить проверку требований.' cancelQuest: '§6Вы отменили квест {0}.' cancelQuestUnavailable: '§cЗадание {0} не может быть отменено.' backupCreated: '§6Вы успешно создали резервную копию всех квестов и информации о игроках.' @@ -237,7 +238,6 @@ msg: list: '§aСписок всех Mythic Mobs:' isntMythicMob: '§cЭтот Mythic Mob не существует.' disabled: '§cMythicMob отключен.' - epicBossDoesntExist: '§cЭтот Epic Boss не существует.' textList: syntax: '§cПравильный синтаксис: ' added: '§aТекст "§7{0}§a" добавлен.' @@ -357,8 +357,6 @@ inv: startableFromGUILore: Позволяет игроку начать квест из меню квестов. scoreboardItem: Включить табло scoreboardItemLore: Если этот параметр отключен, квест не будет отслеживаться на табло. - hideItem: Скрыть меню и динамическую карту - hideItemLore: Если этот параметр включен, квест не будет отображаться ни на динамической карте, ни в меню квестов. hideNoRequirementsItem: Скрыть когда требования не выполнены hideNoRequirementsItemLore: Если включено, задание не будет отображаться в меню заданий, когда требования не выполняются. bypassLimit: Не считайте лимит квестов From 3a21b1816754a9fb3cee7c1f75c2b2f3391d44cf Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Fri, 20 Jan 2023 19:34:27 +0100 Subject: [PATCH 17/41] :sparkles: Added placeholder for percentage stage progression --- core/src/main/java/fr/skytasul/quests/utils/Utils.java | 4 +++- core/src/main/resources/config.yml | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/fr/skytasul/quests/utils/Utils.java b/core/src/main/java/fr/skytasul/quests/utils/Utils.java index 88d3b939..8d6db611 100644 --- a/core/src/main/java/fr/skytasul/quests/utils/Utils.java +++ b/core/src/main/java/fr/skytasul/quests/utils/Utils.java @@ -161,7 +161,9 @@ public static String getStringFromItemStack(ItemStack is, String amountColor, bo } public static String getStringFromNameAndAmount(String name, String amountColor, int remaining, int total, boolean showXOne) { - return name + ((remaining > 1 || showXOne) ? "§r" + amountColor + " " + Utils.format(QuestsConfiguration.getDescriptionAmountFormat(), remaining, total - remaining, total) : ""); + int done = total - remaining; + int percentage = (int) (done / (double) total * 100); + return name + ((remaining > 1 || showXOne) ? "§r" + amountColor + " " + Utils.format(QuestsConfiguration.getDescriptionAmountFormat(), remaining, done, percentage) : ""); } public static void sendMessage(CommandSender sender, String msg, Object... replace){ diff --git a/core/src/main/resources/config.yml b/core/src/main/resources/config.yml index 9f4d7765..9a3f1b97 100644 --- a/core/src/main/resources/config.yml +++ b/core/src/main/resources/config.yml @@ -151,7 +151,7 @@ itemAmountColor: "§e" stageDescriptionItemsSplit: # Prefix before each line prefix: "§e- §6" - # Format of object amounts. Placeholders: {0} = remaining (decreasing), {1} = done (increasing), {2} = total. Example: "{1}/{2}" + # Format of object amounts. Placeholders: {0} = remaining (decreasing), {1} = done (increasing), {2} = total, {3} = percentage (0 to 100). Example: "{1}/{2}" amountFormat: "x{0}" # Show amount format if there is only one object remaining showXOne: true From b7ebab78383d9642ed239b1d399c7fc46d744efd Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Fri, 20 Jan 2023 19:34:51 +0100 Subject: [PATCH 18/41] :bug: Fixed scoreboard not being used at full width --- .../main/java/fr/skytasul/quests/scoreboards/Scoreboard.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/fr/skytasul/quests/scoreboards/Scoreboard.java b/core/src/main/java/fr/skytasul/quests/scoreboards/Scoreboard.java index 8f5a5362..ce6ebac7 100644 --- a/core/src/main/java/fr/skytasul/quests/scoreboards/Scoreboard.java +++ b/core/src/main/java/fr/skytasul/quests/scoreboards/Scoreboard.java @@ -32,7 +32,7 @@ public class Scoreboard extends BukkitRunnable implements Listener { private static final Pattern QUEST_PLACEHOLDER = Pattern.compile("\\{quest_(.+)\\}"); - private static final int maxLength = NMS.getMCVersion() >= 13 ? 128 : 30; + private static final int maxLength = NMS.getMCVersion() >= 13 ? 1024 : 30; private PlayerAccount acc; private Player p; From 2d91c575423fdfde19ffd2ff02e3b6f0c2b26fca Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Fri, 27 Jan 2023 19:14:33 +0100 Subject: [PATCH 19/41] :recycle: Refactored countable stage internally + updated "kill mobs" GUI --- .../java/fr/skytasul/quests/api/mobs/Mob.java | 7 +- .../types/AbstractCountableBlockStage.java | 32 ++-- .../stages/types/AbstractCountableStage.java | 154 ++++++++++++----- .../api/stages/types/AbstractItemStage.java | 27 ++- .../skytasul/quests/gui/blocks/BlocksGUI.java | 92 +++------- .../quests/gui/creation/QuestObjectGUI.java | 6 +- .../skytasul/quests/gui/mobs/MobsListGUI.java | 157 +++++++----------- .../quests/gui/templates/ListGUI.java | 5 +- .../quests/gui/templates/PagedGUI.java | 22 ++- .../skytasul/quests/stages/StageEatDrink.java | 12 +- .../skytasul/quests/stages/StageEnchant.java | 12 +- .../fr/skytasul/quests/stages/StageFish.java | 12 +- .../fr/skytasul/quests/stages/StageMelt.java | 12 +- .../fr/skytasul/quests/stages/StageMine.java | 25 ++- .../fr/skytasul/quests/stages/StageMobs.java | 38 +++-- .../quests/stages/StagePlaceBlocks.java | 14 +- .../java/fr/skytasul/quests/utils/Lang.java | 2 - .../java/fr/skytasul/quests/utils/Utils.java | 7 +- .../quests/utils/types/CountableObject.java | 105 ++++++++++++ 19 files changed, 431 insertions(+), 310 deletions(-) create mode 100644 core/src/main/java/fr/skytasul/quests/utils/types/CountableObject.java diff --git a/core/src/main/java/fr/skytasul/quests/api/mobs/Mob.java b/core/src/main/java/fr/skytasul/quests/api/mobs/Mob.java index d7a0b4ef..5ad50345 100644 --- a/core/src/main/java/fr/skytasul/quests/api/mobs/Mob.java +++ b/core/src/main/java/fr/skytasul/quests/api/mobs/Mob.java @@ -3,6 +3,7 @@ import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.apache.commons.lang.Validate; import org.bukkit.entity.Entity; @@ -50,6 +51,10 @@ public String getName() { return formattedName; } + public List getDescriptiveLore() { + return factory.getDescriptiveLore(data); + } + public void setCustomName(String customName) { this.customName = customName; } @@ -143,5 +148,5 @@ public static Mob deserialize(Map map) { mob.setMinLevel((Double) map.get("minLevel")); return mob; } - + } diff --git a/core/src/main/java/fr/skytasul/quests/api/stages/types/AbstractCountableBlockStage.java b/core/src/main/java/fr/skytasul/quests/api/stages/types/AbstractCountableBlockStage.java index 897be7e4..cb623b2a 100644 --- a/core/src/main/java/fr/skytasul/quests/api/stages/types/AbstractCountableBlockStage.java +++ b/core/src/main/java/fr/skytasul/quests/api/stages/types/AbstractCountableBlockStage.java @@ -1,24 +1,24 @@ package fr.skytasul.quests.api.stages.types; -import java.util.Map; -import java.util.Map.Entry; - +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; - import fr.skytasul.quests.api.stages.StageCreation; -import fr.skytasul.quests.gui.Inventories; import fr.skytasul.quests.gui.ItemUtils; import fr.skytasul.quests.gui.blocks.BlocksGUI; import fr.skytasul.quests.gui.creation.stages.Line; import fr.skytasul.quests.structure.QuestBranch; import fr.skytasul.quests.utils.Lang; import fr.skytasul.quests.utils.types.BQBlock; +import fr.skytasul.quests.utils.types.CountableObject; +import fr.skytasul.quests.utils.types.CountableObject.MutableCountableObject; public abstract class AbstractCountableBlockStage extends AbstractCountableStage { - protected AbstractCountableBlockStage(QuestBranch branch, Map> objects) { + protected AbstractCountableBlockStage(QuestBranch branch, List> objects) { super(branch, objects); } @@ -45,28 +45,30 @@ protected BQBlock deserialize(Object object) { public abstract static class AbstractCreator extends StageCreation { - protected Map> blocks; + protected List> blocks; protected AbstractCreator(Line line, boolean ending) { super(line, ending); line.setItem(getBlocksSlot(), getBlocksItem(), (p, item) -> { - BlocksGUI blocksGUI = Inventories.create(p, new BlocksGUI()); - blocksGUI.setBlocksFromMap(blocks); - blocksGUI.run = obj -> { + new BlocksGUI(blocks, obj -> { setBlocks(obj); reopenGUI(p, true); - }; + }).create(p); }); } + public List> getImmutableBlocks() { + return blocks.stream().map(MutableCountableObject::toImmutable).collect(Collectors.toList()); + } + protected abstract ItemStack getBlocksItem(); protected int getBlocksSlot() { return 7; } - public void setBlocks(Map> blocks) { + public void setBlocks(List> blocks) { this.blocks = blocks; line.editItem(getBlocksSlot(), ItemUtils.lore(line.getItem(getBlocksSlot()), Lang.optionValue.format(blocks.size() + " blocks"))); } @@ -74,16 +76,16 @@ public void setBlocks(Map> blocks) { @Override public void start(Player p) { super.start(p); - Inventories.create(p, new BlocksGUI()).run = obj -> { + new BlocksGUI(Collections.emptyList(), obj -> { setBlocks(obj); reopenGUI(p, true); - }; + }).create(p); } @Override public void edit(T stage) { super.edit(stage); - setBlocks(stage.cloneObjects()); + setBlocks(stage.getMutableObjects()); } } diff --git a/core/src/main/java/fr/skytasul/quests/api/stages/types/AbstractCountableStage.java b/core/src/main/java/fr/skytasul/quests/api/stages/types/AbstractCountableStage.java index d24fc310..cd451ae3 100644 --- a/core/src/main/java/fr/skytasul/quests/api/stages/types/AbstractCountableStage.java +++ b/core/src/main/java/fr/skytasul/quests/api/stages/types/AbstractCountableStage.java @@ -2,9 +2,13 @@ import java.util.AbstractMap; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Optional; +import java.util.UUID; import java.util.function.Supplier; +import java.util.stream.Collectors; import org.bukkit.Bukkit; import org.bukkit.boss.BarColor; import org.bukkit.boss.BarStyle; @@ -21,45 +25,97 @@ import fr.skytasul.quests.structure.QuestBranch.Source; import fr.skytasul.quests.utils.Lang; import fr.skytasul.quests.utils.Utils; +import fr.skytasul.quests.utils.types.CountableObject; +import fr.skytasul.quests.utils.types.CountableObject.MutableCountableObject; public abstract class AbstractCountableStage extends AbstractStage { - protected Map> objects; + protected final List> objects; protected Map bars = new HashMap<>(); private boolean barsEnabled = false; private int cachedSize = 0; - public AbstractCountableStage(QuestBranch branch, Map> objects) { + protected AbstractCountableStage(QuestBranch branch, List> objects) { super(branch); this.objects = objects; calculateSize(); } - public Map> getObjects() { + @Deprecated + protected AbstractCountableStage(QuestBranch branch, Map> objects) { + this(branch, objects.keySet().stream().sorted().map(index -> { + Entry entry = objects.get(index); + return CountableObject.create(uuidFromLegacyIndex(index), entry.getKey(), entry.getValue()); + }).collect(Collectors.toList())); + + BeautyQuests.logger.warning("The stage " + getType().getName() + + " uses an outdated way to store player datas. Please notice its author."); + } + + public List> getObjects() { return objects; } + public List> getMutableObjects() { + return objects.stream().map(countable -> CountableObject.createMutable(countable.getUUID(), + cloneObject(countable.getObject()), countable.getAmount())).collect(Collectors.toList()); + } + + public Optional> getObject(UUID uuid) { + return objects.stream().filter(object -> object.getUUID().equals(uuid)).findAny(); + } + + @Deprecated public Map> cloneObjects() { Map> map = new HashMap<>(); - for (Entry> entry : objects.entrySet()) { - map.put(entry.getKey(), new AbstractMap.SimpleEntry<>(cloneObject(entry.getValue().getKey()), entry.getValue().getValue())); + for (int id = 0; id < objects.size(); id++) { + CountableObject object = objects.get(id); + map.put(id, new AbstractMap.SimpleEntry<>(cloneObject(object.getObject()), object.getAmount())); } return map; } - public Map getPlayerRemainings(PlayerAccount acc, boolean warnNull) { - Map remaining = getData(acc, "remaining"); + @SuppressWarnings("rawtypes") + public Map getPlayerRemainings(PlayerAccount acc, boolean warnNull) { + Map remaining = getData(acc, "remaining"); if (warnNull && remaining == null) BeautyQuests.logger.severe("Cannot retrieve stage datas for " + acc.getNameAndID() + " on " + super.toString()); - return remaining; + + if (remaining == null || remaining.isEmpty()) + return (Map) remaining; + + Object object = remaining.keySet().iterator().next(); + if (object instanceof Integer) { + // datas before migration + Map newRemaining = new HashMap<>(remaining.size()); + Map dataMap = new HashMap<>(remaining.size()); + remaining.forEach((key, amount) -> { + UUID uuid = uuidFromLegacyIndex((Integer) key); + if (!getObject(uuid).isPresent()) { + BeautyQuests.logger.warning("Cannot migrate " + acc.getNameAndID() + " data for stage " + toString() + + " as there is no migrated data for object " + key); + } + newRemaining.put(uuid, amount); + dataMap.put(uuid.toString(), amount); + }); + updateObjective(acc, acc.getPlayer(), "remaining", dataMap); + return newRemaining; + } else if (object instanceof String) { + // datas stored as string + return remaining.entrySet().stream() + .collect(Collectors.toMap(entry -> UUID.fromString((String) entry.getKey()), Entry::getValue)); + } else + throw new UnsupportedOperationException(object.getClass().getName()); + } + + protected void updatePlayerRemaining(PlayerAccount acc, Player player, Map remaining) { + updateObjective(acc, player, "remaining", remaining.entrySet().stream() + .collect(Collectors.toMap(entry -> entry.getKey().toString(), Entry::getValue))); } protected void calculateSize() { - cachedSize = 0; - for (Entry objectsEntry : objects.values()) { - cachedSize += objectsEntry.getValue(); - } + cachedSize = objects.stream().mapToInt(CountableObject::getAmount).sum(); barsEnabled = QuestsConfiguration.showMobsProgressBar() && cachedSize > 0; } @@ -74,14 +130,17 @@ protected Supplier[] descriptionFormat(PlayerAccount acc, Source source) } private String[] buildRemainingArray(PlayerAccount acc, Source source) { - Map playerAmounts = getPlayerRemainings(acc, true); + Map playerAmounts = getPlayerRemainings(acc, true); if (playerAmounts == null) return new String[] { "§4§lerror" }; String[] elements = new String[playerAmounts.size()]; + int i = 0; - for (Entry obj : playerAmounts.entrySet()) { - Entry object = objects.get(obj.getKey()); - elements[i] = object == null ? "no object " + obj.getKey() : QuestsConfiguration.getItemNameColor() + Utils.getStringFromNameAndAmount(getName(object.getKey()), QuestsConfiguration.getItemAmountColor(), obj.getValue(), object.getValue(), QuestsConfiguration.showDescriptionItemsXOne(source)); - i++; + for (Entry entry : playerAmounts.entrySet()) { + elements[i++] = getObject(entry.getKey()) + .map(object -> QuestsConfiguration.getItemNameColor() + Utils.getStringFromNameAndAmount( + getName(object.getObject()), QuestsConfiguration.getItemAmountColor(), entry.getValue(), + object.getAmount(), QuestsConfiguration.showDescriptionItemsXOne(source))) + .orElse("no object " + entry.getKey()); } return elements; } @@ -89,11 +148,8 @@ private String[] buildRemainingArray(PlayerAccount acc, Source source) { @Override protected void initPlayerDatas(PlayerAccount acc, Map datas) { super.initPlayerDatas(acc, datas); - Map amounts = new HashMap<>(); - for (Entry> entry : objects.entrySet()) { - amounts.put(entry.getKey(), entry.getValue().getValue()); - } - datas.put("remaining", amounts); + datas.put("remaining", objects.stream() + .collect(Collectors.toMap(object -> object.getUUID().toString(), CountableObject::getAmount))); } /** @@ -109,17 +165,18 @@ protected void initPlayerDatas(PlayerAccount acc, Map datas) { public boolean event(PlayerAccount acc, Player p, Object object, int amount) { if (amount < 0) throw new IllegalArgumentException("Event amount must be positive (" + amount + ")"); if (!canUpdate(p)) return true; - for (Entry> entry : objects.entrySet()) { - int id = entry.getKey(); - if (objectApplies(entry.getValue().getKey(), object)) { - Map playerAmounts = getPlayerRemainings(acc, true); + + for (CountableObject countableObject : objects) { + if (objectApplies(countableObject.getObject(), object)) { + Map playerAmounts = getPlayerRemainings(acc, true); if (playerAmounts == null) return true; - if (playerAmounts.containsKey(id)) { - int playerAmount = playerAmounts.get(id); + if (playerAmounts.containsKey(countableObject.getUUID())) { + int playerAmount = playerAmounts.remove(countableObject.getUUID()); if (playerAmount <= amount) { - playerAmounts.remove(id); + // playerAmount - amount will be negative, so this object must be removed. + // we do nothing as the entry has already been deleted } else - playerAmounts.put(id, playerAmount - amount); + playerAmounts.put(countableObject.getUUID(), playerAmount - amount); } else continue; @@ -133,7 +190,8 @@ public boolean event(PlayerAccount acc, Player p, Object object, int amount) { BeautyQuests.logger.warning(p.getName() + " does not have boss bar for stage " + toString() + ". This is a bug!"); }else bar.update(playerAmounts.values().stream().mapToInt(Integer::intValue).sum()); } - updateObjective(acc, p, "remaining", playerAmounts); + + updatePlayerRemaining(acc, p, playerAmounts); return false; } } @@ -162,7 +220,7 @@ public void unload() { @Override public void joins(PlayerAccount acc, Player p) { super.joins(acc, p); - Map remainings = getPlayerRemainings(acc, true); + Map remainings = getPlayerRemainings(acc, true); if (remainings == null) return; createBar(p, remainings.values().stream().mapToInt(Integer::intValue).sum()); } @@ -175,7 +233,7 @@ public void leaves(PlayerAccount acc, Player p) { protected void createBar(Player p, int amount) { if (barsEnabled) { - if (bars.containsKey(p)) { + if (bars.containsKey(p)) { // NOSONAR Map#computeIfAbsent cannot be used here as we should log the issue BeautyQuests.logger.warning("Trying to create an already existing bossbar for player " + p.getName()); return; } @@ -211,11 +269,12 @@ protected void serialize(Map map) {} @Override protected void serialize(ConfigurationSection section) { ConfigurationSection objectsSection = section.createSection("objects"); - for (Entry> obj : objects.entrySet()) { - ConfigurationSection objectSection = objectsSection.createSection(Integer.toString(obj.getKey())); - objectSection.set("amount", obj.getValue().getValue()); - objectSection.set("object", serialize(obj.getValue().getKey())); + for (CountableObject obj : objects) { + ConfigurationSection objectSection = objectsSection.createSection(obj.getUUID().toString()); + objectSection.set("amount", obj.getAmount()); + objectSection.set("object", serialize(obj.getObject())); } + Map serialized = new HashMap<>(); serialize(serialized); Utils.setConfigurationSectionContent(section, serialized); @@ -233,17 +292,30 @@ protected void deserialize(ConfigurationSection section) { ConfigurationSection objectsSection = section.getConfigurationSection("objects"); if (objectsSection != null) { for (String key : objectsSection.getKeys(false)) { - ConfigurationSection object = objectsSection.getConfigurationSection(key); - Object serialized = object.get("object"); + UUID uuid; + try { + uuid = UUID.fromString(key); + } catch (IllegalArgumentException ex) { + uuid = uuidFromLegacyIndex(Integer.parseInt(key)); + } + + ConfigurationSection objectSection = objectsSection.getConfigurationSection(key); + Object serialized = objectSection.get("object"); if (serialized instanceof ConfigurationSection) serialized = ((ConfigurationSection) serialized).getValues(false); - objects.put(Integer.parseInt(key), new AbstractMap.SimpleEntry<>(deserialize(serialized), object.getInt("amount"))); + objects.add(CountableObject.create(uuid, deserialize(serialized), objectSection.getInt("amount"))); } } - + if (objects.isEmpty()) BeautyQuests.logger.warning("Stage with no content: " + toString()); calculateSize(); } + private static UUID uuidFromLegacyIndex(int index) { // useful for migration purpose + return new UUID(index, 2478L); + // 2478 is a magic value, the only necessity is that it stays constant + // and I like the number 2478 + } + class BossBar { private Player p; private BQBossBar bar; diff --git a/core/src/main/java/fr/skytasul/quests/api/stages/types/AbstractItemStage.java b/core/src/main/java/fr/skytasul/quests/api/stages/types/AbstractItemStage.java index 21e5f81a..6f87844b 100644 --- a/core/src/main/java/fr/skytasul/quests/api/stages/types/AbstractItemStage.java +++ b/core/src/main/java/fr/skytasul/quests/api/stages/types/AbstractItemStage.java @@ -1,17 +1,14 @@ package fr.skytasul.quests.api.stages.types; -import java.util.AbstractMap; +import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Map.Entry; +import java.util.UUID; import java.util.stream.Collectors; - import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; - import fr.skytasul.quests.api.comparison.ItemComparisonMap; import fr.skytasul.quests.api.stages.StageCreation; import fr.skytasul.quests.gui.ItemUtils; @@ -22,18 +19,20 @@ import fr.skytasul.quests.utils.Lang; import fr.skytasul.quests.utils.Utils; import fr.skytasul.quests.utils.XMaterial; +import fr.skytasul.quests.utils.types.CountableObject; public abstract class AbstractItemStage extends AbstractCountableStage { protected final ItemComparisonMap comparisons; - protected AbstractItemStage(QuestBranch branch, Map> objects, ItemComparisonMap comparisons) { + protected AbstractItemStage(QuestBranch branch, List> objects, + ItemComparisonMap comparisons) { super(branch, objects); this.comparisons = comparisons; } protected AbstractItemStage(QuestBranch branch, ConfigurationSection section) { - super(branch, new HashMap<>()); + super(branch, new ArrayList<>()); if (section.contains("itemComparisons")) { comparisons = new ItemComparisonMap(section.getConfigurationSection("itemComparisons")); @@ -121,9 +120,9 @@ public void start(Player p) { @Override public void edit(T stage) { super.edit(stage); - setItems(stage.getObjects().values().stream().map(entry -> { - ItemStack item = entry.getKey().clone(); - item.setAmount(entry.getValue()); + setItems(stage.getObjects().stream().map(entry -> { + ItemStack item = entry.getObject().clone(); + item.setAmount(entry.getAmount()); return item; }).collect(Collectors.toList())); setComparisons(stage.comparisons.clone()); @@ -131,18 +130,18 @@ public void edit(T stage) { @Override public final T finishStage(QuestBranch branch) { - Map> itemsMap = new HashMap<>(); + List> itemsMap = new ArrayList<>(); for (int i = 0; i < items.size(); i++) { ItemStack item = items.get(i); int amount = item.getAmount(); item.setAmount(1); - itemsMap.put(i, new AbstractMap.SimpleEntry<>(item, amount)); + itemsMap.add(CountableObject.create(new UUID(item.hashCode(), 2478), item, amount)); } return finishStage(branch, itemsMap, comparisons); } - protected abstract T finishStage(QuestBranch branch, Map> itemsMap, ItemComparisonMap comparisons); + protected abstract T finishStage(QuestBranch branch, List> items, ItemComparisonMap comparisons); } - + } \ No newline at end of file diff --git a/core/src/main/java/fr/skytasul/quests/gui/blocks/BlocksGUI.java b/core/src/main/java/fr/skytasul/quests/gui/blocks/BlocksGUI.java index b7060d93..78b2024c 100644 --- a/core/src/main/java/fr/skytasul/quests/gui/blocks/BlocksGUI.java +++ b/core/src/main/java/fr/skytasul/quests/gui/blocks/BlocksGUI.java @@ -1,91 +1,45 @@ package fr.skytasul.quests.gui.blocks; import static fr.skytasul.quests.gui.ItemUtils.item; - -import java.util.AbstractMap; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; +import java.util.Collection; +import java.util.List; +import java.util.UUID; import java.util.function.Consumer; - -import org.bukkit.Bukkit; -import org.bukkit.Material; -import org.bukkit.entity.Player; -import org.bukkit.event.inventory.ClickType; -import org.bukkit.inventory.Inventory; +import java.util.function.Function; +import org.bukkit.DyeColor; import org.bukkit.inventory.ItemStack; - -import fr.skytasul.quests.gui.CustomInventory; -import fr.skytasul.quests.gui.Inventories; +import fr.skytasul.quests.gui.templates.ListGUI; import fr.skytasul.quests.utils.Lang; -import fr.skytasul.quests.utils.XMaterial; import fr.skytasul.quests.utils.types.BQBlock; +import fr.skytasul.quests.utils.types.CountableObject; +import fr.skytasul.quests.utils.types.CountableObject.MutableCountableObject; -public class BlocksGUI implements CustomInventory { +public class BlocksGUI extends ListGUI> { - private ItemStack none = item(XMaterial.RED_STAINED_GLASS_PANE, "§c", Lang.addBlock.toString()); - private ItemStack done = item(XMaterial.DIAMOND, Lang.done.toString()); - - public Map> blocks = new HashMap<>(); - - public Inventory inv; - public Consumer>> run; - - public CustomInventory openLastInv(Player p) { - p.openInventory(inv); - return this; + private Consumer>> end; + + public BlocksGUI(Collection> blocks, + Consumer>> end) { + super(Lang.INVENTORY_BLOCKSLIST.toString(), DyeColor.GREEN, blocks); + this.end = end; } @Override - public Inventory open(Player p) { - inv = Bukkit.createInventory(null, 9, Lang.INVENTORY_BLOCKSLIST.toString()); - - inv.setItem(8, done); - for (int i = 0; i < 8; i++) inv.setItem(i, none.clone()); - - return inv = p.openInventory(inv).getTopInventory(); + public void finish(List> objects) { + end.accept(objects); } @Override - public boolean onClick(Player p, Inventory inv, ItemStack is, int slot, ClickType click) { - if (slot == 8){ - Inventories.closeAndExit(p); - run.accept(blocks); - return true; - } - if (click.isRightClick()){ - blocks.remove(slot); - inv.setItem(slot, none); - return true; - } + public void createObject(Function, ItemStack> callback) { new SelectBlockGUI(true, (type, amount) -> { - Inventories.put(p, openLastInv(p), inv); - setItem(inv, slot, type.getMaterial(), type.getAsString(), amount); - blocks.put(slot, new AbstractMap.SimpleEntry<>(type, amount)); + callback.apply(CountableObject.createMutable(UUID.randomUUID(), type, amount)); }).create(p); - return true; - } - - public void setBlocksFromMap(Map> map) { - for (Entry> entry : map.entrySet()) { - int id = entry.getKey(); - Entry blockEntry = entry.getValue(); - blocks.put(id, blockEntry); - setItem(inv, id, blockEntry.getKey().getMaterial(), blockEntry.getKey().getAsString(), blockEntry.getValue()); - } - } - - @Override - public CloseBehavior onClose(Player p, Inventory inv) { - return CloseBehavior.REOPEN; } - public static void setItem(Inventory inv, int slot, XMaterial type, String name, int amount) { - if (type == null) return; - ItemStack is = item(type, Lang.materialName.format(name), Lang.Amount.format(amount)); - inv.setItem(slot, is); - is = inv.getItem(slot); - if (is == null || is.getType() == Material.AIR) setItem(inv, slot, XMaterial.STONE, name, amount); + @Override + public ItemStack getObjectItemStack(MutableCountableObject object) { + return item(object.getObject().getMaterial(), Lang.materialName.format(object.getObject().getAsString()), + Lang.Amount.format(object.getAmount())); } } diff --git a/core/src/main/java/fr/skytasul/quests/gui/creation/QuestObjectGUI.java b/core/src/main/java/fr/skytasul/quests/gui/creation/QuestObjectGUI.java index 95e8276c..6b4f7004 100644 --- a/core/src/main/java/fr/skytasul/quests/gui/creation/QuestObjectGUI.java +++ b/core/src/main/java/fr/skytasul/quests/gui/creation/QuestObjectGUI.java @@ -5,13 +5,11 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; - 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 fr.skytasul.quests.api.QuestsAPI; import fr.skytasul.quests.api.objects.QuestObject; import fr.skytasul.quests.api.objects.QuestObjectClickEvent; @@ -110,7 +108,9 @@ public static void initialize(){ QuestsAPI.getRewards().register(new RewardCreator("requirementDependentReward", RequirementDependentReward.class, ItemUtils.item(XMaterial.REDSTONE, Lang.rewardWithRequirements.toString()), RequirementDependentReward::new, true).setCanBeAsync(true)); QuestsAPI.getRewards().register(new RewardCreator("randomReward", RandomReward.class, ItemUtils.item(XMaterial.EMERALD, Lang.rewardRandom.toString()), RandomReward::new, true).setCanBeAsync(true)); QuestsAPI.getRewards().register(new RewardCreator("wait", WaitReward.class, ItemUtils.item(XMaterial.CLOCK, Lang.rewardWait.toString()), WaitReward::new, true).setCanBeAsync(true)); - QuestsAPI.getRewards().register(new RewardCreator("titleReward", TitleReward.class, ItemUtils.item(XMaterial.NAME_TAG, Lang.rewardTitle.toString()), TitleReward::new, false)); + if (NMS.getMCVersion() >= 9) + QuestsAPI.getRewards().register(new RewardCreator("titleReward", TitleReward.class, + ItemUtils.item(XMaterial.NAME_TAG, Lang.rewardTitle.toString()), TitleReward::new, false)); DebugUtils.logMessage("Initlializing default requirements."); diff --git a/core/src/main/java/fr/skytasul/quests/gui/mobs/MobsListGUI.java b/core/src/main/java/fr/skytasul/quests/gui/mobs/MobsListGUI.java index 75d4a201..31478fc9 100644 --- a/core/src/main/java/fr/skytasul/quests/gui/mobs/MobsListGUI.java +++ b/core/src/main/java/fr/skytasul/quests/gui/mobs/MobsListGUI.java @@ -1,130 +1,97 @@ package fr.skytasul.quests.gui.mobs; -import java.util.AbstractMap; import java.util.ArrayList; -import java.util.HashMap; +import java.util.Collection; import java.util.List; -import java.util.Map; -import java.util.Map.Entry; +import java.util.UUID; import java.util.function.Consumer; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; +import java.util.function.Function; +import org.bukkit.DyeColor; import org.bukkit.event.inventory.ClickType; -import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import fr.skytasul.quests.api.mobs.LeveledMobFactory; import fr.skytasul.quests.api.mobs.Mob; import fr.skytasul.quests.editors.TextEditor; import fr.skytasul.quests.editors.checkers.NumberParser; -import fr.skytasul.quests.gui.CustomInventory; -import fr.skytasul.quests.gui.Inventories; import fr.skytasul.quests.gui.ItemUtils; +import fr.skytasul.quests.gui.templates.ListGUI; import fr.skytasul.quests.utils.Lang; import fr.skytasul.quests.utils.Utils; -import fr.skytasul.quests.utils.XMaterial; +import fr.skytasul.quests.utils.types.CountableObject; +import fr.skytasul.quests.utils.types.CountableObject.MutableCountableObject; -public class MobsListGUI implements CustomInventory{ +public class MobsListGUI extends ListGUI>> { - private ItemStack none = ItemUtils.item(XMaterial.RED_STAINED_GLASS_PANE, "§c", Lang.mobsNone.toString()); - - public Map, Integer>> mobs = new HashMap<>(); - - public Inventory inv; - public Consumer, Integer>>> run; - - public CustomInventory openLastInv(Player p) { - p.openInventory(inv); - return this; - } + private Consumer>>> end; - @Override - public Inventory open(Player p){ - inv = Bukkit.createInventory(null, 9, Lang.INVENTORY_MOBS.toString()); - - inv.setItem(8, ItemUtils.itemDone); - for (int i = 0; i < 8; i++) inv.setItem(i, none.clone()); - - inv = p.openInventory(inv).getTopInventory(); - return inv; + public MobsListGUI(Collection>> objects, + Consumer>>> end) { + super(Lang.INVENTORY_MOBS.toString(), DyeColor.ORANGE, objects); + this.end = end; } - public void setMobsFromMap(Map, Integer>> map) { - for (Entry, Integer>> entry : map.entrySet()) { - int id = entry.getKey(); - Entry, Integer> mobEntry = entry.getValue(); - mobs.put(id, mobEntry); - inv.setItem(id, createItemStack(mobEntry.getKey(), mobEntry.getValue())); - } + @Override + public void finish(List>> objects) { + end.accept(objects); } - + @Override - public boolean onClick(Player p, Inventory inv, ItemStack current, int slot, ClickType click){ - if (slot == 8){ - Inventories.closeAndExit(p); - run.accept(mobs); - return true; - } - Entry, Integer> mobEntry = mobs.get(slot); - if (mobEntry == null) { - new MobSelectionGUI(mob -> { - if (mob != null) { - inv.setItem(slot, createItemStack(mob, 1)); - mobs.put(slot, new AbstractMap.SimpleEntry<>(mob, 1)); - } - Inventories.put(p, openLastInv(p), MobsListGUI.this.inv); - }).create(p); - }else { - if (click == ClickType.SHIFT_LEFT) { - Lang.MOB_NAME.send(p); - new TextEditor<>(p, () -> openLastInv(p), name -> { - mobEntry.getKey().setCustomName((String) name); - inv.setItem(slot, createItemStack(mobEntry.getKey(), mobEntry.getValue())); - openLastInv(p); - }).passNullIntoEndConsumer().enter(); - }else if (click == ClickType.LEFT) { - Lang.MOB_AMOUNT.send(p); - new TextEditor<>(p, () -> openLastInv(p), amount -> { - mobEntry.setValue(amount); - inv.setItem(slot, createItemStack(mobEntry.getKey(), amount)); - openLastInv(p); - }, NumberParser.INTEGER_PARSER_STRICT_POSITIVE).enter(); - } else if (click == ClickType.SHIFT_RIGHT) { - if (mobEntry.getKey().getFactory() instanceof LeveledMobFactory) { - new TextEditor<>(p, () -> openLastInv(p), level -> { - mobEntry.getKey().setMinLevel(level); - inv.setItem(slot, createItemStack(mobEntry.getKey(), mobEntry.getValue())); - openLastInv(p); - }, new NumberParser<>(Double.class, true, false)).enter(); - } else { - Utils.playPluginSound(p.getLocation(), "ENTITY_VILLAGER_NO", 0.6f); - } - } else if (click == ClickType.RIGHT) { - mobs.remove(slot); - inv.setItem(slot, none.clone()); + public void clickObject(MutableCountableObject> mob, ItemStack item, ClickType click) { + super.clickObject(mob, item, click); + if (click == ClickType.SHIFT_LEFT) { + Lang.MOB_NAME.send(p); + new TextEditor<>(p, super::reopen, name -> { + mob.getObject().setCustomName((String) name); + setItems(); + reopen(); + }).passNullIntoEndConsumer().enter(); + } else if (click == ClickType.LEFT) { + Lang.MOB_AMOUNT.send(p); + new TextEditor<>(p, super::reopen, amount -> { + mob.setAmount(amount); + setItems(); + reopen(); + }, NumberParser.INTEGER_PARSER_STRICT_POSITIVE).enter(); + } else if (click == ClickType.SHIFT_RIGHT) { + if (mob.getObject().getFactory() instanceof LeveledMobFactory) { + new TextEditor<>(p, super::reopen, level -> { + mob.getObject().setMinLevel(level); + setItems(); + reopen(); + }, new NumberParser<>(Double.class, true, false)).enter(); + } else { + Utils.playPluginSound(p.getLocation(), "ENTITY_VILLAGER_NO", 0.6f); } + } else if (click == ClickType.RIGHT) { + remove(mob); } - return true; } - - private ItemStack createItemStack(Mob mob, int amount) { + + @Override + public void createObject(Function>, ItemStack> callback) { + new MobSelectionGUI(mob -> { + if (mob == null) + reopen(); + else + callback.apply(CountableObject.createMutable(UUID.randomUUID(), mob, 1)); + }).create(p); + } + + @Override + public ItemStack getObjectItemStack(MutableCountableObject> mob) { List lore = new ArrayList<>(); - lore.add(Lang.Amount.format(amount)); - lore.addAll(mob.getFactory().getDescriptiveLore(mob.getData())); + lore.add(Lang.Amount.format(mob.getAmount())); + lore.addAll(mob.getObject().getDescriptiveLore()); lore.add(""); lore.add(Lang.click.toString()); - if (mob.getFactory() instanceof LeveledMobFactory) { + if (mob.getObject().getFactory() instanceof LeveledMobFactory) { lore.add("§7" + Lang.ClickShiftRight + " > §e" + Lang.setLevel); } else { lore.add("§8§n" + Lang.ClickShiftRight + " > " + Lang.setLevel); } - ItemStack item = ItemUtils.item(mob.getMobItem(), mob.getName(), lore); - item.setAmount(Math.min(amount, 64)); + ItemStack item = ItemUtils.item(mob.getObject().getMobItem(), mob.getObject().getName(), lore); + item.setAmount(Math.min(mob.getAmount(), 64)); return item; } - @Override - public CloseBehavior onClose(Player p, Inventory inv) { - return CloseBehavior.REOPEN; - } - } \ No newline at end of file diff --git a/core/src/main/java/fr/skytasul/quests/gui/templates/ListGUI.java b/core/src/main/java/fr/skytasul/quests/gui/templates/ListGUI.java index 67703192..361781a9 100644 --- a/core/src/main/java/fr/skytasul/quests/gui/templates/ListGUI.java +++ b/core/src/main/java/fr/skytasul/quests/gui/templates/ListGUI.java @@ -3,14 +3,12 @@ import java.util.Collection; import java.util.List; import java.util.function.Function; - 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.Inventory; import org.bukkit.inventory.ItemStack; - import fr.skytasul.quests.gui.ItemUtils; import fr.skytasul.quests.utils.Lang; import fr.skytasul.quests.utils.XMaterial; @@ -27,6 +25,9 @@ public abstract class ListGUI extends PagedGUI { public ListGUI(String name, DyeColor color, Collection objects) { super(name, color, objects); + if (objects.contains(null)) + throw new IllegalArgumentException("Object cannot be null in a list GUI"); + super.objects.add(null); super.validate = list -> { list.remove(null); diff --git a/core/src/main/java/fr/skytasul/quests/gui/templates/PagedGUI.java b/core/src/main/java/fr/skytasul/quests/gui/templates/PagedGUI.java index 46029b92..548e19cd 100644 --- a/core/src/main/java/fr/skytasul/quests/gui/templates/PagedGUI.java +++ b/core/src/main/java/fr/skytasul/quests/gui/templates/PagedGUI.java @@ -5,15 +5,14 @@ import java.util.List; import java.util.function.Consumer; import java.util.function.Function; - import org.apache.commons.lang.Validate; import org.bukkit.Bukkit; import org.bukkit.DyeColor; +import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.inventory.ClickType; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; - import fr.skytasul.quests.editors.TextEditor; import fr.skytasul.quests.gui.CustomInventory; import fr.skytasul.quests.gui.Inventories; @@ -118,15 +117,30 @@ protected void setItems() { private int setMainItem(int mainSlot, ItemStack is){ int line = (int) Math.floor(mainSlot * 1.0 / 7.0); int slot = mainSlot + (2 * line); - inv.setItem(slot, is); + setItem(is, slot); return slot; } private int setBarItem(int barSlot, ItemStack is){ int slot = barSlot * 9 + 8; - inv.setItem(slot, is); + setItem(is, slot); return slot; } + + private void setItem(ItemStack is, int rawSlot) { + inv.setItem(rawSlot, is); + + if (is != null && is.getType() != Material.AIR) { + ItemStack invItem = inv.getItem(rawSlot); + if (invItem == null || invItem.getType() == Material.AIR) { + // means the item was a material that cannot be put in an inventory: + // fire, water block, crops... + is = is.clone(); + is.setType(Material.STONE); + inv.setItem(rawSlot, is); + } + } + } /** * @param object T object to get the slot from diff --git a/core/src/main/java/fr/skytasul/quests/stages/StageEatDrink.java b/core/src/main/java/fr/skytasul/quests/stages/StageEatDrink.java index 50a96201..01b4bab1 100644 --- a/core/src/main/java/fr/skytasul/quests/stages/StageEatDrink.java +++ b/core/src/main/java/fr/skytasul/quests/stages/StageEatDrink.java @@ -1,13 +1,10 @@ package fr.skytasul.quests.stages; -import java.util.Map; -import java.util.Map.Entry; - +import java.util.List; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.event.EventHandler; import org.bukkit.event.player.PlayerItemConsumeEvent; import org.bukkit.inventory.ItemStack; - import fr.skytasul.quests.api.comparison.ItemComparisonMap; import fr.skytasul.quests.api.stages.types.AbstractItemStage; import fr.skytasul.quests.gui.ItemUtils; @@ -18,10 +15,11 @@ import fr.skytasul.quests.structure.QuestBranch.Source; import fr.skytasul.quests.utils.Lang; import fr.skytasul.quests.utils.XMaterial; +import fr.skytasul.quests.utils.types.CountableObject; public class StageEatDrink extends AbstractItemStage { - public StageEatDrink(QuestBranch branch, Map> objects, ItemComparisonMap comparisons) { + public StageEatDrink(QuestBranch branch, List> objects, ItemComparisonMap comparisons) { super(branch, objects, comparisons); } @@ -53,8 +51,8 @@ protected ItemStack getEditItem() { } @Override - protected StageEatDrink finishStage(QuestBranch branch, Map> itemsMap, ItemComparisonMap comparisons) { - return new StageEatDrink(branch, itemsMap, comparisons); + protected StageEatDrink finishStage(QuestBranch branch, List> items, ItemComparisonMap comparisons) { + return new StageEatDrink(branch, items, comparisons); } } 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 35ea649f..37e585f8 100644 --- a/core/src/main/java/fr/skytasul/quests/stages/StageEnchant.java +++ b/core/src/main/java/fr/skytasul/quests/stages/StageEnchant.java @@ -1,15 +1,12 @@ package fr.skytasul.quests.stages; -import java.util.Map; -import java.util.Map.Entry; - +import java.util.List; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.enchantment.EnchantItemEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; - import fr.skytasul.quests.api.comparison.ItemComparisonMap; import fr.skytasul.quests.api.stages.types.AbstractItemStage; import fr.skytasul.quests.gui.ItemUtils; @@ -20,10 +17,11 @@ import fr.skytasul.quests.structure.QuestBranch.Source; import fr.skytasul.quests.utils.Lang; import fr.skytasul.quests.utils.XMaterial; +import fr.skytasul.quests.utils.types.CountableObject; public class StageEnchant extends AbstractItemStage { - public StageEnchant(QuestBranch branch, Map> fishes, ItemComparisonMap comparisons) { + public StageEnchant(QuestBranch branch, List> fishes, ItemComparisonMap comparisons) { super(branch, fishes, comparisons); } @@ -67,8 +65,8 @@ protected ItemStack getEditItem() { } @Override - protected StageEnchant finishStage(QuestBranch branch, Map> itemsMap, ItemComparisonMap comparisons) { - return new StageEnchant(branch, itemsMap, comparisons); + protected StageEnchant finishStage(QuestBranch branch, List> items, ItemComparisonMap comparisons) { + return new StageEnchant(branch, items, comparisons); } } 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 326772b5..e8f63b98 100644 --- a/core/src/main/java/fr/skytasul/quests/stages/StageFish.java +++ b/core/src/main/java/fr/skytasul/quests/stages/StageFish.java @@ -1,8 +1,6 @@ package fr.skytasul.quests.stages; -import java.util.Map; -import java.util.Map.Entry; - +import java.util.List; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Item; import org.bukkit.entity.Player; @@ -11,7 +9,6 @@ import org.bukkit.event.player.PlayerFishEvent; import org.bukkit.event.player.PlayerFishEvent.State; import org.bukkit.inventory.ItemStack; - import fr.skytasul.quests.api.comparison.ItemComparisonMap; import fr.skytasul.quests.api.stages.types.AbstractItemStage; import fr.skytasul.quests.gui.ItemUtils; @@ -22,10 +19,11 @@ import fr.skytasul.quests.structure.QuestBranch.Source; import fr.skytasul.quests.utils.Lang; import fr.skytasul.quests.utils.XMaterial; +import fr.skytasul.quests.utils.types.CountableObject; public class StageFish extends AbstractItemStage { - public StageFish(QuestBranch branch, Map> fishes, ItemComparisonMap comparisons) { + public StageFish(QuestBranch branch, List> fishes, ItemComparisonMap comparisons) { super(branch, fishes, comparisons); } @@ -68,8 +66,8 @@ protected ItemStack getEditItem() { } @Override - protected StageFish finishStage(QuestBranch branch, Map> itemsMap, ItemComparisonMap comparisons) { - return new StageFish(branch, itemsMap, comparisons); + protected StageFish finishStage(QuestBranch branch, List> items, ItemComparisonMap comparisons) { + return new StageFish(branch, items, comparisons); } } diff --git a/core/src/main/java/fr/skytasul/quests/stages/StageMelt.java b/core/src/main/java/fr/skytasul/quests/stages/StageMelt.java index 1d677674..ef111daf 100644 --- a/core/src/main/java/fr/skytasul/quests/stages/StageMelt.java +++ b/core/src/main/java/fr/skytasul/quests/stages/StageMelt.java @@ -1,14 +1,11 @@ package fr.skytasul.quests.stages; -import java.util.Map; -import java.util.Map.Entry; - +import java.util.List; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.inventory.FurnaceExtractEvent; import org.bukkit.inventory.ItemStack; - import fr.skytasul.quests.api.comparison.ItemComparisonMap; import fr.skytasul.quests.api.stages.types.AbstractItemStage; import fr.skytasul.quests.gui.ItemUtils; @@ -19,10 +16,11 @@ import fr.skytasul.quests.structure.QuestBranch.Source; import fr.skytasul.quests.utils.Lang; import fr.skytasul.quests.utils.XMaterial; +import fr.skytasul.quests.utils.types.CountableObject; public class StageMelt extends AbstractItemStage { - public StageMelt(QuestBranch branch, Map> items, ItemComparisonMap comparisons) { + public StageMelt(QuestBranch branch, List> items, ItemComparisonMap comparisons) { super(branch, items, comparisons); } @@ -58,8 +56,8 @@ protected ItemStack getEditItem() { } @Override - protected StageMelt finishStage(QuestBranch branch, Map> itemsMap, ItemComparisonMap comparisons) { - return new StageMelt(branch, itemsMap, comparisons); + protected StageMelt finishStage(QuestBranch branch, List> items, ItemComparisonMap comparisons) { + return new StageMelt(branch, items, comparisons); } } diff --git a/core/src/main/java/fr/skytasul/quests/stages/StageMine.java b/core/src/main/java/fr/skytasul/quests/stages/StageMine.java index 75267c75..4a7a81e4 100644 --- a/core/src/main/java/fr/skytasul/quests/stages/StageMine.java +++ b/core/src/main/java/fr/skytasul/quests/stages/StageMine.java @@ -1,9 +1,11 @@ package fr.skytasul.quests.stages; -import java.util.HashMap; +import java.util.ArrayList; +import java.util.List; import java.util.Map; -import java.util.Map.Entry; +import java.util.Optional; import java.util.Spliterator; +import java.util.UUID; import java.util.stream.Collectors; import org.bukkit.block.Block; import org.bukkit.configuration.ConfigurationSection; @@ -30,13 +32,14 @@ import fr.skytasul.quests.utils.Lang; import fr.skytasul.quests.utils.XMaterial; import fr.skytasul.quests.utils.types.BQBlock; +import fr.skytasul.quests.utils.types.CountableObject; @LocatableType (types = LocatedType.BLOCK) public class StageMine extends AbstractCountableBlockStage implements Locatable.MultipleLocatable { private boolean placeCancelled; - public StageMine(QuestBranch branch, Map> blocks) { + public StageMine(QuestBranch branch, List> blocks) { super(branch, blocks); } @@ -83,10 +86,13 @@ public void onPlace(BlockPlaceEvent e){ Player p = e.getPlayer(); PlayerAccount acc = PlayersManager.getPlayerAccount(p); if (!branch.hasStageLaunched(acc, this)) return; - Map playerBlocks = getPlayerRemainings(acc, true); + + Map playerBlocks = getPlayerRemainings(acc, true); if (playerBlocks == null) return; - for (Integer id : playerBlocks.keySet()) { - if (objectApplies(super.objects.get(id).getKey(), e.getBlock())) { + for (UUID id : playerBlocks.keySet()) { + Optional> object = getObject(id); + if (object.isPresent() && objectApplies(object.get().getObject(), e.getBlock())) { + // we cannot use Optional#ifPresent(...) as we must stop the loop e.getBlock().setMetadata("playerInStage", new FixedMetadataValue(BeautyQuests.getInstance(), p.getName())); return; } @@ -95,7 +101,8 @@ public void onPlace(BlockPlaceEvent e){ @Override public Spliterator getNearbyLocated(NearbyFetcher fetcher) { - return BQBlock.getNearbyBlocks(fetcher, objects.values().stream().map(Entry::getKey).collect(Collectors.toList())); + return BQBlock.getNearbyBlocks(fetcher, + objects.stream().map(CountableObject::getObject).collect(Collectors.toList())); } @Override @@ -105,7 +112,7 @@ protected void serialize(ConfigurationSection section) { } public static StageMine deserialize(ConfigurationSection section, QuestBranch branch) { - StageMine stage = new StageMine(branch, new HashMap<>()); + StageMine stage = new StageMine(branch, new ArrayList<>()); stage.deserialize(section); if (section.contains("placeCancelled")) stage.placeCancelled = section.getBoolean("placeCancelled"); @@ -142,7 +149,7 @@ public void edit(StageMine stage) { @Override public StageMine finishStage(QuestBranch branch) { - StageMine stage = new StageMine(branch, blocks); + StageMine stage = new StageMine(branch, getImmutableBlocks()); stage.setPlaceCancelled(prevent); return stage; } 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 14931075..819fe2b2 100644 --- a/core/src/main/java/fr/skytasul/quests/stages/StageMobs.java +++ b/core/src/main/java/fr/skytasul/quests/stages/StageMobs.java @@ -1,13 +1,16 @@ package fr.skytasul.quests.stages; import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; -import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import java.util.Spliterator; import java.util.Spliterators; +import java.util.stream.Collectors; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; @@ -19,7 +22,6 @@ import fr.skytasul.quests.api.stages.types.Locatable; import fr.skytasul.quests.api.stages.types.Locatable.LocatableType; import fr.skytasul.quests.api.stages.types.Locatable.LocatedType; -import fr.skytasul.quests.gui.Inventories; import fr.skytasul.quests.gui.ItemUtils; import fr.skytasul.quests.gui.creation.stages.Line; import fr.skytasul.quests.gui.mobs.MobsListGUI; @@ -30,13 +32,15 @@ import fr.skytasul.quests.utils.Lang; import fr.skytasul.quests.utils.XMaterial; import fr.skytasul.quests.utils.compatibility.mobs.CompatMobDeathEvent; +import fr.skytasul.quests.utils.types.CountableObject; +import fr.skytasul.quests.utils.types.CountableObject.MutableCountableObject; @LocatableType (types = LocatedType.ENTITY) public class StageMobs extends AbstractCountableStage> implements Locatable.MultipleLocatable { private boolean shoot = false; - public StageMobs(QuestBranch branch, Map, Integer>> mobs) { + public StageMobs(QuestBranch branch, List>> mobs) { super(branch, mobs); } @@ -124,7 +128,7 @@ public Spliterator getNearbyLocated(NearbyFetcher fetcher) { return fetcher.getCenter().getWorld() .getEntities() .stream() - .filter(entity -> objects.values().stream().anyMatch(entry -> entry.getKey().appliesEntity(entity))) + .filter(entity -> objects.stream().anyMatch(entry -> entry.getObject().appliesEntity(entity))) .map(x -> { double ds = x.getLocation().distanceSquared(fetcher.getCenter()); if (ds > fetcher.getMaxDistanceSquared()) return null; @@ -137,7 +141,7 @@ public Spliterator getNearbyLocated(NearbyFetcher fetcher) { } public static StageMobs deserialize(ConfigurationSection section, QuestBranch branch) { - StageMobs stage = new StageMobs(branch, new HashMap<>()); + StageMobs stage = new StageMobs(branch, new ArrayList<>()); stage.deserialize(section); if (section.contains("shoot")) stage.shoot = section.getBoolean("shoot"); @@ -146,24 +150,22 @@ public static StageMobs deserialize(ConfigurationSection section, QuestBranch br public static class Creator extends StageCreation { - private Map, Integer>> mobs; + private List>> mobs; private boolean shoot = false; public Creator(Line line, boolean ending) { super(line, ending); line.setItem(7, ItemUtils.item(XMaterial.STONE_SWORD, Lang.editMobs.toString()), (p, item) -> { - MobsListGUI mobsGUI = Inventories.create(p, new MobsListGUI()); - mobsGUI.setMobsFromMap(mobs); - mobsGUI.run = (obj) -> { - mobs = obj; + new MobsListGUI(mobs, newMobs -> { + setMobs(newMobs); reopenGUI(p, true); - }; + }).create(p); }); line.setItem(6, ItemUtils.itemSwitch(Lang.mobsKillType.toString(), shoot), (p, item) -> setShoot(ItemUtils.toggle(item))); } - public void setMobs(Map, Integer>> mobs) { + public void setMobs(List>> mobs) { this.mobs = mobs; line.editItem(7, ItemUtils.lore(line.getItem(7), Lang.optionValue.format(Lang.AmountMobs.format(mobs.size())))); } @@ -178,16 +180,16 @@ public void setShoot(boolean shoot) { @Override public void start(Player p) { super.start(p); - MobsListGUI mobsGUI = Inventories.create(p, new MobsListGUI()); - mobsGUI.run = (obj) -> { - setMobs(obj); + new MobsListGUI(Collections.emptyList(), newMobs -> { + setMobs(newMobs); reopenGUI(p, true); - }; + }).create(p); } @Override public StageMobs finishStage(QuestBranch branch) { - StageMobs stage = new StageMobs(branch, mobs); + StageMobs stage = new StageMobs(branch, + mobs.stream().map(MutableCountableObject::toImmutable).collect(Collectors.toList())); stage.setShoot(shoot); return stage; } @@ -195,7 +197,7 @@ public StageMobs finishStage(QuestBranch branch) { @Override public void edit(StageMobs stage) { super.edit(stage); - setMobs(stage.cloneObjects()); + setMobs(stage.getMutableObjects()); setShoot(stage.shoot); } } 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 c47130d3..1ca748dc 100644 --- a/core/src/main/java/fr/skytasul/quests/stages/StagePlaceBlocks.java +++ b/core/src/main/java/fr/skytasul/quests/stages/StagePlaceBlocks.java @@ -1,16 +1,13 @@ package fr.skytasul.quests.stages; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; - +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.block.BlockPlaceEvent; import org.bukkit.inventory.ItemStack; - import fr.skytasul.quests.api.stages.types.AbstractCountableBlockStage; import fr.skytasul.quests.gui.ItemUtils; import fr.skytasul.quests.gui.creation.stages.Line; @@ -21,10 +18,11 @@ import fr.skytasul.quests.utils.Lang; import fr.skytasul.quests.utils.XMaterial; import fr.skytasul.quests.utils.types.BQBlock; +import fr.skytasul.quests.utils.types.CountableObject; public class StagePlaceBlocks extends AbstractCountableBlockStage { - public StagePlaceBlocks(QuestBranch branch, Map> blocks) { + public StagePlaceBlocks(QuestBranch branch, List> blocks) { super(branch, blocks); } @@ -44,7 +42,7 @@ public void onPlace(BlockPlaceEvent e) { } public static StagePlaceBlocks deserialize(ConfigurationSection section, QuestBranch branch) { - StagePlaceBlocks stage = new StagePlaceBlocks(branch, new HashMap<>()); + StagePlaceBlocks stage = new StagePlaceBlocks(branch, new ArrayList<>()); stage.deserialize(section); return stage; } @@ -62,7 +60,7 @@ protected ItemStack getBlocksItem() { @Override public StagePlaceBlocks finishStage(QuestBranch branch) { - return new StagePlaceBlocks(branch, blocks); + return new StagePlaceBlocks(branch, getImmutableBlocks()); } } diff --git a/core/src/main/java/fr/skytasul/quests/utils/Lang.java b/core/src/main/java/fr/skytasul/quests/utils/Lang.java index 002cd9d7..0b886961 100644 --- a/core/src/main/java/fr/skytasul/quests/utils/Lang.java +++ b/core/src/main/java/fr/skytasul/quests/utils/Lang.java @@ -526,7 +526,6 @@ public enum Lang implements Locale { questMenuLore("inv.chooseQuest.menuLore"), INVENTORY_MOBS("inv.mobs.name"), - mobsNone("inv.mobs.none"), click("inv.mobs.clickLore"), setLevel("inv.mobs.setLevel"), @@ -597,7 +596,6 @@ public enum Lang implements Locale { blockTagLore("inv.block.blockTagLore"), INVENTORY_BLOCKSLIST("inv.blocksList.name"), - addBlock("inv.blocksList.addBlock"), INVENTORY_BLOCK_ACTION("inv.blockAction.name"), clickLocation("inv.blockAction.location"), diff --git a/core/src/main/java/fr/skytasul/quests/utils/Utils.java b/core/src/main/java/fr/skytasul/quests/utils/Utils.java index 8d6db611..eb7ca6dc 100644 --- a/core/src/main/java/fr/skytasul/quests/utils/Utils.java +++ b/core/src/main/java/fr/skytasul/quests/utils/Utils.java @@ -163,7 +163,12 @@ public static String getStringFromItemStack(ItemStack is, String amountColor, bo public static String getStringFromNameAndAmount(String name, String amountColor, int remaining, int total, boolean showXOne) { int done = total - remaining; int percentage = (int) (done / (double) total * 100); - return name + ((remaining > 1 || showXOne) ? "§r" + amountColor + " " + Utils.format(QuestsConfiguration.getDescriptionAmountFormat(), remaining, done, percentage) : ""); + String string = name; + if (remaining > 1 || showXOne) { + string += "§r" + amountColor + " " + + Utils.format(QuestsConfiguration.getDescriptionAmountFormat(), remaining, done, total, percentage); + } + return string; } public static void sendMessage(CommandSender sender, String msg, Object... replace){ diff --git a/core/src/main/java/fr/skytasul/quests/utils/types/CountableObject.java b/core/src/main/java/fr/skytasul/quests/utils/types/CountableObject.java new file mode 100644 index 00000000..c0fe101b --- /dev/null +++ b/core/src/main/java/fr/skytasul/quests/utils/types/CountableObject.java @@ -0,0 +1,105 @@ +package fr.skytasul.quests.utils.types; + +import java.util.UUID; + +public interface CountableObject { + + UUID getUUID(); + + T getObject(); + + int getAmount(); + + default MutableCountableObject toMutable() { + return createMutable(getUUID(), getObject(), getAmount()); + } + + public interface MutableCountableObject extends CountableObject { + + void setObject(T object); + + void setAmount(int newAmount); + + default CountableObject toImmutable() { + return create(getUUID(), getObject(), getAmount()); + } + + } + + static CountableObject create(UUID uuid, T object, int amount) { + return new DummyCountableObject<>(uuid, object, amount); + } + + static MutableCountableObject createMutable(UUID uuid, T object, int amount) { + return new DummyMutableCountableObject<>(uuid, object, amount); + } + + class DummyCountableObject implements CountableObject { + + private final UUID uuid; + private final T object; + private final int amount; + + public DummyCountableObject(UUID uuid, T object, int amount) { + this.uuid = uuid; + this.object = object; + this.amount = amount; + } + + @Override + public UUID getUUID() { + return uuid; + } + + @Override + public T getObject() { + return object; + } + + @Override + public int getAmount() { + return amount; + } + + } + + class DummyMutableCountableObject implements MutableCountableObject { + + private final UUID uuid; + private T object; + private int amount; + + public DummyMutableCountableObject(UUID uuid, T object, int amount) { + this.uuid = uuid; + this.object = object; + this.amount = amount; + } + + @Override + public UUID getUUID() { + return uuid; + } + + @Override + public T getObject() { + return object; + } + + @Override + public void setObject(T object) { + this.object = object; + } + + @Override + public int getAmount() { + return amount; + } + + @Override + public void setAmount(int amount) { + this.amount = amount; + } + + } + +} From faa8b14cd2c70522c78baf74a3a1910ff5817d41 Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Fri, 27 Jan 2023 19:16:08 +0100 Subject: [PATCH 20/41] :bug: Fixed equipment requirement not checking item amount --- .../skytasul/quests/requirements/EquipmentRequirement.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/fr/skytasul/quests/requirements/EquipmentRequirement.java b/core/src/main/java/fr/skytasul/quests/requirements/EquipmentRequirement.java index d6ea7c5b..8887b304 100644 --- a/core/src/main/java/fr/skytasul/quests/requirements/EquipmentRequirement.java +++ b/core/src/main/java/fr/skytasul/quests/requirements/EquipmentRequirement.java @@ -2,15 +2,12 @@ import java.util.Map; import java.util.function.Consumer; - import org.bukkit.DyeColor; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; - import com.google.common.collect.ImmutableMap; - import fr.skytasul.quests.api.comparison.ItemComparisonMap; import fr.skytasul.quests.api.objects.QuestObjectClickEvent; import fr.skytasul.quests.api.options.QuestOption; @@ -38,7 +35,8 @@ public EquipmentRequirement(EquipmentSlot slot, ItemStack item, ItemComparisonMa @Override public boolean test(Player p) { - return comparisons.isSimilar(p.getInventory().getItem(slot), item); + ItemStack playerItem = p.getInventory().getItem(slot); + return comparisons.isSimilar(playerItem, item) && playerItem.getAmount() >= item.getAmount(); } @Override From 7b38bb23d3c642ebfe3ea475b0415020bdc3b9b7 Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Wed, 1 Feb 2023 15:04:22 +0100 Subject: [PATCH 21/41] :technologist: Added "hasPriority" parameter for item comparisons --- .../fr/skytasul/quests/api/QuestsAPI.java | 8 ++- .../quests/api/comparison/ItemComparison.java | 12 ++++- .../api/comparison/ItemComparisonMap.java | 53 ++++++++++++++----- 3 files changed, 58 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/fr/skytasul/quests/api/QuestsAPI.java b/core/src/main/java/fr/skytasul/quests/api/QuestsAPI.java index ae98ada1..4569a289 100644 --- a/core/src/main/java/fr/skytasul/quests/api/QuestsAPI.java +++ b/core/src/main/java/fr/skytasul/quests/api/QuestsAPI.java @@ -86,10 +86,16 @@ public static List getItemComparisons() { } public static void registerItemComparison(ItemComparison comparison) { - Validate.isTrue(itemComparisons.stream().noneMatch(x -> x.getID().equals(comparison.getID())), "This item comparison was already registerd"); + Validate.isTrue(itemComparisons.stream().noneMatch(x -> x.getID().equals(comparison.getID())), + "This item comparison was already registered"); itemComparisons.add(comparison); DebugUtils.logMessage("Item comparison registered (id: " + comparison.getID() + ")"); } + + public static void unregisterItemComparison(ItemComparison comparison) { + Validate.isTrue(itemComparisons.remove(comparison), "This item comparison was not registered"); + DebugUtils.logMessage("Item comparison unregistered (id: " + comparison.getID() + ")"); + } public static List getMobStackers() { return mobStackers; diff --git a/core/src/main/java/fr/skytasul/quests/api/comparison/ItemComparison.java b/core/src/main/java/fr/skytasul/quests/api/comparison/ItemComparison.java index 15a2a404..d449855c 100644 --- a/core/src/main/java/fr/skytasul/quests/api/comparison/ItemComparison.java +++ b/core/src/main/java/fr/skytasul/quests/api/comparison/ItemComparison.java @@ -1,14 +1,13 @@ package fr.skytasul.quests.api.comparison; import java.util.function.BiPredicate; - import org.bukkit.inventory.ItemStack; public class ItemComparison { private final String id, itemName, itemDescription; private final BiPredicate comparator; - private boolean enabledByDefault, needsMeta; + private boolean enabledByDefault, needsMeta, hasPriority; public ItemComparison(String id, String itemName, String itemDescription, BiPredicate comparator) { this.id = id; @@ -47,6 +46,15 @@ public boolean isMetaNeeded() { return needsMeta; } + public ItemComparison setHasPriority() { + this.hasPriority = true; + return this; + } + + public boolean hasPriority() { + return hasPriority; + } + /** * This must not check the amount of the item. The function call must not affect the item in any way. */ diff --git a/core/src/main/java/fr/skytasul/quests/api/comparison/ItemComparisonMap.java b/core/src/main/java/fr/skytasul/quests/api/comparison/ItemComparisonMap.java index 15394563..2f36721c 100644 --- a/core/src/main/java/fr/skytasul/quests/api/comparison/ItemComparisonMap.java +++ b/core/src/main/java/fr/skytasul/quests/api/comparison/ItemComparisonMap.java @@ -1,15 +1,15 @@ package fr.skytasul.quests.api.comparison; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; - import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; - import fr.skytasul.quests.api.QuestsAPI; public class ItemComparisonMap implements Cloneable { @@ -32,22 +32,25 @@ public ItemComparisonMap(Map notDefault) { public void setNotDefaultComparisons(ConfigurationSection section) { this.notDefault = (Map) section.getValues(false); - effective = new ArrayList<>(); + effective = new ArrayList<>(3); for (ItemComparison comp : QuestsAPI.getItemComparisons()) { - if (section.getBoolean(comp.getID(), comp.isEnabledByDefault())) effective.add(comp); + if (section.getBoolean(comp.getID(), comp.isEnabledByDefault())) + effective.add(comp); } + updated(); } public void setNotDefaultComparisons(Map comparisons) { this.notDefault = comparisons; - - effective = new ArrayList<>(); + + effective = new ArrayList<>(3); for (ItemComparison comp : QuestsAPI.getItemComparisons()) { Boolean bool = notDefault.get(comp.getID()); if (Boolean.FALSE.equals(bool)) continue; if (!comp.isEnabledByDefault() && !Boolean.TRUE.equals(bool)) continue; effective.add(comp); } + updated(); } public Map getNotDefault() { @@ -79,6 +82,7 @@ public boolean toggle(ItemComparison comparison) { } if (bool) { effective.add(comparison); + updated(); return true; }else { effective.remove(comparison); @@ -86,16 +90,41 @@ public boolean toggle(ItemComparison comparison) { } } + private void updated() { + Collections.sort(effective, Comparator.comparing(ItemComparison::hasPriority)); + } + public boolean isSimilar(ItemStack item1, ItemStack item2) { boolean meta1 = item1.hasItemMeta(); boolean meta2 = item2.hasItemMeta(); - return effective.stream().allMatch(x -> { - if (x.isMetaNeeded()) { - if (meta1 != meta2) return false; - if (!meta1) return true; + + boolean lastResult = true; + for (ItemComparison comparison : effective) { + if (!comparison.hasPriority() && !lastResult) { + // comparisons with priority are tested at the very beginning + // if this comparison does not has priority and the last result is false then there is no need to go + // further: we can stop there + return false; } - return x.isSimilar(item1, item2); - }); + + Boolean result = null; + + if (comparison.isMetaNeeded()) { + if (meta1 != meta2) continue; + if (!meta1) result = true; + } + + if (result == null) result = comparison.isSimilar(item1, item2); + + if (result && comparison.hasPriority()) { + // if the comparison has priority and matches those items then we can stop there + return true; + } + + lastResult = result; + } + + return lastResult; } public boolean containsItems(Inventory inv, ItemStack i, int amount) { From 4489e9c27058682add8a5dcc862cf62ce1f3e177 Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Wed, 1 Feb 2023 15:04:58 +0100 Subject: [PATCH 22/41] :heavy_plus_sign: Added ItemsAdder item comparison --- core/pom.xml | 6 +++ .../java/fr/skytasul/quests/utils/Lang.java | 2 + .../utils/compatibility/BQItemsAdder.java | 37 +++++++++++++++++++ .../compatibility/DependenciesManager.java | 20 ++++++++-- .../worldguard/BQWorldGuard.java | 11 ++++-- core/src/main/resources/locales/en_US.yml | 2 + core/src/main/resources/plugin.yml | 1 + 7 files changed, 72 insertions(+), 7 deletions(-) create mode 100644 core/src/main/java/fr/skytasul/quests/utils/compatibility/BQItemsAdder.java diff --git a/core/pom.xml b/core/pom.xml index 4024c16e..ba21a8ae 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -295,6 +295,12 @@ 2022.6 provided + + com.github.LoneDev6 + api-itemsadder + 3.2.5 + provided + com.github.Revxrsal.Lamp bukkit diff --git a/core/src/main/java/fr/skytasul/quests/utils/Lang.java b/core/src/main/java/fr/skytasul/quests/utils/Lang.java index 0b886961..624cd4b9 100644 --- a/core/src/main/java/fr/skytasul/quests/utils/Lang.java +++ b/core/src/main/java/fr/skytasul/quests/utils/Lang.java @@ -661,6 +661,8 @@ public enum Lang implements Locale { comparisonEnchantsLore("inv.itemComparisons.enchantsLore"), comparisonRepairCost("inv.itemComparisons.repairCost"), comparisonRepairCostLore("inv.itemComparisons.repairCostLore"), + comparisonItemsAdder("inv.itemComparisons.itemsAdder"), + comparisonItemsAdderLore("inv.itemComparisons.itemsAdderLore"), INVENTORY_EDIT_TITLE("inv.editTitle.name"), title_title("inv.editTitle.title"), diff --git a/core/src/main/java/fr/skytasul/quests/utils/compatibility/BQItemsAdder.java b/core/src/main/java/fr/skytasul/quests/utils/compatibility/BQItemsAdder.java new file mode 100644 index 00000000..59ba929f --- /dev/null +++ b/core/src/main/java/fr/skytasul/quests/utils/compatibility/BQItemsAdder.java @@ -0,0 +1,37 @@ +package fr.skytasul.quests.utils.compatibility; + +import org.bukkit.inventory.ItemStack; +import fr.skytasul.quests.api.QuestsAPI; +import fr.skytasul.quests.api.comparison.ItemComparison; +import fr.skytasul.quests.utils.Lang; +import dev.lone.itemsadder.api.CustomStack; + +public final class BQItemsAdder { + + private BQItemsAdder() {} + + private static final ItemComparison COMPARISON = new ItemComparison("items_adder", Lang.comparisonItemsAdder.toString(), + Lang.comparisonItemsAdderLore.toString(), BQItemsAdder::compareItems).setHasPriority(); + + public static void initialize() { + QuestsAPI.registerItemComparison(COMPARISON); + } + + public static void unload() { + QuestsAPI.unregisterItemComparison(COMPARISON); + } + + public static boolean compareItems(ItemStack item1, ItemStack item2) { + CustomStack custom1 = CustomStack.byItemStack(item1); + CustomStack custom2 = CustomStack.byItemStack(item2); + + if ((custom1 == null) != (custom2 == null)) + return false; // tests if 1 item is null and the other is not null => not the same items + + if (custom1 == null) + return true; // means both items are null => same items + + return custom1.matchNamespacedID(custom2); + } + +} diff --git a/core/src/main/java/fr/skytasul/quests/utils/compatibility/DependenciesManager.java b/core/src/main/java/fr/skytasul/quests/utils/compatibility/DependenciesManager.java index 8a09e4a3..57e2be56 100644 --- a/core/src/main/java/fr/skytasul/quests/utils/compatibility/DependenciesManager.java +++ b/core/src/main/java/fr/skytasul/quests/utils/compatibility/DependenciesManager.java @@ -45,7 +45,9 @@ public class DependenciesManager implements Listener { public static final BQDependency znpcs = new BQDependency("ServersNPC", () -> QuestsAPI.setNPCsManager(new BQServerNPCs()), null, plugin -> { - if (plugin.getClass().getName().equals("io.github.znetworkw.znpcservers.ServersNPC")) return true; + if (plugin.getClass().getName().equals("io.github.znetworkw.znpcservers.ServersNPC")) // NOSONAR + return true; + BeautyQuests.logger.warning("Your version of znpcs (" + plugin.getDescription().getVersion() + ") is not supported by BeautyQuests."); return false; }); @@ -100,7 +102,9 @@ public class DependenciesManager implements Listener { public static final BQDependency holod2 = new BQDependency("HolographicDisplays", () -> QuestsAPI.setHologramsManager(new BQHolographicDisplays2()), null, plugin -> plugin.getClass().getName().equals("com.gmail.filoghost.holographicdisplays.HolographicDisplays")); public static final BQDependency holod3 = new BQDependency("HolographicDisplays", () -> QuestsAPI.setHologramsManager(new BQHolographicDisplays3()), null, plugin -> { - if (!plugin.getClass().getName().equals("me.filoghost.holographicdisplays.plugin.HolographicDisplays")) return false; + if (!plugin.getClass().getName().equals("me.filoghost.holographicdisplays.plugin.HolographicDisplays")) // NOSONAR + return false; + try { Class.forName("me.filoghost.holographicdisplays.api.HolographicDisplaysAPI"); return true; @@ -113,7 +117,8 @@ public class DependenciesManager implements Listener { public static final BQDependency sentinel = new BQDependency("Sentinel", BQSentinel::initialize); - public static final BQDependency wg = new BQDependency("WorldGuard", BQWorldGuard::init, () -> BQWorldGuard.getInstance().disable(), null); + public static final BQDependency wg = + new BQDependency("WorldGuard", BQWorldGuard::initialize, BQWorldGuard::unload); public static final BQDependency jobs = new BQDependency("Jobs", () -> QuestsAPI.getRequirements().register(new RequirementCreator("jobLevelRequired", JobLevelRequirement.class, ItemUtils.item(XMaterial.LEATHER_CHESTPLATE, Lang.RJobLvl.toString()), JobLevelRequirement::new))); public static final BQDependency fac = new BQDependency("Factions", () -> QuestsAPI.getRequirements().register(new RequirementCreator("factionRequired", FactionRequirement.class, ItemUtils.item(XMaterial.WITHER_SKELETON_SKULL, Lang.RFaction.toString()), FactionRequirement::new))); public static final BQDependency acc = new BQDependency("AccountsHook"); @@ -126,6 +131,8 @@ public class DependenciesManager implements Listener { public static final BQDependency ultimateTimber = new BQDependency("UltimateTimber", () -> Bukkit.getPluginManager().registerEvents(new BQUltimateTimber(), BeautyQuests.getInstance())); public static final BQDependency PlayerBlockTracker = new BQDependency("PlayerBlockTracker"); public static final BQDependency WildStacker = new BQDependency("WildStacker", BQWildStacker::initialize); + public static final BQDependency ItemsAdder = + new BQDependency("ItemsAdder", BQItemsAdder::initialize, BQItemsAdder::unload); //public static final BQDependency par = new BQDependency("Parties"); //public static final BQDependency eboss = new BQDependency("EpicBosses", () -> Bukkit.getPluginManager().registerEvents(new EpicBosses(), BeautyQuests.getInstance())); @@ -145,7 +152,8 @@ public DependenciesManager() { vault, papi, acc, // hooks skapi, jobs, fac, mmo, mclvl, // rewards and requirements dyn, BlueMap, // maps - cmi, holod2, holod3, decentholograms // holograms + cmi, holod2, holod3, decentholograms, // holograms + ItemsAdder // items )); } @@ -211,6 +219,10 @@ public BQDependency(String pluginName, Runnable initialize) { this(pluginName, initialize, null, null); } + public BQDependency(String pluginName, Runnable initialize, Runnable disable) { + this(pluginName, initialize, disable, null); + } + public BQDependency(String pluginName, Runnable initialize, Runnable disable, Predicate isValid) { Validate.notNull(pluginName); this.pluginNames = new ArrayList<>(); diff --git a/core/src/main/java/fr/skytasul/quests/utils/compatibility/worldguard/BQWorldGuard.java b/core/src/main/java/fr/skytasul/quests/utils/compatibility/worldguard/BQWorldGuard.java index d6ec34e8..dce77991 100644 --- a/core/src/main/java/fr/skytasul/quests/utils/compatibility/worldguard/BQWorldGuard.java +++ b/core/src/main/java/fr/skytasul/quests/utils/compatibility/worldguard/BQWorldGuard.java @@ -64,7 +64,7 @@ protected BQWorldGuard() { } } - public void disable() { + private void disable() { if (handleEntry) { handleEntry = false; WorldGuardEntryHandler.FACTORY.unregister(com.sk89q.worldguard.WorldGuard.getInstance().getPlatform().getSessionManager()); @@ -114,14 +114,19 @@ public ProtectedRegion getRegion(String name, World w) { return getRegionManager(w).getRegion(name); } - public static void init() { + public static void initialize() { Validate.isTrue(instance == null, "BQ WorldGuard integration already initialized."); instance = new BQWorldGuard(); - QuestsAPI.registerStage(new StageType<>("REGION", StageArea.class, Lang.Find.name(), StageArea::deserialize, ItemUtils.item(XMaterial.WOODEN_AXE, Lang.stageGoTo.toString()), StageArea.Creator::new)); + QuestsAPI.getStages().register(new StageType<>("REGION", StageArea.class, Lang.Find.name(), StageArea::deserialize, + ItemUtils.item(XMaterial.WOODEN_AXE, Lang.stageGoTo.toString()), StageArea.Creator::new)); QuestsAPI.getRequirements().register(new RequirementCreator("regionRequired", RegionRequirement.class, ItemUtils.item(XMaterial.WOODEN_AXE, Lang.RRegion.toString()), RegionRequirement::new)); } + public static void unload() { + instance.disable(); + } + public static BQWorldGuard getInstance() { return instance; } diff --git a/core/src/main/resources/locales/en_US.yml b/core/src/main/resources/locales/en_US.yml index 28516b74..eedb7e2a 100644 --- a/core/src/main/resources/locales/en_US.yml +++ b/core/src/main/resources/locales/en_US.yml @@ -702,6 +702,8 @@ inv: enchantsLore: Compares items enchants repairCost: Repair cost repairCostLore: Compares repair cost for armors and swords + itemsAdder: ItemsAdder + itemsAdderLore: Compares ItemsAdder IDs editTitle: name: Edit Title title: §6Title diff --git a/core/src/main/resources/plugin.yml b/core/src/main/resources/plugin.yml index 82bce6ab..4d14b193 100644 --- a/core/src/main/resources/plugin.yml +++ b/core/src/main/resources/plugin.yml @@ -36,6 +36,7 @@ softdepend: - PlayerBlockTracker - LevelledMobs - WildStacker +- ItemsAdder #commands: # beautyquests: From 71f59163150b65830dbf946a168d689fab464eba Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Thu, 2 Feb 2023 11:06:04 +0100 Subject: [PATCH 23/41] :children_crossing: Added "none" keyword to the "asking message" editor --- .../src/main/java/fr/skytasul/quests/stages/StageBringBack.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 36590fac..90556af6 100644 --- a/core/src/main/java/fr/skytasul/quests/stages/StageBringBack.java +++ b/core/src/main/java/fr/skytasul/quests/stages/StageBringBack.java @@ -72,7 +72,7 @@ public boolean checkItems(Player p, boolean msg){ public void sendNeedMessage(Player p) { String message = getMessage(); - if (message != null && !message.isEmpty()) + if (message != null && !message.isEmpty() && !message.equals("none")) Lang.NpcText.sendWP(p, npcName(), Utils.format(message, line), 1, 1); } From df9f0359ed0ebc0860a826f83e75e429acb46a11 Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Sun, 5 Feb 2023 21:34:13 +0100 Subject: [PATCH 24/41] :thread: Reworked data management to be fully asynchronous --- .../java/fr/skytasul/quests/BeautyQuests.java | 18 +- .../fr/skytasul/quests/QuestsListener.java | 4 +- .../commands/CommandsPlayerManagement.java | 83 +++++++-- .../quests/gui/creation/FinishGUI.java | 19 +- .../quests/players/DataException.java | 15 ++ .../quests/players/PlayerAccount.java | 32 ++-- .../quests/players/PlayersManager.java | 166 ++++++++++-------- .../quests/players/PlayersManagerDB.java | 127 ++++++++------ .../quests/players/PlayersManagerYAML.java | 40 +++-- .../fr/skytasul/quests/structure/Quest.java | 26 ++- .../quests/structure/pools/QuestPool.java | 7 +- .../java/fr/skytasul/quests/utils/Utils.java | 6 +- .../quests/utils/compatibility/Accounts.java | 10 +- .../quests/utils/logger/LoggerExpanded.java | 37 ++++ 14 files changed, 383 insertions(+), 207 deletions(-) create mode 100644 core/src/main/java/fr/skytasul/quests/players/DataException.java diff --git a/core/src/main/java/fr/skytasul/quests/BeautyQuests.java b/core/src/main/java/fr/skytasul/quests/BeautyQuests.java index 11943d95..f7b6959b 100644 --- a/core/src/main/java/fr/skytasul/quests/BeautyQuests.java +++ b/core/src/main/java/fr/skytasul/quests/BeautyQuests.java @@ -87,6 +87,7 @@ public class BeautyQuests extends JavaPlugin { private ScoreboardManager scoreboards; private QuestsManager quests; private QuestPoolsManager pools; + private PlayersManager players; /* ---------- Operations -------- */ @@ -370,7 +371,8 @@ private void loadConfigParameters(boolean init) throws LoadingException { } } - PlayersManager.manager = db == null ? new PlayersManagerYAML() : new PlayersManagerDB(db); + players = db == null ? new PlayersManagerYAML() : new PlayersManagerDB(db); + PlayersManager.manager = players; /* static initialization */ if (init) { @@ -436,9 +438,10 @@ private void loadAllDatas() throws Throwable { } try{ - if (db == null && backupDir != null) createPlayerDatasBackup(backupDir, (PlayersManagerYAML) PlayersManager.manager); + if (db == null && backupDir != null) + createPlayerDatasBackup(backupDir, (PlayersManagerYAML) players); - PlayersManager.manager.load(); + players.load(); }catch (Exception ex) { if (backupDir == null) createDataBackup(backupDir()); logger.severe("Error while loading player datas.", ex); @@ -476,7 +479,7 @@ private void loadAllDatas() throws Throwable { Bukkit.getScheduler().runTaskLater(BeautyQuests.getInstance(), () -> { for (Player p : Bukkit.getOnlinePlayers()) { - PlayersManager.loadPlayer(p); + players.loadPlayer(p); } loaded = true; }, 1L); @@ -501,7 +504,7 @@ public void saveAllConfig(boolean unload) throws Exception { data.set("version", getDescription().getVersion()); try { - PlayersManager.manager.save(); + players.save(); }catch (Exception ex) { logger.severe("Error when saving player datas.", ex); } @@ -523,6 +526,7 @@ private void resetDatas(){ }catch (Exception ex) { logger.severe("An error occurred while closing database connection.", ex); } + players = null; PlayersManager.manager = null; //HandlerList.unregisterAll(this); loaded = false; @@ -684,6 +688,10 @@ public QuestPoolsManager getPoolsManager() { return pools; } + public PlayersManager getPlayersManager() { + return players; + } + public ILoggerHandler getLoggerHandler() { return loggerHandler == null ? ILoggerHandler.EMPTY_LOGGER : loggerHandler; } diff --git a/core/src/main/java/fr/skytasul/quests/QuestsListener.java b/core/src/main/java/fr/skytasul/quests/QuestsListener.java index 25315d38..f0fdaa0e 100644 --- a/core/src/main/java/fr/skytasul/quests/QuestsListener.java +++ b/core/src/main/java/fr/skytasul/quests/QuestsListener.java @@ -147,7 +147,7 @@ public void onJoin(PlayerJoinEvent e){ Player player = e.getPlayer(); DebugUtils.logMessage(player.getName() + " joined the server"); // for timing purpose if (BeautyQuests.loaded && !QuestsConfiguration.hookAccounts()) { - PlayersManager.loadPlayer(player); + BeautyQuests.getInstance().getPlayersManager().loadPlayer(player); } } @@ -156,7 +156,7 @@ public void onQuit(PlayerQuitEvent e) { Player player = e.getPlayer(); DebugUtils.logMessage(player.getName() + " left the server"); // for timing purpose if (!QuestsConfiguration.hookAccounts()) { - PlayersManager.unloadPlayer(player); + BeautyQuests.getInstance().getPlayersManager().unloadPlayer(player); } } 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 567bd920..24fcdfc2 100644 --- a/core/src/main/java/fr/skytasul/quests/commands/CommandsPlayerManagement.java +++ b/core/src/main/java/fr/skytasul/quests/commands/CommandsPlayerManagement.java @@ -1,6 +1,9 @@ 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; @@ -22,6 +25,7 @@ import fr.skytasul.quests.structure.QuestBranch; import fr.skytasul.quests.structure.pools.QuestPool; import fr.skytasul.quests.utils.Lang; +import fr.skytasul.quests.utils.Utils; import fr.skytasul.quests.utils.types.DialogRunner; import fr.skytasul.quests.utils.types.DialogRunner.DialogNextReason; import revxrsal.commands.annotation.Optional; @@ -173,25 +177,40 @@ public void startDialog(BukkitCommandActor actor, Player player, Quest quest) { public void resetPlayer(BukkitCommandActor actor, EntitySelector players) { for (Player player : players) { PlayerAccount acc = PlayersManager.getPlayerAccount(player); + + List> futures = new ArrayList<>(acc.getQuestsDatas().size() + acc.getPoolDatas().size()); + int quests = 0, pools = 0; for (PlayerQuestDatas questDatas : new ArrayList<>(acc.getQuestsDatas())) { Quest quest = questDatas.getQuest(); - if (quest != null) { - quest.resetPlayer(acc); - }else acc.removeQuestDatas(questDatas.getQuestID()); + CompletableFuture future = + quest == null ? acc.removeQuestDatas(questDatas.getQuestID()) : quest.resetPlayer(acc); + future = future.whenComplete(BeautyQuests.logger.logError("An error occurred while resetting quest " + + questDatas.getQuestID() + " to player " + player.getName(), actor.getSender())); + futures.add(future); quests++; } for (PlayerPoolDatas poolDatas : new ArrayList<>(acc.getPoolDatas())) { QuestPool pool = poolDatas.getPool(); - if (pool != null) { - pool.resetPlayer(acc); - }else acc.removePoolDatas(poolDatas.getPoolID()); + CompletableFuture future = + pool == null ? acc.removePoolDatas(poolDatas.getPoolID()) : pool.resetPlayer(acc); + future = future.whenComplete(BeautyQuests.logger.logError( + "An error occurred while resetting pool " + poolDatas.getPoolID() + " to player " + player.getName(), + actor.getSender())); + futures.add(future); pools++; } acc.resetDatas(); - Bukkit.getPluginManager().callEvent(new PlayerAccountResetEvent(player, acc)); - if (acc.isCurrent()) Lang.DATA_REMOVED.send(player, quests, actor.getName(), pools); - Lang.DATA_REMOVED_INFO.send(actor.getSender(), quests, player.getName(), pools); + + final int questsFinal = quests; + final int poolsFinal = pools; + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).whenComplete(Utils.runSyncConsumer(() -> { + Bukkit.getPluginManager().callEvent(new PlayerAccountResetEvent(player, acc)); + if (acc.isCurrent()) + Lang.DATA_REMOVED.send(player, questsFinal, actor.getName(), poolsFinal); + Lang.DATA_REMOVED_INFO.send(actor.getSender(), questsFinal, player.getName(), poolsFinal); + })); + } } @@ -209,9 +228,11 @@ public void resetPlayerQuest(BukkitCommandActor actor, Player player, @Optional } private void reset(CommandSender sender, Player target, PlayerAccount acc, Quest qu) { - qu.resetPlayer(acc); - if (acc.isCurrent()) Lang.DATA_QUEST_REMOVED.send(target, qu.getName(), sender.getName()); - Lang.DATA_QUEST_REMOVED_INFO.send(sender, target.getName(), qu.getName()); + qu.resetPlayer(acc).whenComplete(BeautyQuests.logger.logError(__ -> { + if (acc.isCurrent()) + Lang.DATA_QUEST_REMOVED.send(target, qu.getName(), sender.getName()); + Lang.DATA_QUEST_REMOVED_INFO.send(sender, target.getName(), qu.getName()); + }, "An error occurred while removing player quest data", sender)); } @Subcommand ("resetPlayerPool") @@ -222,20 +243,46 @@ public void resetPlayerPool(BukkitCommandActor actor, Player player, QuestPool p pool.resetPlayerTimer(acc); Lang.POOL_RESET_TIMER.send(actor.getSender(), pool.getID(), player.getName()); }else { - pool.resetPlayer(acc); - Lang.POOL_RESET_FULL.send(actor.getSender(), pool.getID(), player.getName()); + pool.resetPlayer(acc).whenComplete(BeautyQuests.logger.logError(__ -> { + Lang.POOL_RESET_FULL.send(actor.getSender(), pool.getID(), player.getName()); + }, "An error occurred while resetting pool " + pool.getID() + " to player " + player.getName(), + actor.getSender())); } } @Subcommand ("resetQuest") @CommandPermission ("beautyquests.command.resetQuest") public void resetQuest(BukkitCommandActor actor, Quest quest) { - int amount = 0; + List> futures = new ArrayList<>(Bukkit.getOnlinePlayers().size()); + for (Player p : Bukkit.getOnlinePlayers()) { - if (quest.resetPlayer(PlayersManager.getPlayerAccount(p))) amount++; + futures.add(quest.resetPlayer(PlayersManager.getPlayerAccount(p)) + .whenComplete(BeautyQuests.logger.logError( + "An error occurred while resetting quest " + quest.getID() + " to player " + p.getName(), + actor.getSender()))); } - amount += PlayersManager.manager.removeQuestDatas(quest); - Lang.QUEST_PLAYERS_REMOVED.send(actor.getSender(), amount); + + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).whenComplete((__, ___) -> { + // we do not care about failure or success of this "global" future + + int resetAmount = + (int) futures.stream().filter(future -> { + try { + return !future.isCompletedExceptionally() && future.get(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } catch (ExecutionException ignored) { + // we already check if the future is completed exceptionnally before using get() + } + return false; + }).count(); + + BeautyQuests.getInstance().getPlayersManager().removeQuestDatas(quest) + .whenComplete(BeautyQuests.logger.logError(removedAmount -> { + Lang.QUEST_PLAYERS_REMOVED.send(actor.getSender(), removedAmount + resetAmount); + }, "An error occurred while removing quest datas", actor.getSender())); + }).whenComplete(BeautyQuests.logger.logError()); + } @Subcommand ("seePlayer") diff --git a/core/src/main/java/fr/skytasul/quests/gui/creation/FinishGUI.java b/core/src/main/java/fr/skytasul/quests/gui/creation/FinishGUI.java index a774e3ca..32748e26 100644 --- a/core/src/main/java/fr/skytasul/quests/gui/creation/FinishGUI.java +++ b/core/src/main/java/fr/skytasul/quests/gui/creation/FinishGUI.java @@ -4,14 +4,12 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Map; - import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.entity.Player; import org.bukkit.event.inventory.ClickType; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; - import fr.skytasul.quests.BeautyQuests; import fr.skytasul.quests.QuestsConfiguration; import fr.skytasul.quests.api.QuestsAPI; @@ -189,12 +187,6 @@ private void finish(){ qu = new Quest(id); } - if (session.areStagesEdited()) { - if (keepPlayerDatas) { - BeautyQuests.logger.warning("Players quests datas will be kept for quest #" + qu.getID() + " - this may cause datas issues."); - }else PlayersManager.manager.removeQuestDatas(qu); - } - for (QuestOption option : this) { if (option.hasCustomValue()) qu.addOption(option); } @@ -209,6 +201,17 @@ private void finish(){ qu.remove(false, true); Utils.sendMessage(p, Lang.CANCELLED.toString()); }else { + + if (session.areStagesEdited()) { + if (keepPlayerDatas) { + BeautyQuests.logger.warning("Players quests datas will be kept for quest #" + qu.getID() + + " - this may cause datas issues."); + } else + BeautyQuests.getInstance().getPlayersManager().removeQuestDatas(session.getQuestEdited()) + .whenComplete(BeautyQuests.logger + .logError("An error occurred while removing player datas after quest edition", p)); + } + QuestsAPI.getQuests().addQuest(qu); Utils.sendMessage(p, ((!session.isEdition()) ? Lang.SUCCESFULLY_CREATED : Lang.SUCCESFULLY_EDITED).toString(), qu.getName(), qu.getBranchesManager().getBranchesAmount()); Utils.playPluginSound(p, "ENTITY_VILLAGER_YES", 1); diff --git a/core/src/main/java/fr/skytasul/quests/players/DataException.java b/core/src/main/java/fr/skytasul/quests/players/DataException.java new file mode 100644 index 00000000..1466deb3 --- /dev/null +++ b/core/src/main/java/fr/skytasul/quests/players/DataException.java @@ -0,0 +1,15 @@ +package fr.skytasul.quests.players; + +public class DataException extends RuntimeException { + + private static final long serialVersionUID = -2135458159622298091L; + + public DataException(String message) { + super(message); + } + + public DataException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/core/src/main/java/fr/skytasul/quests/players/PlayerAccount.java b/core/src/main/java/fr/skytasul/quests/players/PlayerAccount.java index 630f42a5..01220c52 100644 --- a/core/src/main/java/fr/skytasul/quests/players/PlayerAccount.java +++ b/core/src/main/java/fr/skytasul/quests/players/PlayerAccount.java @@ -5,11 +5,11 @@ import java.util.HashMap; import java.util.List; import java.util.Map; - +import java.util.concurrent.CompletableFuture; import org.bukkit.OfflinePlayer; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; - +import fr.skytasul.quests.BeautyQuests; import fr.skytasul.quests.api.data.SavableData; import fr.skytasul.quests.players.accounts.AbstractAccount; import fr.skytasul.quests.structure.Quest; @@ -63,20 +63,22 @@ public PlayerQuestDatas getQuestDatasIfPresent(Quest quest) { public PlayerQuestDatas getQuestDatas(Quest quest) { PlayerQuestDatas datas = questDatas.get(quest.getID()); if (datas == null) { - datas = PlayersManager.manager.createPlayerQuestDatas(this, quest); + datas = BeautyQuests.getInstance().getPlayersManager().createPlayerQuestDatas(this, quest); questDatas.put(quest.getID(), datas); } return datas; } - public PlayerQuestDatas removeQuestDatas(Quest quest) { + public CompletableFuture removeQuestDatas(Quest quest) { return removeQuestDatas(quest.getID()); } - public PlayerQuestDatas removeQuestDatas(int id) { + public CompletableFuture removeQuestDatas(int id) { PlayerQuestDatas removed = questDatas.remove(id); - if (removed != null) PlayersManager.manager.playerQuestDataRemoved(this, id, removed); - return removed; + if (removed == null) + return CompletableFuture.completedFuture(null); + + return BeautyQuests.getInstance().getPlayersManager().playerQuestDataRemoved(removed).thenApply(__ -> removed); } protected PlayerQuestDatas removeQuestDatasSilently(int id) { @@ -94,20 +96,22 @@ public boolean hasPoolDatas(QuestPool pool) { public PlayerPoolDatas getPoolDatas(QuestPool pool) { PlayerPoolDatas datas = poolDatas.get(pool.getID()); if (datas == null) { - datas = PlayersManager.manager.createPlayerPoolDatas(this, pool); + datas = BeautyQuests.getInstance().getPlayersManager().createPlayerPoolDatas(this, pool); poolDatas.put(pool.getID(), datas); } return datas; } - public PlayerPoolDatas removePoolDatas(QuestPool pool) { + public CompletableFuture removePoolDatas(QuestPool pool) { return removePoolDatas(pool.getID()); } - public PlayerPoolDatas removePoolDatas(int id) { + public CompletableFuture removePoolDatas(int id) { PlayerPoolDatas removed = poolDatas.remove(id); - if (removed != null) PlayersManager.manager.playerPoolDataRemoved(this, id, removed); - return removed; + if (removed == null) + return CompletableFuture.completedFuture(null); + + return BeautyQuests.getInstance().getPlayersManager().playerPoolDataRemoved(removed).thenApply(__ -> removed); } public Collection getPoolDatas() { @@ -115,13 +119,13 @@ public Collection getPoolDatas() { } public T getData(SavableData data) { - if (!PlayersManager.manager.getAccountDatas().contains(data)) + if (!BeautyQuests.getInstance().getPlayersManager().getAccountDatas().contains(data)) throw new IllegalArgumentException("The " + data.getId() + " account data has not been registered."); return (T) additionalDatas.getOrDefault(data, data.getDefaultValue()); } public void setData(SavableData data, T value) { - if (!PlayersManager.manager.getAccountDatas().contains(data)) + if (!BeautyQuests.getInstance().getPlayersManager().getAccountDatas().contains(data)) throw new IllegalArgumentException("The " + data.getId() + " account data has not been registered."); additionalDatas.put(data, value); } diff --git a/core/src/main/java/fr/skytasul/quests/players/PlayersManager.java b/core/src/main/java/fr/skytasul/quests/players/PlayersManager.java index d3078b42..66a9d3dd 100644 --- a/core/src/main/java/fr/skytasul/quests/players/PlayersManager.java +++ b/core/src/main/java/fr/skytasul/quests/players/PlayersManager.java @@ -10,6 +10,7 @@ import java.util.Map; import java.util.Set; import java.util.UUID; +import java.util.concurrent.CompletableFuture; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; @@ -31,25 +32,30 @@ import fr.skytasul.quests.utils.compatibility.MissingDependencyException; public abstract class PlayersManager { - + + protected final Map cachedAccounts = new HashMap<>(); protected final Set> accountDatas = new HashSet<>(); private boolean loaded = false; public abstract void load(AccountFetchRequest request); - protected abstract void removeAccount(PlayerAccount acc); + public abstract void unloadAccount(PlayerAccount acc); + + protected abstract CompletableFuture removeAccount(PlayerAccount acc); - public abstract PlayerQuestDatas createPlayerQuestDatas(PlayerAccount acc, Quest quest); + public abstract CompletableFuture removeQuestDatas(Quest quest); - public void playerQuestDataRemoved(PlayerAccount acc, int id, PlayerQuestDatas datas) {} + public abstract PlayerQuestDatas createPlayerQuestDatas(PlayerAccount acc, Quest quest); public abstract PlayerPoolDatas createPlayerPoolDatas(PlayerAccount acc, QuestPool pool); + + public CompletableFuture playerQuestDataRemoved(PlayerQuestDatas datas) { + return CompletableFuture.completedFuture(null); + } - public void playerPoolDataRemoved(PlayerAccount acc, int id, PlayerPoolDatas datas) {} - - public abstract int removeQuestDatas(Quest quest); - - public abstract void unloadAccount(PlayerAccount acc); + public CompletableFuture playerPoolDataRemoved(PlayerPoolDatas datas) { + return CompletableFuture.completedFuture(null); + } public void load() { if (loaded) throw new IllegalStateException("Already loaded"); @@ -79,11 +85,11 @@ public Collection> getAccountDatas() { return accountDatas; } - public AbstractAccount createAbstractAccount(Player p) { + protected AbstractAccount createAbstractAccount(Player p) { return QuestsConfiguration.hookAccounts() ? Accounts.getPlayerAccount(p) : new UUIDAccount(p.getUniqueId()); } - public String getIdentifier(OfflinePlayer p) { + protected String getIdentifier(OfflinePlayer p) { if (QuestsConfiguration.hookAccounts()) { if (!p.isOnline()) throw new IllegalArgumentException("Cannot fetch player identifier of an offline player with AccountsHook"); @@ -117,88 +123,94 @@ protected AbstractAccount createAccountFromIdentifier(String identifier) { } return null; } - - protected static Map cachedAccounts = new HashMap<>(); - private static Map cachedPlayerNames = new HashMap<>(); - private static Gson gson = new Gson(); - private static long lastOnlineFailure = 0; - public static PlayersManager manager; - public static synchronized void loadPlayer(Player p) { + public synchronized void loadPlayer(Player p) { cachedPlayerNames.put(p.getUniqueId(), p.getName()); long time = System.currentTimeMillis(); DebugUtils.logMessage("Loading player " + p.getName() + "..."); cachedAccounts.remove(p); Bukkit.getScheduler().runTaskAsynchronously(BeautyQuests.getInstance(), () -> { - int i = 2; - while (i > 0) { - i--; + for (int i = 1; i >= 0; i--) { try { - if (!p.isOnline()) { - BeautyQuests.logger.warning("Player " + p.getName() - + " has quit the server while loading its datas. This may be a bug."); - return; - } - - AccountFetchRequest request = new AccountFetchRequest(p, time, true, true); - manager.load(request); - - if (request.isFinished() && request.getAccount() != null) { - if (!p.isOnline()) { - if (request.isAccountCreated()) { - DebugUtils.logMessage("New account registered for " + p.getName() - + "... but deleted as player left before loading."); - manager.removeAccount(request.getAccount()); - } - return; - } - if (request.isAccountCreated()) - DebugUtils.logMessage("New account registered for " + p.getName() + " (" - + request.getAccount().abstractAcc.getIdentifier() + "), index " - + request.getAccount().index + " via " + DebugUtils.stackTraces(2, 4)); - cachedAccounts.put(p, request.getAccount()); - Bukkit.getScheduler().runTask(BeautyQuests.getInstance(), () -> { - String loadMessage = "Completed load of " + p.getName() + " 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(); - DebugUtils.logMessage(loadMessage); - if (p.isOnline()) { - Bukkit.getPluginManager().callEvent( - new PlayerAccountJoinEvent(p, request.getAccount(), request.isAccountCreated())); - } else { - BeautyQuests.logger.warning("Player " + p.getName() - + " has quit the server while loading its datas. This may be a bug."); - if (request.isAccountCreated()) { - manager.removeAccount(request.getAccount()); - } - } - }); + if (!tryLoad(p, time)) return; - } - BeautyQuests.logger.severe("The account of " + p.getName() + " has not been properly loaded."); - }catch (Exception ex) { + } catch (Exception ex) { BeautyQuests.logger.severe("An error ocurred while trying to load datas of " + p.getName() + ".", ex); } - BeautyQuests.logger.severe("Doing " + i + " more attempt."); + if (i > 0) + BeautyQuests.logger.severe("Doing " + i + " more attempt."); } BeautyQuests.logger.severe("Datas of " + p.getName() + " have failed to load. This may cause MANY issues."); }); } + + private boolean tryLoad(Player p, long time) { + if (!p.isOnline()) { + BeautyQuests.logger + .warning("Player " + p.getName() + " has quit the server while loading its datas. This may be a bug."); + return false; + } + + AccountFetchRequest request = new AccountFetchRequest(p, time, true, true); + load(request); + + if (!request.isFinished() || request.getAccount() == null) { + BeautyQuests.logger.severe("The account of " + p.getName() + " has not been properly loaded."); + return true; + } + + if (!p.isOnline()) { + if (request.isAccountCreated()) { + DebugUtils.logMessage( + "New account registered for " + p.getName() + "... but deleted as player left before loading."); + removeAccount(request.getAccount()).whenComplete( + BeautyQuests.logger.logError("An error occurred while removing newly created account")); + } + return false; + } + + if (request.isAccountCreated()) + DebugUtils.logMessage( + "New account registered for " + p.getName() + " (" + request.getAccount().abstractAcc.getIdentifier() + + "), index " + request.getAccount().index + " via " + DebugUtils.stackTraces(2, 4)); + + cachedAccounts.put(p, request.getAccount()); + Bukkit.getScheduler().runTask(BeautyQuests.getInstance(), () -> { + String loadMessage = "Completed load of " + p.getName() + " 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(); + + DebugUtils.logMessage(loadMessage); + + if (p.isOnline()) { + Bukkit.getPluginManager() + .callEvent(new PlayerAccountJoinEvent(p, request.getAccount(), request.isAccountCreated())); + } else { + BeautyQuests.logger.warning( + "Player " + p.getName() + " has quit the server while loading its datas. This may be a bug."); + + if (request.isAccountCreated()) + removeAccount(request.getAccount()).whenComplete( + BeautyQuests.logger.logError("An error occurred while removing newly created account")); + } + }); + return false; + } - public static synchronized void unloadPlayer(Player p) { + public synchronized void unloadPlayer(Player p) { PlayerAccount acc = cachedAccounts.get(p); if (acc == null) return; DebugUtils.logMessage("Unloading player " + p.getName() + "... (" + acc.getQuestsDatas().size() + " quests, " + acc.getPoolDatas().size() + " pools)"); Bukkit.getPluginManager().callEvent(new PlayerAccountLeaveEvent(p, acc)); - manager.unloadAccount(acc); + unloadAccount(acc); cachedAccounts.remove(p); } - public static PlayerAccount getPlayerAccount(Player p) { + public PlayerAccount getAccount(Player p) { if (QuestsAPI.getNPCsManager().isNPC(p)) return null; if (!p.isOnline()) { BeautyQuests.logger.severe("Trying to fetch the account of an offline player (" + p.getName() + ")"); @@ -208,6 +220,20 @@ public static PlayerAccount getPlayerAccount(Player p) { return cachedAccounts.get(p); } + private static Map cachedPlayerNames = new HashMap<>(); + private static Gson gson = new Gson(); + private static long lastOnlineFailure = 0; + + /** + * @deprecated use {@link BeautyQuests#getPlayersManager()} + */ + @Deprecated + public static PlayersManager manager; // TODO remove, changed in 0.20.1 + + public static PlayerAccount getPlayerAccount(Player p) { + return BeautyQuests.getInstance().getPlayersManager().getAccount(p); + } + public static synchronized String getPlayerName(UUID uuid) { if (cachedPlayerNames.containsKey(uuid)) return cachedPlayerNames.get(uuid); diff --git a/core/src/main/java/fr/skytasul/quests/players/PlayersManagerDB.java b/core/src/main/java/fr/skytasul/quests/players/PlayersManagerDB.java index 8cf85048..ff48d726 100644 --- a/core/src/main/java/fr/skytasul/quests/players/PlayersManagerDB.java +++ b/core/src/main/java/fr/skytasul/quests/players/PlayersManagerDB.java @@ -14,6 +14,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @@ -99,7 +100,7 @@ public void addAccountData(SavableData data) { .collect(Collectors.joining(", ", "UPDATE " + ACCOUNTS_TABLE + " SET ", " WHERE `id` = ?")); } - private synchronized void retrievePlayerDatas(PlayerAccount acc) { + private void retrievePlayerDatas(PlayerAccount acc) { try (Connection connection = db.getConnection()) { try (PreparedStatement statement = connection.prepareStatement(getQuestsData)) { statement.setInt(1, acc.index); @@ -138,7 +139,7 @@ private synchronized void retrievePlayerDatas(PlayerAccount acc) { } @Override - public synchronized void load(AccountFetchRequest request) { + public void load(AccountFetchRequest request) { try (Connection connection = db.getConnection()) { String uuid = request.getOfflinePlayer().getUniqueId().toString(); try (PreparedStatement statement = connection.prepareStatement(getAccountsIDs)) { @@ -153,7 +154,8 @@ public synchronized void load(AccountFetchRequest request) { // in order to ensure that, if the player was previously connected to another server, // its datas have been fully pushed to database, we wait for 0,4 seconds long timeout = 400 - (System.currentTimeMillis() - request.getJoinTimestamp()); - if (timeout > 0) wait(timeout); + if (timeout > 0) + Thread.sleep(timeout); }catch (InterruptedException e) { e.printStackTrace(); Thread.currentThread().interrupt(); @@ -187,14 +189,16 @@ public synchronized void load(AccountFetchRequest request) { } @Override - protected synchronized void removeAccount(PlayerAccount acc) { - try (Connection connection = db.getConnection(); - PreparedStatement statement = connection.prepareStatement(deleteAccount)) { - statement.setInt(1, acc.index); - statement.executeUpdate(); - }catch (SQLException ex) { - ex.printStackTrace(); - } + protected CompletableFuture removeAccount(PlayerAccount acc) { + return CompletableFuture.runAsync(() -> { + try (Connection connection = db.getConnection(); + PreparedStatement statement = connection.prepareStatement(deleteAccount)) { + statement.setInt(1, acc.index); + statement.executeUpdate(); + } catch (SQLException ex) { + throw new DataException("An error occurred while removing account from database.", ex); + } + }); } @Override @@ -203,16 +207,18 @@ public PlayerQuestDatas createPlayerQuestDatas(PlayerAccount acc, Quest quest) { } @Override - public synchronized void playerQuestDataRemoved(PlayerAccount acc, int id, PlayerQuestDatas datas) { - try (Connection connection = db.getConnection(); - PreparedStatement statement = connection.prepareStatement(removeQuestData)) { - ((PlayerQuestDatasDB) datas).stop(); - statement.setInt(1, acc.index); - statement.setInt(2, id); - statement.executeUpdate(); - }catch (SQLException e) { - e.printStackTrace(); - } + public CompletableFuture playerQuestDataRemoved(PlayerQuestDatas datas) { + return CompletableFuture.runAsync(() -> { + try (Connection connection = db.getConnection(); + PreparedStatement statement = connection.prepareStatement(removeQuestData)) { + ((PlayerQuestDatasDB) datas).stop(); + statement.setInt(1, datas.acc.index); + statement.setInt(2, datas.questID); + statement.executeUpdate(); + } catch (SQLException ex) { + throw new DataException("An error occurred while removing player quest data from database.", ex); + } + }); } @Override @@ -221,47 +227,52 @@ public PlayerPoolDatas createPlayerPoolDatas(PlayerAccount acc, QuestPool pool) } @Override - public synchronized void playerPoolDataRemoved(PlayerAccount acc, int id, PlayerPoolDatas datas) { - try (Connection connection = db.getConnection(); - PreparedStatement statement = connection.prepareStatement(removePoolData)) { - statement.setInt(1, acc.index); - statement.setInt(2, id); - statement.executeUpdate(); - }catch (SQLException e) { - e.printStackTrace(); - } + public CompletableFuture playerPoolDataRemoved(PlayerPoolDatas datas) { + return CompletableFuture.runAsync(() -> { + try (Connection connection = db.getConnection(); + PreparedStatement statement = connection.prepareStatement(removePoolData)) { + statement.setInt(1, datas.acc.index); + statement.setInt(2, datas.poolID); + statement.executeUpdate(); + } catch (SQLException ex) { + throw new DataException("An error occurred while removing player quest data from database.", ex); + } + }); } - + @Override - public synchronized int removeQuestDatas(Quest quest) { - int amount = 0; - try (Connection connection = db.getConnection(); - PreparedStatement statement = connection.prepareStatement(removeExistingQuestDatas)) { - for (PlayerAccount acc : PlayersManager.cachedAccounts.values()) { - PlayerQuestDatasDB datas = (PlayerQuestDatasDB) acc.removeQuestDatasSilently(quest.getID()); - if (datas != null) datas.stop(); + public CompletableFuture removeQuestDatas(Quest quest) { + return CompletableFuture.supplyAsync(() -> { + int amount = 0; + try (Connection connection = db.getConnection(); + PreparedStatement statement = connection.prepareStatement(removeExistingQuestDatas)) { + for (PlayerAccount acc : cachedAccounts.values()) { + PlayerQuestDatasDB datas = (PlayerQuestDatasDB) acc.removeQuestDatasSilently(quest.getID()); + if (datas != null) datas.stop(); + } + statement.setInt(1, quest.getID()); + amount += statement.executeUpdate(); + } catch (SQLException ex) { + throw new DataException("Failed to remove quest datas from database.", ex); } - statement.setInt(1, quest.getID()); - amount += statement.executeUpdate(); - }catch (SQLException e) { - e.printStackTrace(); - } - DebugUtils.logMessage("Removed " + amount + " quest datas for quest " + quest.getID()); - return amount; + DebugUtils.logMessage("Removed " + amount + " quest datas for quest " + quest.getID()); + return amount; + }); } - public synchronized boolean hasAccounts(Player p) { - try (Connection connection = db.getConnection(); - PreparedStatement statement = connection.prepareStatement(getAccountsIDs)) { - statement.setString(1, p.getUniqueId().toString()); - ResultSet result = statement.executeQuery(); - boolean has = result.next(); - result.close(); - return has; - }catch (SQLException e) { - e.printStackTrace(); - } - return false; + public CompletableFuture hasAccounts(Player p) { + return CompletableFuture.supplyAsync(() -> { + try (Connection connection = db.getConnection(); + PreparedStatement statement = connection.prepareStatement(getAccountsIDs)) { + statement.setString(1, p.getUniqueId().toString()); + ResultSet result = statement.executeQuery(); + boolean has = result.next(); + result.close(); + return has; + } catch (SQLException ex) { + throw new DataException("An error occurred while fetching account from database.", ex); + } + }); } @Override @@ -305,7 +316,7 @@ private String prepareDatasStatement(String column) throws SQLException { @Override public void save() { - PlayersManager.cachedAccounts.values().forEach(x -> saveAccount(x, false)); + cachedAccounts.values().forEach(x -> saveAccount(x, false)); } private void createTables() throws SQLException { diff --git a/core/src/main/java/fr/skytasul/quests/players/PlayersManagerYAML.java b/core/src/main/java/fr/skytasul/quests/players/PlayersManagerYAML.java index f9eb6378..0231aea4 100644 --- a/core/src/main/java/fr/skytasul/quests/players/PlayersManagerYAML.java +++ b/core/src/main/java/fr/skytasul/quests/players/PlayersManagerYAML.java @@ -10,6 +10,9 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import org.apache.commons.lang.Validate; import org.bukkit.Bukkit; @@ -100,10 +103,10 @@ public void load(AccountFetchRequest request) { } @Override - protected void removeAccount(PlayerAccount acc) { + protected CompletableFuture removeAccount(PlayerAccount acc) { loadedAccounts.remove(acc.index); identifiersIndex.remove(acc.index); - removePlayerFile(acc.index); + return CompletableFuture.runAsync(() -> removePlayerFile(acc.index)); } @Override @@ -117,15 +120,28 @@ public PlayerPoolDatas createPlayerPoolDatas(PlayerAccount acc, QuestPool pool) } @Override - public int removeQuestDatas(Quest quest) { - loadAllAccounts(); - int amount = 0; - - for (PlayerAccount account : loadedAccounts.values()) { - if (account.removeQuestDatas(quest) != null) amount++; - } - - return amount; + public CompletableFuture removeQuestDatas(Quest quest) { + return CompletableFuture.supplyAsync(() -> { + loadAllAccounts(); + int amount = 0; + + for (PlayerAccount account : loadedAccounts.values()) { + try { + if (account.removeQuestDatas(quest).get() != null) { + // we can use the .get() method as the CompletableFuture created by the YAML players manager is + // already completed + amount++; + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new CompletionException(e); + } catch (ExecutionException e) { + throw new CompletionException(e); + } + } + + return amount; + }); } public boolean hasAccounts(Player p) { @@ -162,7 +178,7 @@ public void debugDuplicate() { for (Player p : Bukkit.getOnlinePlayers()) { p.kickPlayer("§cCleanup operation."); } - PlayersManager.cachedAccounts.clear(); + cachedAccounts.clear(); loadAllAccounts(); int amount = 0; diff --git a/core/src/main/java/fr/skytasul/quests/structure/Quest.java b/core/src/main/java/fr/skytasul/quests/structure/Quest.java index 10493abf..6e66de45 100644 --- a/core/src/main/java/fr/skytasul/quests/structure/Quest.java +++ b/core/src/main/java/fr/skytasul/quests/structure/Quest.java @@ -11,6 +11,7 @@ import java.util.Iterator; import java.util.List; import java.util.OptionalInt; +import java.util.concurrent.CompletableFuture; import java.util.regex.Pattern; import org.bukkit.Bukkit; import org.bukkit.configuration.ConfigurationSection; @@ -220,16 +221,24 @@ public boolean cancelPlayer(PlayerAccount acc) { return true; } - public boolean resetPlayer(PlayerAccount acc){ - if (acc == null) return false; - boolean c = false; + public CompletableFuture resetPlayer(PlayerAccount acc){ + if (acc == null) + return CompletableFuture.completedFuture(Boolean.FALSE); + + boolean hadDatas = false; + CompletableFuture future = null; + if (acc.hasQuestDatas(this)) { + hadDatas = true; cancelPlayer(acc); - acc.removeQuestDatas(this); - c = true; + future = acc.removeQuestDatas(this); } - if (acc.isCurrent() && hasOption(OptionStartDialog.class) && getOption(OptionStartDialog.class).getDialogRunner().removePlayer(acc.getPlayer())) c = true; - return c; + + if (acc.isCurrent() && hasOption(OptionStartDialog.class) + && getOption(OptionStartDialog.class).getDialogRunner().removePlayer(acc.getPlayer())) + hadDatas = true; + + return future == null ? CompletableFuture.completedFuture(hadDatas) : future.thenApply(__ -> true); } public boolean isLauncheable(Player p, PlayerAccount acc, boolean sendMessage) { @@ -441,7 +450,8 @@ public void remove(boolean msg, boolean removeDatas) { QuestsAPI.getQuests().removeQuest(this); unload(); if (removeDatas) { - PlayersManager.manager.removeQuestDatas(this); + BeautyQuests.getInstance().getPlayersManager().removeQuestDatas(this).whenComplete( + BeautyQuests.logger.logError("An error occurred while removing player datas after quest removal")); if (file.exists()) file.delete(); } removed = true; diff --git a/core/src/main/java/fr/skytasul/quests/structure/pools/QuestPool.java b/core/src/main/java/fr/skytasul/quests/structure/pools/QuestPool.java index 21da45ca..c175fc9c 100644 --- a/core/src/main/java/fr/skytasul/quests/structure/pools/QuestPool.java +++ b/core/src/main/java/fr/skytasul/quests/structure/pools/QuestPool.java @@ -3,13 +3,12 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ThreadLocalRandom; import java.util.stream.Collectors; - import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; - import fr.skytasul.quests.BeautyQuests; import fr.skytasul.quests.api.QuestsAPI; import fr.skytasul.quests.api.npcs.BQNPC; @@ -129,8 +128,8 @@ public ItemStack getItemStack(String action) { "", action); } - public void resetPlayer(PlayerAccount acc) { - acc.removePoolDatas(this); + public CompletableFuture resetPlayer(PlayerAccount acc) { + return acc.removePoolDatas(this); } public void resetPlayerTimer(PlayerAccount acc) { diff --git a/core/src/main/java/fr/skytasul/quests/utils/Utils.java b/core/src/main/java/fr/skytasul/quests/utils/Utils.java index eb7ca6dc..6e4d2052 100644 --- a/core/src/main/java/fr/skytasul/quests/utils/Utils.java +++ b/core/src/main/java/fr/skytasul/quests/utils/Utils.java @@ -19,6 +19,7 @@ import java.util.Map.Entry; import java.util.Objects; import java.util.Optional; +import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; @@ -380,13 +381,16 @@ public static void walkResources(Class clazz, String path, int depth, Consume } } - public static void runOrSync(Runnable run) { if (Bukkit.isPrimaryThread()) { run.run(); }else Bukkit.getScheduler().runTask(BeautyQuests.getInstance(), run); } + public static BiConsumer runSyncConsumer(Runnable run) { + return (__, ___) -> runSync(run); + } + public static void runSync(Runnable run){ Bukkit.getScheduler().runTask(BeautyQuests.getInstance(), run); } diff --git a/core/src/main/java/fr/skytasul/quests/utils/compatibility/Accounts.java b/core/src/main/java/fr/skytasul/quests/utils/compatibility/Accounts.java index 913b7743..ae2ab048 100644 --- a/core/src/main/java/fr/skytasul/quests/utils/compatibility/Accounts.java +++ b/core/src/main/java/fr/skytasul/quests/utils/compatibility/Accounts.java @@ -1,17 +1,15 @@ package fr.skytasul.quests.utils.compatibility; import java.util.UUID; - import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; - import fr.skytasul.accounts.Account; import fr.skytasul.accounts.AccountService; import fr.skytasul.accounts.events.AccountLeaveEvent; import fr.skytasul.accounts.events.AccountUseEvent; -import fr.skytasul.quests.players.PlayersManager; +import fr.skytasul.quests.BeautyQuests; import fr.skytasul.quests.players.accounts.HookedAccount; public class Accounts implements Listener { @@ -38,14 +36,12 @@ public static String getPlayerCurrentIdentifier(Player p) { @EventHandler public void onAccountUse(AccountUseEvent e) { - PlayersManager.loadPlayer(e.getPlayer()); - //Bukkit.getPluginManager().callEvent(new PlayerAccountJoinEvent(e.getPlayer(), PlayersManager.getPlayerAccount(e.getPlayer()), e.isAccountCreated())); + BeautyQuests.getInstance().getPlayersManager().loadPlayer(e.getPlayer()); } @EventHandler public void onAccountLeave(AccountLeaveEvent e) { - PlayersManager.unloadPlayer(e.getPlayer()); - //Bukkit.getPluginManager().callEvent(new PlayerAccountLeaveEvent(e.getPlayer(), PlayersManager.getPlayerAccount(e.getPlayer()))); + BeautyQuests.getInstance().getPlayersManager().unloadPlayer(e.getPlayer()); } } diff --git a/core/src/main/java/fr/skytasul/quests/utils/logger/LoggerExpanded.java b/core/src/main/java/fr/skytasul/quests/utils/logger/LoggerExpanded.java index 2b7a56ac..e14e07a0 100644 --- a/core/src/main/java/fr/skytasul/quests/utils/logger/LoggerExpanded.java +++ b/core/src/main/java/fr/skytasul/quests/utils/logger/LoggerExpanded.java @@ -1,7 +1,12 @@ package fr.skytasul.quests.utils.logger; +import java.util.concurrent.CompletionException; +import java.util.function.BiConsumer; +import java.util.function.Consumer; import java.util.logging.Level; import java.util.logging.Logger; +import org.bukkit.command.CommandSender; +import fr.skytasul.quests.utils.Lang; public class LoggerExpanded { @@ -30,4 +35,36 @@ public void severe(String msg) { public void severe(String msg, Throwable throwable) { logger.log(Level.SEVERE, msg, throwable); } + + public BiConsumer logError(Consumer consumer, String friendlyErrorMessage, CommandSender sender) { + return (object, ex) -> { + if (ex == null) { + if (consumer != null) + consumer.accept(object); + } else { + if (ex instanceof CompletionException) { + CompletionException exCompl = (CompletionException) ex; + if (exCompl.getCause() != null) + ex = exCompl.getCause(); + } + + if (sender != null) + Lang.ERROR_OCCURED.send(sender, friendlyErrorMessage); + severe(friendlyErrorMessage, ex); + } + }; + } + + public BiConsumer logError(String friendlyErrorMessage, CommandSender sender) { + return logError(null, friendlyErrorMessage, sender); + } + + public BiConsumer logError(String friendlyErrorMessage) { + return logError(null, friendlyErrorMessage, null); + } + + public BiConsumer logError() { + return logError(null, null, null); + } + } From 72a6e567c2e5d668bbab39527cdce01f31c619b7 Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Wed, 15 Feb 2023 17:40:20 +0100 Subject: [PATCH 25/41] :card_file_box: Added database auto-reconnect option --- core/src/main/resources/hikari.properties | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/resources/hikari.properties b/core/src/main/resources/hikari.properties index 01d762db..271557b5 100644 --- a/core/src/main/resources/hikari.properties +++ b/core/src/main/resources/hikari.properties @@ -7,4 +7,5 @@ dataSource.rewriteBatchedStatements=true dataSource.cacheResultSetMetadata=true dataSource.cacheServerConfiguration=true dataSource.elideSetAutoCommits=true -dataSource.maintainTimeStats=false \ No newline at end of file +dataSource.maintainTimeStats=false +dataSource.autoReconnect=true \ No newline at end of file From 7501fea58fae2366d670dbb3ab64b12e40a06280 Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Wed, 15 Feb 2023 17:40:49 +0100 Subject: [PATCH 26/41] :bug: Fixed bug in scoreboard when having $ symbol in quest placeholders --- .../main/java/fr/skytasul/quests/scoreboards/Scoreboard.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/fr/skytasul/quests/scoreboards/Scoreboard.java b/core/src/main/java/fr/skytasul/quests/scoreboards/Scoreboard.java index ce6ebac7..227ff3a9 100644 --- a/core/src/main/java/fr/skytasul/quests/scoreboards/Scoreboard.java +++ b/core/src/main/java/fr/skytasul/quests/scoreboards/Scoreboard.java @@ -373,7 +373,7 @@ private String formatQuestPlaceholders(String text) { } } } - matcher.appendReplacement(textBuffer, replacement); + matcher.appendReplacement(textBuffer, Matcher.quoteReplacement(replacement)); } matcher.appendTail(textBuffer); return textBuffer.toString(); From a90d82d93bbc2814197a29987813e63fce2322a6 Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Sat, 18 Feb 2023 17:13:33 +0100 Subject: [PATCH 27/41] :bug: Potion of the Turtle Master is now correctly displayed in stages --- .../src/main/java/fr/skytasul/quests/utils/MinecraftNames.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/fr/skytasul/quests/utils/MinecraftNames.java b/core/src/main/java/fr/skytasul/quests/utils/MinecraftNames.java index a4ca2f36..22579b23 100644 --- a/core/src/main/java/fr/skytasul/quests/utils/MinecraftNames.java +++ b/core/src/main/java/fr/skytasul/quests/utils/MinecraftNames.java @@ -87,7 +87,8 @@ public static String getMaterialName(ItemStack item) { PotionMeta meta = (PotionMeta) item.getItemMeta(); try { PotionData basePotion = meta.getBasePotionData(); - XPotion potion = XPotion.matchXPotion(basePotion.getType().getEffectType()); + XPotion potion = basePotion.getType().name().equals("TURTLE_MASTER") ? XPotion.TURTLE_MASTER + : XPotion.matchXPotion(basePotion.getType().getEffectType()); String string = potion.getTranslated(type); if (basePotion.isUpgraded()) { string += " II" + potion.strongDuration; From 7f9349f583d6f28586c7b36a120a28c3c758a0c2 Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Tue, 21 Feb 2023 14:21:39 +0100 Subject: [PATCH 28/41] :loud_sound: Added more logging during player datas loading --- core/src/main/java/fr/skytasul/quests/QuestsListener.java | 5 ++++- .../java/fr/skytasul/quests/players/PlayersManager.java | 7 ++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/fr/skytasul/quests/QuestsListener.java b/core/src/main/java/fr/skytasul/quests/QuestsListener.java index f0fdaa0e..30e131b8 100644 --- a/core/src/main/java/fr/skytasul/quests/QuestsListener.java +++ b/core/src/main/java/fr/skytasul/quests/QuestsListener.java @@ -145,7 +145,10 @@ public void onOpen(InventoryOpenEvent e) { @EventHandler (priority = EventPriority.LOWEST) public void onJoin(PlayerJoinEvent e){ Player player = e.getPlayer(); - DebugUtils.logMessage(player.getName() + " joined the server"); // for timing purpose + + DebugUtils.logMessage(player.getName() + " (" + player.getUniqueId().toString() + ") joined the server"); + // for timing purpose + if (BeautyQuests.loaded && !QuestsConfiguration.hookAccounts()) { BeautyQuests.getInstance().getPlayersManager().loadPlayer(player); } diff --git a/core/src/main/java/fr/skytasul/quests/players/PlayersManager.java b/core/src/main/java/fr/skytasul/quests/players/PlayersManager.java index 66a9d3dd..f984b15f 100644 --- a/core/src/main/java/fr/skytasul/quests/players/PlayersManager.java +++ b/core/src/main/java/fr/skytasul/quests/players/PlayersManager.java @@ -177,9 +177,10 @@ private boolean tryLoad(Player p, long time) { cachedAccounts.put(p, request.getAccount()); Bukkit.getScheduler().runTask(BeautyQuests.getInstance(), () -> { - String loadMessage = "Completed load of " + p.getName() + " datas within " + (System.currentTimeMillis() - time) - + " ms (" + request.getAccount().getQuestsDatas().size() + " quests, " - + request.getAccount().getPoolDatas().size() + " pools)"; + 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(); From 59ba283d4011832b250abe3d0b6a83ef8536baae Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Wed, 1 Mar 2023 11:52:21 +0100 Subject: [PATCH 29/41] :bug: Fixed issues with some item comparisons --- .../quests/gui/misc/ItemComparisonGUI.java | 89 +++++++++++-------- 1 file changed, 52 insertions(+), 37 deletions(-) diff --git a/core/src/main/java/fr/skytasul/quests/gui/misc/ItemComparisonGUI.java b/core/src/main/java/fr/skytasul/quests/gui/misc/ItemComparisonGUI.java index 5b522a3e..8054b6ec 100644 --- a/core/src/main/java/fr/skytasul/quests/gui/misc/ItemComparisonGUI.java +++ b/core/src/main/java/fr/skytasul/quests/gui/misc/ItemComparisonGUI.java @@ -1,11 +1,11 @@ package fr.skytasul.quests.gui.misc; +import java.util.Objects; import org.bukkit.DyeColor; import org.bukkit.event.inventory.ClickType; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.Repairable; - import fr.skytasul.quests.api.QuestsAPI; import fr.skytasul.quests.api.comparison.ItemComparison; import fr.skytasul.quests.api.comparison.ItemComparisonMap; @@ -17,54 +17,69 @@ import fr.skytasul.quests.utils.XMaterial; public class ItemComparisonGUI extends PagedGUI { - + private ItemComparisonMap comparisons; - + public ItemComparisonGUI(ItemComparisonMap comparisons, Runnable validate) { - super(Lang.INVENTORY_ITEM_COMPARISONS.toString(), DyeColor.LIME, QuestsAPI.getItemComparisons(), x -> validate.run(), null); + super(Lang.INVENTORY_ITEM_COMPARISONS.toString(), DyeColor.LIME, QuestsAPI.getItemComparisons(), x -> validate.run(), + null); this.comparisons = comparisons; } - + @Override public ItemStack getItemStack(ItemComparison object) { - return ItemUtils.itemSwitch(object.getItemName(), comparisons.isEnabled(object), QuestOption.formatDescription(object.getItemDescription())); + return ItemUtils.itemSwitch(object.getItemName(), comparisons.isEnabled(object), + QuestOption.formatDescription(object.getItemDescription())); } @Override public void click(ItemComparison existing, ItemStack item, ClickType clickType) { ItemUtils.set(item, comparisons.toggle(existing)); } - + public static void initialize() { - QuestsAPI.registerItemComparison(new ItemComparison("bukkit", Lang.comparisonBukkit.toString(), Lang.comparisonBukkitLore.toString(), ItemStack::isSimilar).setEnabledByDefault()); - QuestsAPI.registerItemComparison(new ItemComparison("customBukkit", Lang.comparisonCustomBukkit.toString(), Lang.comparisonCustomBukkitLore.toString(), Utils::isSimilar)); - QuestsAPI.registerItemComparison(new ItemComparison("material", Lang.comparisonMaterial.toString(), Lang.comparisonMaterialLore.toString(), (item1, item2) -> { - if (item2.getType() != item1.getType()) return false; - if (item1.getType().getMaxDurability() > 0 || XMaterial.isNewVersion()) return true; - return item2.getDurability() == item1.getDurability(); - })); - QuestsAPI.registerItemComparison(new ItemComparison("name", Lang.comparisonName.toString(), Lang.comparisonNameLore.toString(), (item1, item2) -> { - ItemMeta meta1 = item1.getItemMeta(); - ItemMeta meta2 = item2.getItemMeta(); - return (meta1.hasDisplayName() == meta2.hasDisplayName()) && meta1.getDisplayName().equals(meta2.getDisplayName()); - }).setMetaNeeded()); - QuestsAPI.registerItemComparison(new ItemComparison("lore", Lang.comparisonLore.toString(), Lang.comparisonLoreLore.toString(), (item1, item2) -> { - ItemMeta meta1 = item1.getItemMeta(); - ItemMeta meta2 = item2.getItemMeta(); - return (meta1.hasLore() == meta2.hasLore()) && meta1.getLore().equals(meta2.getLore()); - }).setMetaNeeded()); - QuestsAPI.registerItemComparison(new ItemComparison("enchants", Lang.comparisonEnchants.toString(), Lang.comparisonEnchantsLore.toString(), (item1, item2) -> { - ItemMeta meta1 = item1.getItemMeta(); - ItemMeta meta2 = item2.getItemMeta(); - return (meta1.hasEnchants() == meta2.hasEnchants()) && meta1.getEnchants().equals(meta2.getEnchants()); - }).setMetaNeeded()); - QuestsAPI.registerItemComparison(new ItemComparison("repair", Lang.comparisonRepairCost.toString(), Lang.comparisonRepairCostLore.toString(), (item1, item2) -> { - ItemMeta meta1 = item1.getItemMeta(); - if (!(meta1 instanceof Repairable)) return true; - ItemMeta meta2 = item2.getItemMeta(); - if (!(meta2 instanceof Repairable)) return true; - return ((Repairable) meta1).getRepairCost() == ((Repairable) meta2).getRepairCost(); - }).setMetaNeeded()); + QuestsAPI.registerItemComparison(new ItemComparison("bukkit", Lang.comparisonBukkit.toString(), + Lang.comparisonBukkitLore.toString(), ItemStack::isSimilar).setEnabledByDefault()); + QuestsAPI.registerItemComparison(new ItemComparison("customBukkit", Lang.comparisonCustomBukkit.toString(), + Lang.comparisonCustomBukkitLore.toString(), Utils::isSimilar)); + QuestsAPI.registerItemComparison(new ItemComparison("material", Lang.comparisonMaterial.toString(), + Lang.comparisonMaterialLore.toString(), (item1, item2) -> { + if (item2.getType() != item1.getType()) + return false; + if (item1.getType().getMaxDurability() > 0 || XMaterial.isNewVersion()) + return true; + return item2.getDurability() == item1.getDurability(); + })); + QuestsAPI.registerItemComparison(new ItemComparison("name", Lang.comparisonName.toString(), + Lang.comparisonNameLore.toString(), (item1, item2) -> { + ItemMeta meta1 = item1.getItemMeta(); + ItemMeta meta2 = item2.getItemMeta(); + return (meta1.hasDisplayName() == meta2.hasDisplayName()) + && Objects.equals(meta1.getDisplayName(), meta2.getDisplayName()); + }).setMetaNeeded()); + QuestsAPI.registerItemComparison(new ItemComparison("lore", Lang.comparisonLore.toString(), + Lang.comparisonLoreLore.toString(), (item1, item2) -> { + ItemMeta meta1 = item1.getItemMeta(); + ItemMeta meta2 = item2.getItemMeta(); + return (meta1.hasLore() == meta2.hasLore()) && Objects.equals(meta1.getLore(), meta2.getLore()); + }).setMetaNeeded()); + QuestsAPI.registerItemComparison(new ItemComparison("enchants", Lang.comparisonEnchants.toString(), + Lang.comparisonEnchantsLore.toString(), (item1, item2) -> { + ItemMeta meta1 = item1.getItemMeta(); + ItemMeta meta2 = item2.getItemMeta(); + return (meta1.hasEnchants() == meta2.hasEnchants()) + && Objects.equals(meta1.getEnchants(), meta2.getEnchants()); + }).setMetaNeeded()); + QuestsAPI.registerItemComparison(new ItemComparison("repair", Lang.comparisonRepairCost.toString(), + Lang.comparisonRepairCostLore.toString(), (item1, item2) -> { + ItemMeta meta1 = item1.getItemMeta(); + if (!(meta1 instanceof Repairable)) + return true; + ItemMeta meta2 = item2.getItemMeta(); + if (!(meta2 instanceof Repairable)) + return true; + return ((Repairable) meta1).getRepairCost() == ((Repairable) meta2).getRepairCost(); + }).setMetaNeeded()); } - + } From 82143efddab63645474680ede29e91821d8c5362 Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Thu, 2 Mar 2023 10:21:39 +0100 Subject: [PATCH 30/41] :bug: Fixed hex colors not working in scoreboards --- .../quests/scoreboards/ScoreboardLine.java | 43 ++++++++++--------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/core/src/main/java/fr/skytasul/quests/scoreboards/ScoreboardLine.java b/core/src/main/java/fr/skytasul/quests/scoreboards/ScoreboardLine.java index f1329933..bf6209a9 100644 --- a/core/src/main/java/fr/skytasul/quests/scoreboards/ScoreboardLine.java +++ b/core/src/main/java/fr/skytasul/quests/scoreboards/ScoreboardLine.java @@ -1,42 +1,45 @@ package fr.skytasul.quests.scoreboards; import java.util.Map; - import org.apache.commons.lang.Validate; +import fr.skytasul.quests.utils.ChatUtils; +import net.md_5.bungee.api.ChatColor; public class ScoreboardLine { private String value; private int refresh = 0; private int length = 0; - - public ScoreboardLine(String value){ + + public ScoreboardLine(String value) { Validate.notNull(value); - this.value = value - .replace("&", "§") - .replace("{questName}", "{quest_name}") - .replace("{questDescription}", "{quest_advancement}"); + this.value = ChatColor.translateAlternateColorCodes('&', + ChatUtils.translateHexColorCodes(value + .replace("{questName}", "{quest_name}") + .replace("{questDescription}", "{quest_advancement}"))); } - - public String getValue(){ + + public String getValue() { return value; } - - public int getRefreshTime(){ + + public int getRefreshTime() { return refresh; } - - public int getMaxLength(){ + + public int getMaxLength() { return length; } - - public static ScoreboardLine deserialize(Map map){ + + public static ScoreboardLine deserialize(Map map) { ScoreboardLine line = new ScoreboardLine((String) map.get("value")); - - if (map.containsKey("refresh")) line.refresh = (int) map.get("refresh"); - if (map.containsKey("length")) line.length = (int) map.get("length"); - + + if (map.containsKey("refresh")) + line.refresh = (int) map.get("refresh"); + if (map.containsKey("length")) + line.length = (int) map.get("length"); + return line; } - + } From 61b18ffda2fe391bd486ee3bbadbbd7ca5f98fe4 Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Sat, 11 Mar 2023 15:54:39 +0100 Subject: [PATCH 31/41] :art: Updated logger to UTF-8 + fixed bad code --- .../quests/utils/logger/LoggerHandler.java | 18 +++++++----------- .../skytasul/quests/utils/types/BQBlock.java | 2 +- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/core/src/main/java/fr/skytasul/quests/utils/logger/LoggerHandler.java b/core/src/main/java/fr/skytasul/quests/utils/logger/LoggerHandler.java index b4493c41..2ce7dc39 100644 --- a/core/src/main/java/fr/skytasul/quests/utils/logger/LoggerHandler.java +++ b/core/src/main/java/fr/skytasul/quests/utils/logger/LoggerHandler.java @@ -1,12 +1,13 @@ package fr.skytasul.quests.utils.logger; -import java.io.File; -import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.StandardCopyOption; +import java.nio.file.StandardOpenOption; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; @@ -15,10 +16,8 @@ import java.util.logging.Formatter; import java.util.logging.Handler; import java.util.logging.LogRecord; - import org.bukkit.plugin.Plugin; import org.bukkit.scheduler.BukkitRunnable; - import fr.skytasul.quests.BeautyQuests; import fr.skytasul.quests.utils.Utils; @@ -26,7 +25,6 @@ public class LoggerHandler extends Handler implements ILoggerHandler { private final Date launchDate = new Date(); - private final File file; private PrintWriter stream; private SimpleDateFormat format = new SimpleDateFormat("[HH:mm:ss] "); @@ -45,12 +43,10 @@ public String format(LogRecord record) { } }); - file = new File(plugin.getDataFolder(), "latest.log"); - if (file.exists()) { - Files.move(file.toPath(), new File(plugin.getDataFolder(), "latest.log_old").toPath(), StandardCopyOption.REPLACE_EXISTING); - } - Files.createFile(file.toPath()); - stream = new PrintWriter(new FileWriter(file)); + Path path = plugin.getDataFolder().toPath().resolve("latest.log"); + if (Files.exists(path)) + Files.move(path, plugin.getDataFolder().toPath().resolve("latest.log_old"), StandardCopyOption.REPLACE_EXISTING); + stream = new PrintWriter(Files.newBufferedWriter(path, StandardCharsets.UTF_8, StandardOpenOption.CREATE_NEW)); write("---- BEAUTYQUESTS LOGGER - OPENED " + launchDate.toString() + " ----"); } diff --git a/core/src/main/java/fr/skytasul/quests/utils/types/BQBlock.java b/core/src/main/java/fr/skytasul/quests/utils/types/BQBlock.java index 3f0a0bb8..87e592ae 100644 --- a/core/src/main/java/fr/skytasul/quests/utils/types/BQBlock.java +++ b/core/src/main/java/fr/skytasul/quests/utils/types/BQBlock.java @@ -136,7 +136,7 @@ public Located next() { throw new NoSuchElementException(); } - }, Spliterator.ORDERED & Spliterator.IMMUTABLE & Spliterator.DISTINCT & Spliterator.NONNULL); + }, Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.DISTINCT | Spliterator.NONNULL); } public static class BQBlockMaterial extends BQBlock { From 83042b68f9226eacbdb9d8c3b894ffe42074e4a0 Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Sat, 11 Mar 2023 15:55:15 +0100 Subject: [PATCH 32/41] :loud_sound: :goal_net: Added logging + caught data-related errors --- .../quests/gui/creation/FinishGUI.java | 2 ++ .../quests/players/PlayersManagerDB.java | 18 ++++++++++-------- .../fr/skytasul/quests/structure/Quest.java | 9 +++++++-- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/fr/skytasul/quests/gui/creation/FinishGUI.java b/core/src/main/java/fr/skytasul/quests/gui/creation/FinishGUI.java index 32748e26..de900349 100644 --- a/core/src/main/java/fr/skytasul/quests/gui/creation/FinishGUI.java +++ b/core/src/main/java/fr/skytasul/quests/gui/creation/FinishGUI.java @@ -170,6 +170,8 @@ private void finish(){ boolean keepPlayerDatas = Boolean.TRUE.equals(this.keepPlayerDatas); Quest qu; if (session.isEdition()) { + DebugUtils.logMessage( + "Editing quest " + session.getQuestEdited().getID() + " with keep datas: " + keepPlayerDatas); session.getQuestEdited().remove(false, false); qu = new Quest(session.getQuestEdited().getID(), session.getQuestEdited().getFile()); }else { diff --git a/core/src/main/java/fr/skytasul/quests/players/PlayersManagerDB.java b/core/src/main/java/fr/skytasul/quests/players/PlayersManagerDB.java index ff48d726..03f07093 100644 --- a/core/src/main/java/fr/skytasul/quests/players/PlayersManagerDB.java +++ b/core/src/main/java/fr/skytasul/quests/players/PlayersManagerDB.java @@ -243,7 +243,6 @@ public CompletableFuture playerPoolDataRemoved(PlayerPoolDatas datas) { @Override public CompletableFuture removeQuestDatas(Quest quest) { return CompletableFuture.supplyAsync(() -> { - int amount = 0; try (Connection connection = db.getConnection(); PreparedStatement statement = connection.prepareStatement(removeExistingQuestDatas)) { for (PlayerAccount acc : cachedAccounts.values()) { @@ -251,12 +250,12 @@ public CompletableFuture removeQuestDatas(Quest quest) { if (datas != null) datas.stop(); } statement.setInt(1, quest.getID()); - amount += statement.executeUpdate(); + int amount = statement.executeUpdate(); + DebugUtils.logMessage("Removed " + amount + " in-database quest datas for quest " + quest.getID()); + return amount; } catch (SQLException ex) { throw new DataException("Failed to remove quest datas from database.", ex); } - DebugUtils.logMessage("Removed " + amount + " quest datas for quest " + quest.getID()); - return amount; }); } @@ -639,7 +638,7 @@ public void run() { BeautyQuests.logger.warning("Setting an illegal NULL value in statement \"" + dataStatement + "\" for account " + acc.index + " and quest " + questID); } } - }catch (SQLException ex) { + } catch (Exception ex) { BeautyQuests.logger.severe("An error occurred while updating a player's quest datas.", ex); }finally { dbLock.unlock(); @@ -695,13 +694,16 @@ protected void stop() { private void createDataRow(Connection connection) throws SQLException { DebugUtils.logMessage("Inserting DB row of quest " + questID + " for account " + acc.index); - try (PreparedStatement insertStatement = connection.prepareStatement(insertQuestData, Statement.RETURN_GENERATED_KEYS)) { + try (PreparedStatement insertStatement = connection.prepareStatement(insertQuestData, new String[] {"id"})) { insertStatement.setInt(1, acc.index); insertStatement.setInt(2, questID); insertStatement.setQueryTimeout(DATA_QUERY_TIMEOUT); - insertStatement.executeUpdate(); + int affectedLines = insertStatement.executeUpdate(); + if (affectedLines != 1) + throw new DataException("No row inserted"); ResultSet generatedKeys = insertStatement.getGeneratedKeys(); - generatedKeys.next(); + if (!generatedKeys.next()) + throw new DataException("Generated keys ResultSet is empty"); dbId = generatedKeys.getInt(1); DebugUtils.logMessage("Created row " + dbId + " for quest " + questID + ", account " + acc.index); } diff --git a/core/src/main/java/fr/skytasul/quests/structure/Quest.java b/core/src/main/java/fr/skytasul/quests/structure/Quest.java index 6e66de45..9d229e0b 100644 --- a/core/src/main/java/fr/skytasul/quests/structure/Quest.java +++ b/core/src/main/java/fr/skytasul/quests/structure/Quest.java @@ -207,6 +207,10 @@ public boolean cancelPlayer(PlayerAccount acc) { return false; DebugUtils.logMessage("Cancelling quest " + id + " for player " + acc.getNameAndID()); + return true; + } + + private void cancelInternal(PlayerAccount acc) { manager.remove(acc); QuestsAPI.propagateQuestsHandlers(handler -> handler.questReset(acc, this)); Bukkit.getPluginManager().callEvent(new PlayerQuestResetEvent(acc, this)); @@ -218,7 +222,6 @@ public boolean cancelPlayer(PlayerAccount acc) { BeautyQuests.logger.warning("Trying to interrupt branching in a cancel reward (useless). " + toString()); } } - return true; } public CompletableFuture resetPlayer(PlayerAccount acc){ @@ -230,7 +233,9 @@ public CompletableFuture resetPlayer(PlayerAccount acc){ if (acc.hasQuestDatas(this)) { hadDatas = true; - cancelPlayer(acc); + + DebugUtils.logMessage("Resetting quest " + id + " for player " + acc.getNameAndID()); + cancelInternal(acc); future = acc.removeQuestDatas(this); } From b6687bfc4a28ed2686f7b7f208665720b72f2249 Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Sun, 12 Mar 2023 15:36:52 +0100 Subject: [PATCH 33/41] :sparkles: Added "/quests pools start" command * moved "/quests resetPlayerPool" to "/quests pools resetPlayer" --- .../quests/commands/CommandsAdmin.java | 9 ---- .../quests/commands/CommandsManager.java | 1 + .../commands/CommandsPlayerManagement.java | 15 ------ .../quests/commands/CommandsPools.java | 54 +++++++++++++++++++ .../quests/structure/pools/QuestPool.java | 10 +--- .../java/fr/skytasul/quests/utils/Lang.java | 2 + core/src/main/resources/locales/en_US.yml | 3 ++ core/src/main/resources/plugin.yml | 5 ++ 8 files changed, 67 insertions(+), 32 deletions(-) create mode 100644 core/src/main/java/fr/skytasul/quests/commands/CommandsPools.java diff --git a/core/src/main/java/fr/skytasul/quests/commands/CommandsAdmin.java b/core/src/main/java/fr/skytasul/quests/commands/CommandsAdmin.java index b0df6f61..6f12fa6f 100644 --- a/core/src/main/java/fr/skytasul/quests/commands/CommandsAdmin.java +++ b/core/src/main/java/fr/skytasul/quests/commands/CommandsAdmin.java @@ -9,14 +9,12 @@ import java.nio.channels.ReadableByteChannel; import java.nio.file.Path; import java.sql.SQLException; - import org.bukkit.Material; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.FireworkMeta; import org.bukkit.inventory.meta.ItemMeta; - import fr.skytasul.quests.BeautyQuests; import fr.skytasul.quests.api.QuestsAPI; import fr.skytasul.quests.api.npcs.BQNPC; @@ -26,7 +24,6 @@ import fr.skytasul.quests.gui.creation.QuestCreationSession; import fr.skytasul.quests.gui.misc.ConfirmGUI; import fr.skytasul.quests.gui.misc.ListBook; -import fr.skytasul.quests.gui.pools.PoolsManageGUI; import fr.skytasul.quests.gui.quests.ChooseQuestGUI; import fr.skytasul.quests.players.AdminMode; import fr.skytasul.quests.players.PlayersManager; @@ -38,7 +35,6 @@ import fr.skytasul.quests.utils.MinecraftNames; import fr.skytasul.quests.utils.Utils; import fr.skytasul.quests.utils.nms.NMS; - import revxrsal.commands.annotation.Flag; import revxrsal.commands.annotation.Optional; import revxrsal.commands.annotation.SecretCommand; @@ -122,11 +118,6 @@ private void remove(CommandSender sender, Quest quest) { } } - @Subcommand ("pools") - @CommandPermission ("beautyquests.command.pools") - public void pools(Player player) { - PoolsManageGUI.get().create(player); - } @Subcommand ("reload") @CommandPermission ("beautyquests.command.manage") diff --git a/core/src/main/java/fr/skytasul/quests/commands/CommandsManager.java b/core/src/main/java/fr/skytasul/quests/commands/CommandsManager.java index d5e2a1bc..e3c25e64 100644 --- a/core/src/main/java/fr/skytasul/quests/commands/CommandsManager.java +++ b/core/src/main/java/fr/skytasul/quests/commands/CommandsManager.java @@ -114,6 +114,7 @@ public void initializeCommands() { registerCommands("", new CommandsAdmin(), new CommandsPlayer(), new CommandsPlayerManagement()); registerCommands("scoreboard", new CommandsScoreboard()); + registerCommands("pools", new CommandsPools()); } public void registerCommands(String subpath, OrphanCommand... commands) { 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 24fcdfc2..4ee1d8f8 100644 --- a/core/src/main/java/fr/skytasul/quests/commands/CommandsPlayerManagement.java +++ b/core/src/main/java/fr/skytasul/quests/commands/CommandsPlayerManagement.java @@ -235,21 +235,6 @@ private void reset(CommandSender sender, Player target, PlayerAccount acc, Quest }, "An error occurred while removing player quest data", sender)); } - @Subcommand ("resetPlayerPool") - @CommandPermission ("beautyquests.command.resetPlayer") - public void resetPlayerPool(BukkitCommandActor actor, Player player, QuestPool pool, @Switch boolean timer) { - PlayerAccount acc = PlayersManager.getPlayerAccount(player); - if (timer) { - pool.resetPlayerTimer(acc); - Lang.POOL_RESET_TIMER.send(actor.getSender(), pool.getID(), player.getName()); - }else { - pool.resetPlayer(acc).whenComplete(BeautyQuests.logger.logError(__ -> { - Lang.POOL_RESET_FULL.send(actor.getSender(), pool.getID(), player.getName()); - }, "An error occurred while resetting pool " + pool.getID() + " to player " + player.getName(), - actor.getSender())); - } - } - @Subcommand ("resetQuest") @CommandPermission ("beautyquests.command.resetQuest") public void resetQuest(BukkitCommandActor actor, 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 new file mode 100644 index 00000000..dfd098c3 --- /dev/null +++ b/core/src/main/java/fr/skytasul/quests/commands/CommandsPools.java @@ -0,0 +1,54 @@ +package fr.skytasul.quests.commands; + +import org.bukkit.entity.Player; +import fr.skytasul.quests.BeautyQuests; +import fr.skytasul.quests.gui.pools.PoolsManageGUI; +import fr.skytasul.quests.players.PlayerAccount; +import fr.skytasul.quests.players.PlayersManager; +import fr.skytasul.quests.structure.pools.QuestPool; +import fr.skytasul.quests.utils.Lang; +import revxrsal.commands.annotation.Default; +import revxrsal.commands.annotation.Subcommand; +import revxrsal.commands.annotation.Switch; +import revxrsal.commands.bukkit.BukkitCommandActor; +import revxrsal.commands.bukkit.annotation.CommandPermission; +import revxrsal.commands.orphan.OrphanCommand; + +public class CommandsPools implements OrphanCommand { + + @Default + @CommandPermission("beautyquests.command.pools") + public void pools(Player player) { + PoolsManageGUI.get().create(player); + } + + @Subcommand("resetPlayer") + @CommandPermission("beautyquests.command.resetPlayer") + public void resetPlayerPool(BukkitCommandActor actor, Player player, QuestPool pool, @Switch boolean timer) { + PlayerAccount acc = PlayersManager.getPlayerAccount(player); + if (timer) { + pool.resetPlayerTimer(acc); + Lang.POOL_RESET_TIMER.send(actor.getSender(), pool.getID(), player.getName()); + } else { + pool.resetPlayer(acc).whenComplete(BeautyQuests.logger.logError(__ -> { + Lang.POOL_RESET_FULL.send(actor.getSender(), pool.getID(), player.getName()); + }, "An error occurred while resetting pool " + pool.getID() + " to player " + player.getName(), + actor.getSender())); + } + } + + @Subcommand("start") + @CommandPermission("beautyquests.command.pools.start") + public void start(BukkitCommandActor actor, Player player, QuestPool pool) { + PlayerAccount acc = PlayersManager.getPlayerAccount(player); + + if (!pool.canGive(player, acc)) { + Lang.POOL_START_ERROR.send(player, pool.getID(), player.getName()); + return; + } + + String result = pool.give(player); + Lang.POOL_START_SUCCESS.send(player, pool.getID(), player.getName(), result); + } + +} diff --git a/core/src/main/java/fr/skytasul/quests/structure/pools/QuestPool.java b/core/src/main/java/fr/skytasul/quests/structure/pools/QuestPool.java index c175fc9c..507e2f79 100644 --- a/core/src/main/java/fr/skytasul/quests/structure/pools/QuestPool.java +++ b/core/src/main/java/fr/skytasul/quests/structure/pools/QuestPool.java @@ -191,24 +191,19 @@ public String give(Player p) { if (notCompleted.isEmpty()) { // all quests completed notCompleted = replenishQuests(datas); if (notCompleted.isEmpty()) { - //System.out.println("QuestPool.give() not completed empty"); if (started.isEmpty()) return Lang.POOL_ALL_COMPLETED.toString(); break; } }else if (acc.getQuestsDatas().stream().filter(quest -> quest.hasStarted() && quests.contains(quest.getQuest())).count() >= maxQuests) { - //System.out.println("QuestPool.give() max"); if (started.isEmpty()) return Lang.POOL_MAX_QUESTS.format(maxQuests); break; } List notStarted = notCompleted.stream().filter(quest -> !quest.hasStarted(acc)).collect(Collectors.toList()); - //System.out.println("QuestPool.give() not completed " + notCompleted.stream().map(x -> Integer.toString(x.getID())).collect(Collectors.joining(" "))); if (notStarted.isEmpty()) notStarted = replenishQuests(datas); - //System.out.println("QuestPool.give() not started " + notStarted.stream().map(x -> Integer.toString(x.getID())).collect(Collectors.joining(" "))); List available = notStarted.stream().filter(quest -> quest.isLauncheable(p, acc, false)).collect(Collectors.toList()); if (available.isEmpty()) { - //System.out.println("QuestPool.give() no available"); if (started.isEmpty()) return Lang.POOL_NO_AVAILABLE.toString(); break; }else { @@ -224,11 +219,10 @@ public String give(Player p) { }); } } - //return "started quest(s) #" + started.stream().map(x -> Integer.toString(x.getID())).collect(Collectors.joining(", ")); - return null; + return "started quest(s) " + started.stream().map(x -> "#" + x.getID()).collect(Collectors.joining(", ")); } - List replenishQuests(PlayerPoolDatas datas) { + private List replenishQuests(PlayerPoolDatas datas) { if (!redoAllowed) return Collections.emptyList(); List notDoneQuests = quests.stream() .filter(Quest::isRepeatable) diff --git a/core/src/main/java/fr/skytasul/quests/utils/Lang.java b/core/src/main/java/fr/skytasul/quests/utils/Lang.java index 624cd4b9..c0eea28e 100644 --- a/core/src/main/java/fr/skytasul/quests/utils/Lang.java +++ b/core/src/main/java/fr/skytasul/quests/utils/Lang.java @@ -143,6 +143,8 @@ public enum Lang implements Locale { ADMIN_MODE_LEFT("msg.command.adminModeLeft"), POOL_RESET_TIMER("msg.command.resetPlayerPool.timer"), // 0: pool ID, 1: player POOL_RESET_FULL("msg.command.resetPlayerPool.full"), // 0: pool ID, 1: player + POOL_START_ERROR("msg.command.startPlayerPool.error", ErrorPrefix), // 0: pool ID, 1: player + POOL_START_SUCCESS("msg.command.startPlayerPool.success", SuccessPrefix), // 0: pool ID, 1: player, 2: result COMMAND_SCOREBOARD_LINESET("msg.command.scoreboard.lineSet"), // 0: line id COMMAND_SCOREBOARD_LINERESET("msg.command.scoreboard.lineReset"), // 0: line id diff --git a/core/src/main/resources/locales/en_US.yml b/core/src/main/resources/locales/en_US.yml index eedb7e2a..4d5f0af0 100644 --- a/core/src/main/resources/locales/en_US.yml +++ b/core/src/main/resources/locales/en_US.yml @@ -161,6 +161,9 @@ msg: resetPlayerPool: timer: §aYou have reset the {0} pool timer of {1}. full: §aYou have reset the {0} pool datas of {1}. + startPlayerPool: + error: 'Failed to start the pool {0} for {1}.' + success: 'Started pool {0} to {1}. Result: {2}' scoreboard: lineSet: §6You have successfully edited the line {0}. lineReset: §6You have successfully reset the line {0}. diff --git a/core/src/main/resources/plugin.yml b/core/src/main/resources/plugin.yml index 4d14b193..e3653010 100644 --- a/core/src/main/resources/plugin.yml +++ b/core/src/main/resources/plugin.yml @@ -80,6 +80,8 @@ permissions: beautyquests.command.scoreboard: true beautyquests.command.scoreboard.toggle: true beautyquests.command.checkpoint: true + beautyquests.command.pools: true + beautyquests.command.pools.start: true beautyquests.command.listPlayer: decription: 'Gives access to the menu GUI' default: true @@ -146,6 +148,9 @@ permissions: beautyquests.command.pools: description: 'Gives access to "/quests pools"' default: op + beautyquests.command.pools.start: + description: 'Gives access to "/quests pools start"' + default: op beautyquests.command.checkpoint: description: 'Allows player to use checkpoints' default: true From 96d5026e269eb8dc22aa4e98e410bb822842e882 Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Sun, 12 Mar 2023 16:15:17 +0100 Subject: [PATCH 34/41] :arrow_up: Upgraded UltimateTimber to 2.3.5 --- core/libs.sh | 2 +- core/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/libs.sh b/core/libs.sh index 91882d9a..e00499bb 100644 --- a/core/libs.sh +++ b/core/libs.sh @@ -23,7 +23,7 @@ echo -e "Maven path: $mavenPath\e[39m" "$mavenPath" install:install-file -Dfile=$jarsPath/Boss.jar -DgroupId=org.mineacademy -DartifactId=boss -Dversion=4.2.1 -Dpackaging=jar "$mavenPath" install:install-file -Dfile=$jarsPath/CMI.jar -DgroupId=com.zrips -DartifactId=cmi -Dversion=9.0.2.1 -Dpackaging=jar "$mavenPath" install:install-file -Dfile=$jarsPath/CMILib.jar -DgroupId=com.zrips -DartifactId=cmilib -Dversion=1.2.3.3 -Dpackaging=jar -"$mavenPath" install:install-file -Dfile=$jarsPath/UltimateTimber.jar -DgroupId=com.songoda -DartifactId=ultimatetimber -Dversion=2.2.5 -Dpackaging=jar +"$mavenPath" install:install-file -Dfile=$jarsPath/UltimateTimber.jar -DgroupId=com.songoda -DartifactId=ultimatetimber -Dversion=2.3.5 -Dpackaging=jar "$mavenPath" install:install-file -Dfile=$jarsPath/AdvancedSpawners-API.jar -DgroupId=gcspawners -DartifactId=gcspawners -Dversion=3.3.0 -Dpackaging=jar #"$mavenPath" install:install-file -Dfile=$jarsPath/MythicMobs.jar -DgroupId=io.lumine.xikage -DartifactId=MythicMobs -Dversion=4.12.0 -Dpackaging=jar #"$mavenPath" install:install-file -Dfile=$jarsPath/TokenEnchantAPI.jar -DgroupId=com.vk2gpz.tokenenchant -DartifactId=TokenEnchantAPI -Dversion=18.15.2 -Dpackaging=jar diff --git a/core/pom.xml b/core/pom.xml index ba21a8ae..db42cfd0 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -327,7 +327,7 @@ com.songoda ultimatetimber - 2.2.5 + 2.3.5 provided From 0aad64e53568bec2c14faa09d4e064b28c5c8808 Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Sun, 12 Mar 2023 16:15:42 +0100 Subject: [PATCH 35/41] :globe_with_meridians: Updated FR, DE, PL, RU and CN + added PT_BR translations! --- core/src/main/resources/config.yml | 2 +- core/src/main/resources/locales/de_DE.yml | 24 + core/src/main/resources/locales/fr_FR.yml | 5 + core/src/main/resources/locales/pl_PL.yml | 142 +++- core/src/main/resources/locales/pt_BR.yml | 834 ++++++++++++++++++++++ core/src/main/resources/locales/ru_RU.yml | 93 +++ core/src/main/resources/locales/zh_CN.yml | 3 + 7 files changed, 1097 insertions(+), 6 deletions(-) create mode 100644 core/src/main/resources/locales/pt_BR.yml diff --git a/core/src/main/resources/config.yml b/core/src/main/resources/config.yml index 9a3f1b97..b478f530 100644 --- a/core/src/main/resources/config.yml +++ b/core/src/main/resources/config.yml @@ -1,7 +1,7 @@ # - General configuration - # Number of minutes before the quest can be redone redoMinuts: 5 -# Chosen lang (file name) Available by default: fr_FR, en_US, zh_CN, zh_HK, de_DE, it_IT, es_ES, pt_PT, sv_SE, hu_HU, ru_RU, pl_PL, th_TH, lt_LT, vi_VN +# Chosen lang (file name) Available by default: fr_FR, en_US, zh_CN, zh_HK, de_DE, it_IT, es_ES, pt_PT, pt_BR, sv_SE, hu_HU, ru_RU, pl_PL, th_TH, lt_LT, vi_VN lang: en_US # (1.13 and above) Minecraft vanilla translations (JSON file name). Some can be found on SkytAsul's Discord server minecraftTranslationsFile: '' diff --git a/core/src/main/resources/locales/de_DE.yml b/core/src/main/resources/locales/de_DE.yml index d78f5ec0..0c1ab366 100644 --- a/core/src/main/resources/locales/de_DE.yml +++ b/core/src/main/resources/locales/de_DE.yml @@ -13,6 +13,7 @@ msg: invalidID: '§cDie Quest mit der ID {0} existiert nicht.' invalidPoolID: '§cDie Gruppe {0} existiert nicht.' alreadyStarted: '§cDu hast die Quest bereits gestartet!' + notStarted: '§cDu machst diese Quest momentan nicht.' quests: maxLaunched: '§cDu kannst nicht mehr als {0} Quest(s) gleichzeitig haben...' nopStep: '§cDiese Quest hat keinen Schritt.' @@ -40,6 +41,7 @@ msg: 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 wünschst, oder "none", wenn du dir keine Nachricht wünschst. Du kannst "{0}" verwenden, das dann durch die erhaltenen 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:' moveToTeleportPoint: '§aGehe zur gewünschten Teleportationsposition.' @@ -73,6 +75,7 @@ msg: negative: '§cDu musst eine positive Zahl eingeben!' zero: '§cDie Zahl darf nicht 0 sein!' invalid: '§c{0} ist keine gültige Zahl.' + notInBounds: '§cDeine Zahl muss zwischen {0} und {1} liegen.' errorOccurred: '§cEin Fehler ist aufgetreten; kontaktiere einen Administrator! §4§lFehlercode: {0}' commandsDisabled: '§cDu kannst zurzeit keine Befehle ausführen!' indexOutOfBounds: '§cDie Zahl {0} ist außerhalb der Grenze! Sie muss zwischen {1} und {2} liegen.' @@ -82,13 +85,17 @@ msg: inventoryFull: '§cDein Inventar ist voll, das Item wurde auf den Boden gelegt.' playerNeverConnected: '§cKann keine Informationen über den Spieler {0} finden.' playerNotOnline: '§cDer Spieler {0} ist offline.' + playerDataNotFound: '§cDaten des Spielers {0} nicht gefunden.' versionRequired: 'Benötigte Version: §l{0}' + restartServer: '§7Starte deinen Server neu, um die Änderungen zu sehen.' dialogs: skipped: 'Dialog übersprungen.' + tooFar: '§7§oDu bist zu weit von {0}...' command: downloadTranslations: syntax: "§cDu musst eine Sprache auswählen zum downloaden.\nBeispiel: \"/quests downloadTranslations en_US\"." notFound: '§cSprache {0} nicht gefunden für die Version {1}.' + exists: '§cDie Datei {0} existiert bereits. Füge "-Overwrite "true" an deinen Befehl an, um ihn zu überschreiben. (/quests downloadTranslations -overwrite true)' downloaded: '§aSprache {0} wurde heruntergeladen! §7Du musst nun die Datei "/plugins/BeautyQuests/config.yml" bearbeiten, um den Wert von §ominecraftTranslationsFile§7 mit {0} zu ändern. Der Server muss anschliessend neu gestartet werden.' checkpoint: noCheckpoint: '§cKein Checkpoint für die Quest {0} gefunden.' @@ -99,6 +106,11 @@ msg: next: '§aDer Schritt wurde übersprungen.' nextUnavailable: '§cDie „Überspringen“‐Option ist nicht verfügbar, wenn der Spieler am Ende eines Zweiges ist.' set: '§aSchritt {0} gestartet.' + startDialog: + impossible: '§cKann den Dialog jetzt nicht starten.' + noDialog: '§cDer Spieler hat keinen ausstehenden Dialog.' + alreadyIn: '§cDer Spieler spielt bereits einen Dialog.' + success: '§aStartete Dialog für Spieler {0} in Quest {1}!' playerNeeded: '§cDu musst ein Spieler sein, um diesen Befehl ausführen zu können.' incorrectSyntax: '§cFalsche Syntax.' noPermission: '§cDu hast nicht die benötigte Berechtigung „{0}“, um diesen Befehl auszuführen!' @@ -118,6 +130,7 @@ msg: remover: '§6{0} Questinformation(en) von {1} wurde(n) gelöscht.' resetQuest: '§6Quest Daten wurden für {0} Spieler entfernt.' startQuest: '§6Du hast den Start der Quest {0} erzwungen. (Spieler‐UUID: {1})' + startQuestNoRequirements: '§cDer Spieler erfüllt nicht die Anforderungen für die Quest {0}... Füge "-OverrideRequirements am Ende deines Befehls hinzu, um die Anforderungsüberprüfung zu umgehen.' cancelQuest: '§6Du hast die Quest {0} abgebrochen.' cancelQuestUnavailable: '§cDie Quest {0} kann nicht abgebrochen werden.' backupCreated: '§6Du hast erfolgreich Sicherungen aller Quests und Spielerinformationen erstellt.' @@ -137,6 +150,7 @@ msg: hidden: '§6Das Scoreboard des Spielers {0} wurde versteckt.' shown: '§6Das Scoreboard des Spielers {0} wurde angezeigt.' own: + hidden: '§6Dein Scoreboard ist jetzt versteckt.' shown: Dein Scoreboard wird wieder angezeigt. help: header: '§6§lBeautyQuests — Hilfe' @@ -145,14 +159,17 @@ msg: remove: '§6/{0} remove : §eLösche eine Quest mit der angegebenen ID oder klicke auf den NPC, wenn nicht definiert.' finishAll: '§6/{0} finishAll : §eBeende alle Quests eines Spielers.' setStage: '§6/{0} setStage [neuer Zweig] [neuer Schritt]: §eÜberspringe den aktuellen Schritt/starte einen Zweig/setze einen Schritt für einen Zweig.' + startDialog: '§6/{0} startDialog : §eStartet den ausstehenden Dialog für eine NPC-Stufe oder den Startdialog für eine Quest.' resetPlayer: '§6/{0} resetPlayer : §eEntferne alle Informationen eines Spielers.' resetPlayerQuest: '§6/{0} resetPlayerQuest [ID]: §eLösche Informationen einer Quest für einen Spieler.' seePlayer: '§6/{0} seePlayer : §eSieh dir die Informationen eines Spielers an.' reload: '§6/{0} reload: §eSpeichere und und lade alle Konfigurationen und Dateien neu. (§cveraltet§e)' start: '§6/{0} start [ID]: §eErzwinge das Starten einer Quest.' setItem: '§6/{0} setItem : §eSpeichere das Hologramm‐Item.' + setFirework: '§6/{0} SetFeuerwerk: §eBearbeite das standardmäßig end Feuerwerk.' adminMode: '§6/{0} adminMode: §eSchalte den Admin‐Modus (für die Anzeige von Protokollnachrichten) für dich um.' version: '§6/{0} version: §eLass dir die aktuelle Plugin‐Version anzeigen.' + downloadTranslations: '§6/{0} heruntergeladene Übersetzung : §eDownloads einer Vanille-Übersetzungsdatei' save: '§6/{0} save: §eFühre eine manuelle Plugin‐Speicherung durch.' list: '§6/{0} list: §eSieh dir die Questliste an. (Funktioniert nur bei unterstützten Versionen.)' typeCancel: '§aSchreibe „cancel“, um zum letzten Text zurückzukehren.' @@ -162,10 +179,14 @@ msg: blockData: '§aSchreibe die Blockdaten (verfügbare Blockdaten: {0}):' blockTag: '§aSchreibe den Blocktag (verfügbare Blocktags: §7{0}§a):' typeBucketAmount: '§aSchreibe die Anzahl an zu füllenden Eimern:' + typeDamageAmount: 'Schreibe die Menge an Schaden, die der Spieler zufügen muss:' goToLocation: '§aGehe zur gewünschten Position für den Schritt.' typeLocationRadius: '§aSchreibe die benötigte Distanz von der Position:' typeGameTicks: '§aSchreibe die benötigten Spiel-Ticks:' already: '§cDu befindest dich bereits im Editor.' + stage: + location: + typeWorldPattern: '§aSchreibe einen Regex für Weltnamen:' enter: title: '§6~ Editor‐Modus ~' subtitle: '§6Schreibe „/quests exitEditor”, um das Verlassen zu erzwingen.' @@ -233,11 +254,14 @@ msg: close: '§6close: §eBestätige alle Nachrichten.' setTime: '§6setTime + + ${project.groupId} + beautyquests-v1_19_R3 + ${project.version} + jar + compile + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 2c4f3611..e2f7ce01 100644 --- a/pom.xml +++ b/pom.xml @@ -42,6 +42,7 @@ v1_18_R2 v1_19_R1 v1_19_R2 + v1_19_R3 dist diff --git a/v1_19_R3/pom.xml b/v1_19_R3/pom.xml new file mode 100644 index 00000000..f1626a99 --- /dev/null +++ b/v1_19_R3/pom.xml @@ -0,0 +1,80 @@ + + + 4.0.0 + jar + beautyquests-v1_19_R3 + + fr.skytasul + beautyquests-parent + 0.20.1-SNAPSHOT + + + + true + 17 + 17 + + + + + jitpack.io + https://jitpack.io + + + + + + fr.skytasul + beautyquests-core + ${project.version} + provided + + + org.spigotmc + spigot + 1.19.4-R0.1-SNAPSHOT + remapped-mojang + provided + + + + + + + net.md-5 + specialsource-maven-plugin + 1.2.4 + + + package + + remap + + remap-obf + + org.spigotmc:minecraft-server:1.19.4-R0.1-SNAPSHOT:txt:maps-mojang + true + org.spigotmc:spigot:1.19.4-R0.1-SNAPSHOT:jar:remapped-mojang + true + remapped-obf + + + + package + + remap + + remap-spigot + + ${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar + org.spigotmc:minecraft-server:1.19.4-R0.1-SNAPSHOT:csrg:maps-spigot + org.spigotmc:spigot:1.19.4-R0.1-SNAPSHOT:jar:remapped-obf + + + + + + + diff --git a/v1_19_R3/src/main/java/fr/skytasul/quests/utils/nms/v1_19_R3.java b/v1_19_R3/src/main/java/fr/skytasul/quests/utils/nms/v1_19_R3.java new file mode 100644 index 00000000..f138329b --- /dev/null +++ b/v1_19_R3/src/main/java/fr/skytasul/quests/utils/nms/v1_19_R3.java @@ -0,0 +1,57 @@ +package fr.skytasul.quests.utils.nms; + +import java.util.List; +import org.apache.commons.lang.Validate; +import org.bukkit.Material; +import org.bukkit.craftbukkit.v1_19_R3.entity.CraftPlayer; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import net.minecraft.core.Holder.Reference; +import net.minecraft.core.HolderLookup.RegistryLookup; +import net.minecraft.core.registries.Registries; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientboundOpenBookPacket; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.Property; +import io.netty.buffer.ByteBuf; + +public class v1_19_R3 extends NMS{ + + @Override + public Object bookPacket(ByteBuf buf){ + return new ClientboundOpenBookPacket(InteractionHand.MAIN_HAND); + } + + @Override + public void sendPacket(Player p, Object packet){ + Validate.isTrue(packet instanceof Packet, "The object specified is not a packet."); + ((CraftPlayer) p).getHandle().connection.send((Packet) packet); + } + + @Override + public double entityNameplateHeight(Entity en) { + return en.getHeight(); + } + + @Override + public List getAvailableBlockProperties(Material material) { + RegistryLookup blockRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BLOCK); + Reference block = blockRegistry + .getOrThrow(ResourceKey.create(Registries.BLOCK, new ResourceLocation(material.getKey().getKey()))); + StateDefinition stateList = block.value().getStateDefinition(); + return stateList.getProperties().stream().map(Property::getName).toList(); + } + + @Override + public List getAvailableBlockTags() { + return MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BLOCK).listTags() + .map(x -> x.key().location().toString()).toList(); + } + +} \ No newline at end of file From 64270bc2e6dcd9fff4ced7f88e44a10cffae9585 Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Wed, 15 Mar 2023 15:05:12 +0100 Subject: [PATCH 37/41] :green_heart: Fixed CI for UltimateTimber? --- core/libs.sh | 2 +- core/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/libs.sh b/core/libs.sh index e00499bb..0abc608b 100644 --- a/core/libs.sh +++ b/core/libs.sh @@ -23,7 +23,7 @@ echo -e "Maven path: $mavenPath\e[39m" "$mavenPath" install:install-file -Dfile=$jarsPath/Boss.jar -DgroupId=org.mineacademy -DartifactId=boss -Dversion=4.2.1 -Dpackaging=jar "$mavenPath" install:install-file -Dfile=$jarsPath/CMI.jar -DgroupId=com.zrips -DartifactId=cmi -Dversion=9.0.2.1 -Dpackaging=jar "$mavenPath" install:install-file -Dfile=$jarsPath/CMILib.jar -DgroupId=com.zrips -DartifactId=cmilib -Dversion=1.2.3.3 -Dpackaging=jar -"$mavenPath" install:install-file -Dfile=$jarsPath/UltimateTimber.jar -DgroupId=com.songoda -DartifactId=ultimatetimber -Dversion=2.3.5 -Dpackaging=jar +"$mavenPath" install:install-file -Dfile=$jarsPath/UltimateTimber.jar -DgroupId=com.songoda -DartifactId=UltimateTimber -Dversion=2.3.5 -Dpackaging=jar "$mavenPath" install:install-file -Dfile=$jarsPath/AdvancedSpawners-API.jar -DgroupId=gcspawners -DartifactId=gcspawners -Dversion=3.3.0 -Dpackaging=jar #"$mavenPath" install:install-file -Dfile=$jarsPath/MythicMobs.jar -DgroupId=io.lumine.xikage -DartifactId=MythicMobs -Dversion=4.12.0 -Dpackaging=jar #"$mavenPath" install:install-file -Dfile=$jarsPath/TokenEnchantAPI.jar -DgroupId=com.vk2gpz.tokenenchant -DartifactId=TokenEnchantAPI -Dversion=18.15.2 -Dpackaging=jar diff --git a/core/pom.xml b/core/pom.xml index db42cfd0..8127d375 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -326,7 +326,7 @@ com.songoda - ultimatetimber + UltimateTimber 2.3.5 provided From 619a9dfa38bb61ea13a0c07d2c9cb8547f077f23 Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Wed, 15 Mar 2023 15:24:04 +0100 Subject: [PATCH 38/41] :green_heart: Fixed libraries installation on newer maven --- core/Sky libs.sh | 2 +- core/libs.sh | 30 +++++++++++++++--------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/core/Sky libs.sh b/core/Sky libs.sh index 9119e14d..93820e43 100644 --- a/core/Sky libs.sh +++ b/core/Sky libs.sh @@ -1 +1 @@ -./libs.sh C:/Users/skyta/Documents/Minecraft/BuildTools/apache-maven-3.6.0/bin/mvn jars/ \ No newline at end of file +./libs.sh mvn jars/ \ No newline at end of file diff --git a/core/libs.sh b/core/libs.sh index 0abc608b..fbff3b79 100644 --- a/core/libs.sh +++ b/core/libs.sh @@ -12,20 +12,20 @@ echo -e "\e[93mInstalling BeautyQuests dependencies jars from \"$jarsPath\" to t echo -e "Maven path: $mavenPath\e[39m" -"$mavenPath" install:install-file -Dfile=$jarsPath/dynmap.jar -DgroupId=org.dynmap -DartifactId=dynmap -Dversion=1.0 -Dpackaging=jar -"$mavenPath" install:install-file -Dfile=$jarsPath/Factions.jar -DgroupId=com.massivecraft -DartifactId=factions -Dversion=1.0 -Dpackaging=jar -"$mavenPath" install:install-file -Dfile=$jarsPath/MassiveCore.jar -DgroupId=com.massivecraft -DartifactId=massivecore -Dversion=1.0 -Dpackaging=jar -"$mavenPath" install:install-file -Dfile=$jarsPath/GPS.jar -DgroupId=com.live.bemmamin -DartifactId=gps -Dversion=1.0 -Dpackaging=jar -"$mavenPath" install:install-file -Dfile=$jarsPath/Jobs.jar -DgroupId=com.gamingmesh -DartifactId=jobs -Dversion=5.1.0.1 -Dpackaging=jar -"$mavenPath" install:install-file -Dfile=$jarsPath/McCombatLevel.jar -DgroupId=com.gmail.mrphpfan -DartifactId=mccombatlevel -Dversion=1.0 -Dpackaging=jar -"$mavenPath" install:install-file -Dfile=$jarsPath/mcMMO.jar -DgroupId=com.gmail.nossr50 -DartifactId=mcmmo -Dversion=1.0 -Dpackaging=jar -"$mavenPath" install:install-file -Dfile=$jarsPath/SkillAPI.jar -DgroupId=com.suxy -DartifactId=skillapi -Dversion=1.0 -Dpackaging=jar -"$mavenPath" install:install-file -Dfile=$jarsPath/Boss.jar -DgroupId=org.mineacademy -DartifactId=boss -Dversion=4.2.1 -Dpackaging=jar -"$mavenPath" install:install-file -Dfile=$jarsPath/CMI.jar -DgroupId=com.zrips -DartifactId=cmi -Dversion=9.0.2.1 -Dpackaging=jar -"$mavenPath" install:install-file -Dfile=$jarsPath/CMILib.jar -DgroupId=com.zrips -DartifactId=cmilib -Dversion=1.2.3.3 -Dpackaging=jar -"$mavenPath" install:install-file -Dfile=$jarsPath/UltimateTimber.jar -DgroupId=com.songoda -DartifactId=UltimateTimber -Dversion=2.3.5 -Dpackaging=jar -"$mavenPath" install:install-file -Dfile=$jarsPath/AdvancedSpawners-API.jar -DgroupId=gcspawners -DartifactId=gcspawners -Dversion=3.3.0 -Dpackaging=jar -#"$mavenPath" install:install-file -Dfile=$jarsPath/MythicMobs.jar -DgroupId=io.lumine.xikage -DartifactId=MythicMobs -Dversion=4.12.0 -Dpackaging=jar -#"$mavenPath" install:install-file -Dfile=$jarsPath/TokenEnchantAPI.jar -DgroupId=com.vk2gpz.tokenenchant -DartifactId=TokenEnchantAPI -Dversion=18.15.2 -Dpackaging=jar +"$mavenPath" install:install-file -Dfile=$jarsPath/dynmap.jar -DgroupId=org.dynmap -DartifactId=dynmap -Dversion=1.0 -Dpackaging=jar -DgeneratePom=true +"$mavenPath" install:install-file -Dfile=$jarsPath/Factions.jar -DgroupId=com.massivecraft -DartifactId=factions -Dversion=1.0 -Dpackaging=jar -DgeneratePom=true +"$mavenPath" install:install-file -Dfile=$jarsPath/MassiveCore.jar -DgroupId=com.massivecraft -DartifactId=massivecore -Dversion=1.0 -Dpackaging=jar -DgeneratePom=true +"$mavenPath" install:install-file -Dfile=$jarsPath/GPS.jar -DgroupId=com.live.bemmamin -DartifactId=gps -Dversion=1.0 -Dpackaging=jar -DgeneratePom=true +"$mavenPath" install:install-file -Dfile=$jarsPath/Jobs.jar -DgroupId=com.gamingmesh -DartifactId=jobs -Dversion=5.1.0.1 -Dpackaging=jar -DgeneratePom=true +"$mavenPath" install:install-file -Dfile=$jarsPath/McCombatLevel.jar -DgroupId=com.gmail.mrphpfan -DartifactId=mccombatlevel -Dversion=1.0 -Dpackaging=jar -DgeneratePom=true +"$mavenPath" install:install-file -Dfile=$jarsPath/mcMMO.jar -DgroupId=com.gmail.nossr50 -DartifactId=mcmmo -Dversion=1.0 -Dpackaging=jar -DgeneratePom=true +"$mavenPath" install:install-file -Dfile=$jarsPath/SkillAPI.jar -DgroupId=com.suxy -DartifactId=skillapi -Dversion=1.0 -Dpackaging=jar -DgeneratePom=true +"$mavenPath" install:install-file -Dfile=$jarsPath/Boss.jar -DgroupId=org.mineacademy -DartifactId=boss -Dversion=4.2.1 -Dpackaging=jar -DgeneratePom=true +"$mavenPath" install:install-file -Dfile=$jarsPath/CMI.jar -DgroupId=com.zrips -DartifactId=cmi -Dversion=9.0.2.1 -Dpackaging=jar -DgeneratePom=true +"$mavenPath" install:install-file -Dfile=$jarsPath/CMILib.jar -DgroupId=com.zrips -DartifactId=cmilib -Dversion=1.2.3.3 -Dpackaging=jar -DgeneratePom=true +"$mavenPath" install:install-file -Dfile=$jarsPath/UltimateTimber.jar -DgroupId=com.songoda -DartifactId=UltimateTimber -Dversion=2.3.5 -Dpackaging=jar -DgeneratePom=true +"$mavenPath" install:install-file -Dfile=$jarsPath/AdvancedSpawners-API.jar -DgroupId=gcspawners -DartifactId=gcspawners -Dversion=3.3.0 -Dpackaging=jar -DgeneratePom=true +#"$mavenPath" install:install-file -Dfile=$jarsPath/MythicMobs.jar -DgroupId=io.lumine.xikage -DartifactId=MythicMobs -Dversion=4.12.0 -Dpackaging=jar -DgeneratePom=true +#"$mavenPath" install:install-file -Dfile=$jarsPath/TokenEnchantAPI.jar -DgroupId=com.vk2gpz.tokenenchant -DartifactId=TokenEnchantAPI -Dversion=18.15.2 -Dpackaging=jar -DgeneratePom=true echo -e "\e[92mOperation complete." \ No newline at end of file From 7e3d4ac7caf001fad5f7f3675dfe2996fe8fac19 Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Thu, 16 Mar 2023 20:55:19 +0100 Subject: [PATCH 39/41] :bug: Fixed issue with quest cancelling --- core/src/main/java/fr/skytasul/quests/structure/Quest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/java/fr/skytasul/quests/structure/Quest.java b/core/src/main/java/fr/skytasul/quests/structure/Quest.java index 9d229e0b..d1127b85 100644 --- a/core/src/main/java/fr/skytasul/quests/structure/Quest.java +++ b/core/src/main/java/fr/skytasul/quests/structure/Quest.java @@ -207,6 +207,7 @@ public boolean cancelPlayer(PlayerAccount acc) { return false; DebugUtils.logMessage("Cancelling quest " + id + " for player " + acc.getNameAndID()); + cancelInternal(acc); return true; } From b18580394baf4bc8b92b47bb812bb1160b52ac20 Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Sun, 19 Mar 2023 15:03:01 +0100 Subject: [PATCH 40/41] :zap: Improved TPS by a *lot* when using znpcs --- .../fr/skytasul/quests/stages/StageLocation.java | 6 +++--- .../utils/compatibility/npcs/BQServerNPCs.java | 15 +++++++++++---- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/fr/skytasul/quests/stages/StageLocation.java b/core/src/main/java/fr/skytasul/quests/stages/StageLocation.java index cce46378..e97ff9d4 100644 --- a/core/src/main/java/fr/skytasul/quests/stages/StageLocation.java +++ b/core/src/main/java/fr/skytasul/quests/stages/StageLocation.java @@ -1,13 +1,11 @@ package fr.skytasul.quests.stages; import java.util.regex.Pattern; - import org.bukkit.Location; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.player.PlayerMoveEvent; - import fr.skytasul.quests.QuestsConfiguration; import fr.skytasul.quests.api.options.QuestOption; import fr.skytasul.quests.api.stages.AbstractStage; @@ -75,8 +73,10 @@ public boolean isGPSEnabled() { @EventHandler public void onPlayerMove(PlayerMoveEvent e){ + if (e.getFrom().getBlockX() == e.getTo().getBlockX() && e.getFrom().getBlockY() == e.getTo().getBlockY() + && e.getFrom().getBlockZ() == e.getTo().getBlockZ()) + return; // only rotation if (!lc.isWorld(e.getTo().getWorld())) return; - if (e.getFrom().getBlockX() == e.getTo().getBlockX() && e.getFrom().getBlockY() == e.getTo().getBlockY() && e.getFrom().getBlockZ() == e.getTo().getBlockZ()) return; // only rotation Player p = e.getPlayer(); if (hasStarted(p) && canUpdate(p)) { diff --git a/core/src/main/java/fr/skytasul/quests/utils/compatibility/npcs/BQServerNPCs.java b/core/src/main/java/fr/skytasul/quests/utils/compatibility/npcs/BQServerNPCs.java index 7623fb64..760a774d 100644 --- a/core/src/main/java/fr/skytasul/quests/utils/compatibility/npcs/BQServerNPCs.java +++ b/core/src/main/java/fr/skytasul/quests/utils/compatibility/npcs/BQServerNPCs.java @@ -3,17 +3,17 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; - import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.event.EventHandler; - +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; import fr.skytasul.quests.QuestsConfiguration.ClickType; import fr.skytasul.quests.api.npcs.BQNPC; import fr.skytasul.quests.api.npcs.BQNPCsManager; - import io.github.znetworkw.znpcservers.ServersNPC; import io.github.znetworkw.znpcservers.configuration.ConfigurationConstants; import io.github.znetworkw.znpcservers.npc.NPC; @@ -24,6 +24,8 @@ public class BQServerNPCs extends BQNPCsManager { + private Cache cachedNpcs = CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.MINUTES).build(); + @Override public int getTimeToWaitForNPCs() { return 45; @@ -36,7 +38,12 @@ public Collection getIDs() { @Override public boolean isNPC(Entity entity) { - return NPC.all().stream().anyMatch(npc1 -> npc1.getEntityID() == entity.getEntityId()); + Boolean result = cachedNpcs.getIfPresent(entity.getEntityId()); + if (result == null) { + result = NPC.all().stream().anyMatch(npc1 -> npc1.getEntityID() == entity.getEntityId()); + cachedNpcs.put(entity.getEntityId(), result); + } + return result; } @Override From 4270bacc25d06a010a6f609403092b3d7a7425e5 Mon Sep 17 00:00:00 2001 From: SkytAsul Date: Sun, 19 Mar 2023 15:04:05 +0100 Subject: [PATCH 41/41] :bookmark: 0.20.1 --- core/src/main/resources/plugin.yml | 4 ++-- pom.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/resources/plugin.yml b/core/src/main/resources/plugin.yml index e3653010..819eb591 100644 --- a/core/src/main/resources/plugin.yml +++ b/core/src/main/resources/plugin.yml @@ -1,7 +1,7 @@ name: BeautyQuests author: SkytAsul -version: "${human.version}_BUILD${build.number}" -#version: "${human.version}" +#version: "${human.version}_BUILD${build.number}" +version: "${human.version}" description: Quests system with a simple graphical interface. website: https://www.spigotmc.org/resources/beautyquests.39255/ api-version: 1.13 diff --git a/pom.xml b/pom.xml index e2f7ce01..2b243938 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ fr.skytasul beautyquests-parent - 0.20.1-SNAPSHOT + 0.20.1 pom beautyquests