diff --git a/src/main/java/net/knarcraft/dynmapcitizens/DynmapCitizens.java b/src/main/java/net/knarcraft/dynmapcitizens/DynmapCitizens.java index 99afdf6..b7fd8cb 100644 --- a/src/main/java/net/knarcraft/dynmapcitizens/DynmapCitizens.java +++ b/src/main/java/net/knarcraft/dynmapcitizens/DynmapCitizens.java @@ -1,10 +1,12 @@ package net.knarcraft.dynmapcitizens; -import net.knarcraft.dynmapcitizens.trait.BlacksmithHandler; -import net.knarcraft.dynmapcitizens.trait.CitizensTraitHandler; -import net.knarcraft.dynmapcitizens.trait.MinstrelHandler; -import net.knarcraft.dynmapcitizens.trait.SentinelHandler; -import net.knarcraft.dynmapcitizens.trait.quests.QuestsHandler; +import net.knarcraft.dynmapcitizens.handler.VaultHandler; +import net.knarcraft.dynmapcitizens.handler.trait.BlacksmithHandler; +import net.knarcraft.dynmapcitizens.handler.trait.CitizensTraitHandler; +import net.knarcraft.dynmapcitizens.handler.trait.MinstrelHandler; +import net.knarcraft.dynmapcitizens.handler.trait.SentinelHandler; +import net.knarcraft.dynmapcitizens.handler.trait.quests.QuestsHandler; +import net.knarcraft.dynmapcitizens.property.Icon; import org.bukkit.Bukkit; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginManager; diff --git a/src/main/java/net/knarcraft/dynmapcitizens/VaultHandler.java b/src/main/java/net/knarcraft/dynmapcitizens/handler/VaultHandler.java similarity index 96% rename from src/main/java/net/knarcraft/dynmapcitizens/VaultHandler.java rename to src/main/java/net/knarcraft/dynmapcitizens/handler/VaultHandler.java index 1ea5723..d082ba4 100644 --- a/src/main/java/net/knarcraft/dynmapcitizens/VaultHandler.java +++ b/src/main/java/net/knarcraft/dynmapcitizens/handler/VaultHandler.java @@ -1,4 +1,4 @@ -package net.knarcraft.dynmapcitizens; +package net.knarcraft.dynmapcitizens.handler; import net.milkbowl.vault.economy.Economy; import org.bukkit.plugin.RegisteredServiceProvider; diff --git a/src/main/java/net/knarcraft/dynmapcitizens/trait/AbstractTraitHandler.java b/src/main/java/net/knarcraft/dynmapcitizens/handler/trait/AbstractTraitHandler.java similarity index 98% rename from src/main/java/net/knarcraft/dynmapcitizens/trait/AbstractTraitHandler.java rename to src/main/java/net/knarcraft/dynmapcitizens/handler/trait/AbstractTraitHandler.java index 391d086..b129fdd 100644 --- a/src/main/java/net/knarcraft/dynmapcitizens/trait/AbstractTraitHandler.java +++ b/src/main/java/net/knarcraft/dynmapcitizens/handler/trait/AbstractTraitHandler.java @@ -1,4 +1,4 @@ -package net.knarcraft.dynmapcitizens.trait; +package net.knarcraft.dynmapcitizens.handler.trait; import net.citizensnpcs.api.CitizensAPI; import net.citizensnpcs.api.npc.NPC; diff --git a/src/main/java/net/knarcraft/dynmapcitizens/trait/BlacksmithHandler.java b/src/main/java/net/knarcraft/dynmapcitizens/handler/trait/BlacksmithHandler.java similarity index 96% rename from src/main/java/net/knarcraft/dynmapcitizens/trait/BlacksmithHandler.java rename to src/main/java/net/knarcraft/dynmapcitizens/handler/trait/BlacksmithHandler.java index b0055ef..6f1ba99 100644 --- a/src/main/java/net/knarcraft/dynmapcitizens/trait/BlacksmithHandler.java +++ b/src/main/java/net/knarcraft/dynmapcitizens/handler/trait/BlacksmithHandler.java @@ -1,4 +1,4 @@ -package net.knarcraft.dynmapcitizens.trait; +package net.knarcraft.dynmapcitizens.handler.trait; import net.citizensnpcs.api.CitizensAPI; import net.citizensnpcs.api.npc.NPC; @@ -7,8 +7,8 @@ import net.knarcraft.blacksmith.BlacksmithPlugin; import net.knarcraft.blacksmith.config.NPCSettings; import net.knarcraft.blacksmith.trait.BlacksmithTrait; import net.knarcraft.dynmapcitizens.DynmapCitizens; -import net.knarcraft.dynmapcitizens.Icon; -import net.knarcraft.dynmapcitizens.UpdateRate; +import net.knarcraft.dynmapcitizens.property.Icon; +import net.knarcraft.dynmapcitizens.property.UpdateRate; import org.bukkit.Bukkit; import org.bukkit.Material; import org.dynmap.DynmapAPI; diff --git a/src/main/java/net/knarcraft/dynmapcitizens/trait/CitizensTraitHandler.java b/src/main/java/net/knarcraft/dynmapcitizens/handler/trait/CitizensTraitHandler.java similarity index 85% rename from src/main/java/net/knarcraft/dynmapcitizens/trait/CitizensTraitHandler.java rename to src/main/java/net/knarcraft/dynmapcitizens/handler/trait/CitizensTraitHandler.java index 90c7d9c..f3cb726 100644 --- a/src/main/java/net/knarcraft/dynmapcitizens/trait/CitizensTraitHandler.java +++ b/src/main/java/net/knarcraft/dynmapcitizens/handler/trait/CitizensTraitHandler.java @@ -1,6 +1,6 @@ -package net.knarcraft.dynmapcitizens.trait; +package net.knarcraft.dynmapcitizens.handler.trait; -import net.knarcraft.dynmapcitizens.UpdateRate; +import net.knarcraft.dynmapcitizens.property.UpdateRate; /** * A handler which takes care of everything for one citizen trait diff --git a/src/main/java/net/knarcraft/dynmapcitizens/trait/MinstrelHandler.java b/src/main/java/net/knarcraft/dynmapcitizens/handler/trait/MinstrelHandler.java similarity index 94% rename from src/main/java/net/knarcraft/dynmapcitizens/trait/MinstrelHandler.java rename to src/main/java/net/knarcraft/dynmapcitizens/handler/trait/MinstrelHandler.java index f5f834c..639e9b9 100644 --- a/src/main/java/net/knarcraft/dynmapcitizens/trait/MinstrelHandler.java +++ b/src/main/java/net/knarcraft/dynmapcitizens/handler/trait/MinstrelHandler.java @@ -1,11 +1,11 @@ -package net.knarcraft.dynmapcitizens.trait; +package net.knarcraft.dynmapcitizens.handler.trait; import net.citizensnpcs.api.CitizensAPI; import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.api.trait.Trait; import net.knarcraft.dynmapcitizens.DynmapCitizens; -import net.knarcraft.dynmapcitizens.Icon; -import net.knarcraft.dynmapcitizens.UpdateRate; +import net.knarcraft.dynmapcitizens.property.Icon; +import net.knarcraft.dynmapcitizens.property.UpdateRate; import net.knarcraft.minstrel.MinstrelPlugin; import net.knarcraft.minstrel.music.Song; import net.knarcraft.minstrel.trait.MinstrelTrait; diff --git a/src/main/java/net/knarcraft/dynmapcitizens/trait/SentinelHandler.java b/src/main/java/net/knarcraft/dynmapcitizens/handler/trait/SentinelHandler.java similarity index 92% rename from src/main/java/net/knarcraft/dynmapcitizens/trait/SentinelHandler.java rename to src/main/java/net/knarcraft/dynmapcitizens/handler/trait/SentinelHandler.java index 7506784..aae0f44 100644 --- a/src/main/java/net/knarcraft/dynmapcitizens/trait/SentinelHandler.java +++ b/src/main/java/net/knarcraft/dynmapcitizens/handler/trait/SentinelHandler.java @@ -1,11 +1,11 @@ -package net.knarcraft.dynmapcitizens.trait; +package net.knarcraft.dynmapcitizens.handler.trait; import net.citizensnpcs.api.CitizensAPI; import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.api.trait.Trait; import net.knarcraft.dynmapcitizens.DynmapCitizens; -import net.knarcraft.dynmapcitizens.Icon; -import net.knarcraft.dynmapcitizens.UpdateRate; +import net.knarcraft.dynmapcitizens.property.Icon; +import net.knarcraft.dynmapcitizens.property.UpdateRate; import org.bukkit.Bukkit; import org.dynmap.DynmapAPI; import org.dynmap.markers.GenericMarker; diff --git a/src/main/java/net/knarcraft/dynmapcitizens/trait/quests/NPCQuestInfo.java b/src/main/java/net/knarcraft/dynmapcitizens/handler/trait/quests/NPCQuestInfo.java similarity index 97% rename from src/main/java/net/knarcraft/dynmapcitizens/trait/quests/NPCQuestInfo.java rename to src/main/java/net/knarcraft/dynmapcitizens/handler/trait/quests/NPCQuestInfo.java index 89ba09d..7082751 100644 --- a/src/main/java/net/knarcraft/dynmapcitizens/trait/quests/NPCQuestInfo.java +++ b/src/main/java/net/knarcraft/dynmapcitizens/handler/trait/quests/NPCQuestInfo.java @@ -1,7 +1,7 @@ -package net.knarcraft.dynmapcitizens.trait.quests; +package net.knarcraft.dynmapcitizens.handler.trait.quests; import me.blackvein.quests.quests.IQuest; -import net.knarcraft.dynmapcitizens.Icon; +import net.knarcraft.dynmapcitizens.property.Icon; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/net/knarcraft/dynmapcitizens/trait/quests/QuestNPCType.java b/src/main/java/net/knarcraft/dynmapcitizens/handler/trait/quests/QuestNPCType.java similarity index 89% rename from src/main/java/net/knarcraft/dynmapcitizens/trait/quests/QuestNPCType.java rename to src/main/java/net/knarcraft/dynmapcitizens/handler/trait/quests/QuestNPCType.java index 918bea6..ea90965 100644 --- a/src/main/java/net/knarcraft/dynmapcitizens/trait/quests/QuestNPCType.java +++ b/src/main/java/net/knarcraft/dynmapcitizens/handler/trait/quests/QuestNPCType.java @@ -1,4 +1,4 @@ -package net.knarcraft.dynmapcitizens.trait.quests; +package net.knarcraft.dynmapcitizens.handler.trait.quests; /** * A specifier for a quest NPC's main type diff --git a/src/main/java/net/knarcraft/dynmapcitizens/handler/trait/quests/QuestPlannerInfoGenerator.java b/src/main/java/net/knarcraft/dynmapcitizens/handler/trait/quests/QuestPlannerInfoGenerator.java new file mode 100644 index 0000000..3d6d6e5 --- /dev/null +++ b/src/main/java/net/knarcraft/dynmapcitizens/handler/trait/quests/QuestPlannerInfoGenerator.java @@ -0,0 +1,64 @@ +package net.knarcraft.dynmapcitizens.handler.trait.quests; + +import me.blackvein.quests.quests.IQuest; +import me.blackvein.quests.quests.Planner; +import net.knarcraft.dynmapcitizens.util.TimeFormatter; + +/** + * A class to generate a string containing all information about a quest's planner info + */ +public class QuestPlannerInfoGenerator { + + private final IQuest quest; + + /** + * Instantiates a new quest planner info generator + * + * @param quest

The quest to generate information about

+ */ + public QuestPlannerInfoGenerator(IQuest quest) { + this.quest = quest; + } + + /** + * Gets information about the time-availability of a quest + * + * @return

Information about when the quest is available

+ */ + public String getQuestPlannerInfo() { + Planner planner = quest.getPlanner(); + StringBuilder plannerInfo = new StringBuilder(); + plannerInfo.append("Planner:"); + return plannerInfo.toString(); + } + +} diff --git a/src/main/java/net/knarcraft/dynmapcitizens/handler/trait/quests/QuestRequirementsInfoGenerator.java b/src/main/java/net/knarcraft/dynmapcitizens/handler/trait/quests/QuestRequirementsInfoGenerator.java new file mode 100644 index 0000000..426b2ff --- /dev/null +++ b/src/main/java/net/knarcraft/dynmapcitizens/handler/trait/quests/QuestRequirementsInfoGenerator.java @@ -0,0 +1,108 @@ +package net.knarcraft.dynmapcitizens.handler.trait.quests; + +import me.blackvein.quests.quests.IQuest; +import me.blackvein.quests.quests.Requirements; +import net.knarcraft.dynmapcitizens.util.QuestsHelper; +import org.bukkit.inventory.ItemStack; + +import java.util.List; +import java.util.Map; + +/** + * A class to generate a string containing all information about a quest's requirements + */ +public class QuestRequirementsInfoGenerator { + + private final IQuest quest; + + /** + * Instantiates a new quest requirement info generator + * + * @param quest

The quest to generate information about

+ */ + public QuestRequirementsInfoGenerator(IQuest quest) { + this.quest = quest; + } + + /** + * Gets information about all requirements for the given quest + * + * @return

Information about the quest's requirements

+ */ + public String getQuestRequirementsInfo() { + Requirements requirements = quest.getRequirements(); + StringBuilder requirementInfo = new StringBuilder(); + if (!requirements.hasRequirement()) { + return requirementInfo.toString(); + } + + requirementInfo.append("Requirements: "); + return requirementInfo.toString(); + } + +} diff --git a/src/main/java/net/knarcraft/dynmapcitizens/handler/trait/quests/QuestRewardsInfoGenerator.java b/src/main/java/net/knarcraft/dynmapcitizens/handler/trait/quests/QuestRewardsInfoGenerator.java new file mode 100644 index 0000000..383aa44 --- /dev/null +++ b/src/main/java/net/knarcraft/dynmapcitizens/handler/trait/quests/QuestRewardsInfoGenerator.java @@ -0,0 +1,58 @@ +package net.knarcraft.dynmapcitizens.handler.trait.quests; + +import me.blackvein.quests.quests.IQuest; +import me.blackvein.quests.quests.Rewards; +import net.knarcraft.dynmapcitizens.util.QuestsHelper; +import org.bukkit.inventory.ItemStack; + +/** + * A class to generate a string containing all information about a quest's rewards + */ +public class QuestRewardsInfoGenerator { + + private final IQuest quest; + + /** + * Instantiates a new quest reward info generator + * + * @param quest

The quest to generate information about

+ */ + public QuestRewardsInfoGenerator(IQuest quest) { + this.quest = quest; + } + + /** + * Gets information about all rewards for the given quest + * + * @return

Information about the quest's rewards

+ */ + public String getQuestRewardsInfo() { + Rewards reward = quest.getRewards(); + StringBuilder rewardInfo = new StringBuilder(); + rewardInfo.append("Rewards:"); + return rewardInfo.toString(); + } + +} diff --git a/src/main/java/net/knarcraft/dynmapcitizens/handler/trait/quests/QuestStagesInfoGenerator.java b/src/main/java/net/knarcraft/dynmapcitizens/handler/trait/quests/QuestStagesInfoGenerator.java new file mode 100644 index 0000000..dbea1c1 --- /dev/null +++ b/src/main/java/net/knarcraft/dynmapcitizens/handler/trait/quests/QuestStagesInfoGenerator.java @@ -0,0 +1,109 @@ +package net.knarcraft.dynmapcitizens.handler.trait.quests; + +import me.blackvein.quests.quests.IQuest; +import me.blackvein.quests.quests.IStage; +import net.citizensnpcs.api.CitizensAPI; +import net.citizensnpcs.api.npc.NPC; +import net.citizensnpcs.api.npc.NPCRegistry; +import net.knarcraft.dynmapcitizens.util.QuestsHelper; +import org.bukkit.inventory.ItemStack; + +import java.util.List; +import java.util.UUID; + +/** + * A class to generate a string containing all information about a quest's stages + */ +public class QuestStagesInfoGenerator { + + private final IQuest quest; + + /** + * Instantiates a new quest stages info generator + * + * @param quest

The quest to generate information about

+ */ + public QuestStagesInfoGenerator(IQuest quest) { + this.quest = quest; + } + + /** + * Gets information about a quest's stages + * + * @return

A string with information about the quest's stages

+ */ + public String getQuestStagesInfo() { + StringBuilder questInfo = new StringBuilder(); + NPCRegistry registry = CitizensAPI.getNPCRegistry(); + int stageCounter = 1; + questInfo.append("Stages:"); + return questInfo.toString(); + } + + /** + * Gets a string to display a quest task involving some action on an item + * + * @param items

The items that are part of the task

+ * @param explanation

The explanation of what the player needs to do with the items

+ * @return

A string describing the necessary tasks

+ */ + private String getQuestItemsTaskString(List items, String explanation) { + StringBuilder questInfo = new StringBuilder(); + for (ItemStack itemStack : items) { + questInfo.append(explanation).append(QuestsHelper.getItemStackString(itemStack)); + } + return questInfo.toString(); + } + +} diff --git a/src/main/java/net/knarcraft/dynmapcitizens/handler/trait/quests/QuestsHandler.java b/src/main/java/net/knarcraft/dynmapcitizens/handler/trait/quests/QuestsHandler.java new file mode 100644 index 0000000..c9b482f --- /dev/null +++ b/src/main/java/net/knarcraft/dynmapcitizens/handler/trait/quests/QuestsHandler.java @@ -0,0 +1,266 @@ +package net.knarcraft.dynmapcitizens.handler.trait.quests; + +import me.blackvein.quests.QuestsAPI; +import me.blackvein.quests.quests.IQuest; +import me.blackvein.quests.quests.IStage; +import net.citizensnpcs.api.CitizensAPI; +import net.citizensnpcs.api.npc.NPCRegistry; +import net.knarcraft.dynmapcitizens.DynmapCitizens; +import net.knarcraft.dynmapcitizens.handler.trait.AbstractTraitHandler; +import net.knarcraft.dynmapcitizens.property.Icon; +import net.knarcraft.dynmapcitizens.property.UpdateRate; +import net.knarcraft.dynmapcitizens.util.QuestsHelper; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.dynmap.DynmapAPI; +import org.dynmap.markers.CircleMarker; +import org.dynmap.markers.GenericMarker; +import org.dynmap.markers.MarkerIcon; +import org.dynmap.markers.MarkerSet; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.logging.Level; + +/** + * A handler class for the quests trait + */ +public class QuestsHandler extends AbstractTraitHandler { + + private QuestsAPI questsAPI; + private MarkerSet questMarkerSet; + private MarkerSet questAreaMarkerSet; + private Map markerIcons; + private Collection loadedQuests; + private Map questGiverInfo; + + @Override + public void initialize() { + questsAPI = (QuestsAPI) Bukkit.getServer().getPluginManager().getPlugin("Quests"); + DynmapAPI dynmapAPI = DynmapCitizens.getInstance().getDynmapAPI(); + markerIcons = DynmapCitizens.getInstance().getMarkerIcons(); + if (questsAPI != null) { + questMarkerSet = getMarkerSet(dynmapAPI, "quests", "Quests"); + questAreaMarkerSet = getMarkerSet(dynmapAPI, "quest_areas", "Quest areas"); + if (questMarkerSet != null && questAreaMarkerSet != null) { + questMarkerSet.setHideByDefault(false); + questAreaMarkerSet.setHideByDefault(true); + questMarkerSet.setLayerPriority(3); + questAreaMarkerSet.setLayerPriority(2); + isEnabled = true; + return; + } + } + isEnabled = false; + } + + @Override + public UpdateRate getUpdateRate() { + return UpdateRate.VERY_SLOW; + } + + @Override + public void updateMarkers() { + if (questsAPI.isLoading()) { + return; + } + + //There is no point in updating if there has been no changes in quests + boolean questsChanged = loadedQuests == null || !loadedQuests.equals(questsAPI.getLoadedQuests()); + loadedQuests = questsAPI.getLoadedQuests(); + + //Remove old quest markers + questMarkerSet.getMarkers().forEach(GenericMarker::deleteMarker); + + //Updates all quest area markers + if (questsChanged) { + updateQuestAreas(); + } + + //Generate information about all NPCs involved in quests + generateQuestNPCInfo(); + + //Generate markers based on the generated info + generateAllMarkers(); + } + + /** + * Generates information about all NPCs involved in quests + */ + private void generateQuestNPCInfo() { + //Clear any previous information + questGiverInfo = new HashMap<>(); + //Generation information about NPC's parts in each quest + for (IQuest quest : questsAPI.getLoadedQuests()) { + if (quest.getNpcStart() != null) { + getInfo(quest.getNpcStart()).addQuestStart(quest); + } + for (IStage stage : quest.getStages()) { + for (UUID npcId : stage.getNpcsToKill()) { + getInfo(npcId).addQuestKill(quest); + } + for (UUID npcId : stage.getItemDeliveryTargets()) { + getInfo(npcId).addQuestDeliver(quest); + } + for (UUID npcId : stage.getNpcsToInteract()) { + getInfo(npcId).addQuestInteract(quest); + } + } + } + } + + /** + * Generates all quest markers based on the previously generated quest NPC info + */ + private void generateAllMarkers() { + NPCRegistry registry = CitizensAPI.getNPCRegistry(); + //Add markers for each NPC detected as part of a quest + for (UUID npcId : questGiverInfo.keySet()) { + NPCQuestInfo info = questGiverInfo.get(npcId); + MarkerIcon icon = markerIcons.get(info.getNPCIcon()); + List questStarts = info.getQuestStarts(); + StringBuilder markerDescription = new StringBuilder(); + + markerDescription.append("

").append(registry.getByUniqueId(npcId).getName()).append("

"); + + if (!questStarts.isEmpty()) { + markerDescription.append("

Quests offered:

    "); + for (IQuest quest : questStarts) { + markerDescription.append("
  • ").append(quest.getName()).append("

    - "); + markerDescription.append(quest.getDescription()).append("
    ").append( + new QuestStagesInfoGenerator(quest).getQuestStagesInfo()); + markerDescription.append(new QuestRewardsInfoGenerator(quest).getQuestRewardsInfo()); + markerDescription.append(new QuestRequirementsInfoGenerator(quest).getQuestRequirementsInfo()); + markerDescription.append(new QuestPlannerInfoGenerator(quest).getQuestPlannerInfo()).append("
  • "); + } + markerDescription.append("
"); + } + + markerDescription.append(getInvolvedInQuestsString(info)); + + addNPCMarker(npcId, QuestsHelper.getMarkerTitle(info.getQuestNPCType()), markerDescription.toString(), icon, questMarkerSet); + } + } + + /** + * Gets information about the quests an NPC is involved in + * + * @param info

The NPC info to look through

+ * @return

Information about an NPC's involvement in different quests

+ */ + private String getInvolvedInQuestsString(NPCQuestInfo info) { + List questKills = info.getQuestKills(); + List questInteractions = info.getQuestInteractions(); + List questDeliveries = info.getQuestDeliveries(); + + if (questKills.isEmpty() && questInteractions.isEmpty() && questDeliveries.isEmpty()) { + return ""; + } + StringBuilder markerDescription = new StringBuilder(); + markerDescription.append("

Involved in quests:

    "); + addInvolvedInString("Killed in", questKills, markerDescription); + addInvolvedInString("Delivery target in", questDeliveries, markerDescription); + addInvolvedInString("Interacted with in quest", questInteractions, markerDescription); + markerDescription.append("
"); + return markerDescription.toString(); + } + + /** + * Adds string explaining how an NPC is involved with the given quests + * + * @param prefix

The string explaining how the NPC is involved

+ * @param quests

The quests the NPC is involved in

+ * @param builder

The string builder to append to

+ */ + private void addInvolvedInString(String prefix, List quests, StringBuilder builder) { + for (IQuest quest : new HashSet<>(quests)) { + builder.append("
  • ").append(prefix).append(": ").append(quest.getName()).append("
  • "); + } + } + + + /** + * Gets the info object for the given NPC + * + * @param npcId

    The id of the NPC to get information about

    + * @return

    The NPC's info object

    + */ + private NPCQuestInfo getInfo(UUID npcId) { + if (questGiverInfo.get(npcId) == null) { + questGiverInfo.put(npcId, new NPCQuestInfo()); + } + return questGiverInfo.get(npcId); + } + + /** + * Updates all quest area markers + */ + private void updateQuestAreas() { + questAreaMarkerSet.getCircleMarkers().forEach(GenericMarker::deleteMarker); + for (IQuest quest : questsAPI.getLoadedQuests()) { + for (IStage stage : quest.getStages()) { + markKillLocations(quest, stage); + markReachLocations(quest, stage); + } + } + //TODO: Mark WorldGuard areas part of quests. Requires WorldGuard integration + } + + /** + * Marks any reach locations found in the given stage + * + * @param quest

    The quest the stage belongs to

    + * @param stage

    The stage to search for reach locations

    + */ + private void markReachLocations(IQuest quest, IStage stage) { + markLocations(stage.getLocationsToReach(), stage.getRadiiToReachWithin(), + "Target location for: " + quest.getName()); + } + + /** + * Marks any kill locations found in the given stage + * + * @param quest

    The quest the stage belongs to

    + * @param stage

    The stage to search for kill locations

    + */ + private void markKillLocations(IQuest quest, IStage stage) { + markLocations(stage.getLocationsToKillWithin(), stage.getRadiiToKillWithin(), + "Kill location for: " + quest.getName()); + } + + /** + * Marks the given locations on the dynamic map + * + * @param locations

    The locations to mark

    + * @param radii

    The radius of each location's circle

    + * @param description

    The description for what the location means

    + */ + private void markLocations(List locations, List radii, String description) { + for (int i = 0; i < locations.size(); i++) { + Location location = locations.get(i); + int radius = radii.get(i); + + //Skip if location is invalid + World world = location.getWorld(); + if (world == null) { + continue; + } + + CircleMarker circleMarker = questAreaMarkerSet.createCircleMarker(null, description, true, + world.getName(), location.getX(), location.getY(), location.getZ(), radius, radius, false); + if (circleMarker == null) { + DynmapCitizens.getInstance().getLogger().log(Level.WARNING, "Unable to create circle marker at " + + location + " with radius " + radius); + } else { + circleMarker.setFillStyle(0.3, 0x75AFD2); + circleMarker.setLineStyle(1, 1.0, 0x36c90e); + } + } + } + +} diff --git a/src/main/java/net/knarcraft/dynmapcitizens/Icon.java b/src/main/java/net/knarcraft/dynmapcitizens/property/Icon.java similarity index 94% rename from src/main/java/net/knarcraft/dynmapcitizens/Icon.java rename to src/main/java/net/knarcraft/dynmapcitizens/property/Icon.java index 4487d96..b0b5ee0 100644 --- a/src/main/java/net/knarcraft/dynmapcitizens/Icon.java +++ b/src/main/java/net/knarcraft/dynmapcitizens/property/Icon.java @@ -1,4 +1,4 @@ -package net.knarcraft.dynmapcitizens; +package net.knarcraft.dynmapcitizens.property; /** * Every icon type used diff --git a/src/main/java/net/knarcraft/dynmapcitizens/UpdateRate.java b/src/main/java/net/knarcraft/dynmapcitizens/property/UpdateRate.java similarity index 94% rename from src/main/java/net/knarcraft/dynmapcitizens/UpdateRate.java rename to src/main/java/net/knarcraft/dynmapcitizens/property/UpdateRate.java index b5f6d51..7d5e55d 100644 --- a/src/main/java/net/knarcraft/dynmapcitizens/UpdateRate.java +++ b/src/main/java/net/knarcraft/dynmapcitizens/property/UpdateRate.java @@ -1,4 +1,4 @@ -package net.knarcraft.dynmapcitizens; +package net.knarcraft.dynmapcitizens.property; /** * An update rate for a group of icons diff --git a/src/main/java/net/knarcraft/dynmapcitizens/trait/quests/QuestsHandler.java b/src/main/java/net/knarcraft/dynmapcitizens/trait/quests/QuestsHandler.java deleted file mode 100644 index 3e69e57..0000000 --- a/src/main/java/net/knarcraft/dynmapcitizens/trait/quests/QuestsHandler.java +++ /dev/null @@ -1,604 +0,0 @@ -package net.knarcraft.dynmapcitizens.trait.quests; - -import me.blackvein.quests.QuestsAPI; -import me.blackvein.quests.quests.IQuest; -import me.blackvein.quests.quests.IStage; -import me.blackvein.quests.quests.Planner; -import me.blackvein.quests.quests.Requirements; -import me.blackvein.quests.quests.Rewards; -import net.citizensnpcs.api.CitizensAPI; -import net.citizensnpcs.api.npc.NPC; -import net.citizensnpcs.api.npc.NPCRegistry; -import net.knarcraft.dynmapcitizens.DynmapCitizens; -import net.knarcraft.dynmapcitizens.Icon; -import net.knarcraft.dynmapcitizens.UpdateRate; -import net.knarcraft.dynmapcitizens.VaultHandler; -import net.knarcraft.dynmapcitizens.trait.AbstractTraitHandler; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.inventory.ItemStack; -import org.dynmap.DynmapAPI; -import org.dynmap.markers.CircleMarker; -import org.dynmap.markers.GenericMarker; -import org.dynmap.markers.MarkerIcon; -import org.dynmap.markers.MarkerSet; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.logging.Level; - -import static net.knarcraft.blacksmith.formatting.StringFormatter.replacePlaceholder; - -/** - * A handler class for the quests trait - */ -public class QuestsHandler extends AbstractTraitHandler { - - private QuestsAPI questsAPI; - private MarkerSet questMarkerSet; - private MarkerSet questAreaMarkerSet; - private Map markerIcons; - private Collection loadedQuests; - private Map questGiverInfo; - - @Override - public void initialize() { - questsAPI = (QuestsAPI) Bukkit.getServer().getPluginManager().getPlugin("Quests"); - DynmapAPI dynmapAPI = DynmapCitizens.getInstance().getDynmapAPI(); - markerIcons = DynmapCitizens.getInstance().getMarkerIcons(); - if (questsAPI != null) { - questMarkerSet = getMarkerSet(dynmapAPI, "quests", "Quests"); - questAreaMarkerSet = getMarkerSet(dynmapAPI, "quest_areas", "Quest areas"); - if (questMarkerSet != null && questAreaMarkerSet != null) { - questMarkerSet.setHideByDefault(false); - questAreaMarkerSet.setHideByDefault(true); - questMarkerSet.setLayerPriority(3); - questAreaMarkerSet.setLayerPriority(2); - isEnabled = true; - return; - } - } - isEnabled = false; - } - - @Override - public UpdateRate getUpdateRate() { - return UpdateRate.VERY_SLOW; - } - - @Override - public void updateMarkers() { - if (questsAPI.isLoading()) { - return; - } - - questGiverInfo = new HashMap<>(); - - //There is no point in updating if there has been no changes in quests - boolean questsChanged = loadedQuests == null || !loadedQuests.equals(questsAPI.getLoadedQuests()); - loadedQuests = questsAPI.getLoadedQuests(); - - //Remove old quest markers - questMarkerSet.getMarkers().forEach(GenericMarker::deleteMarker); - - //Updates all quest area markers - if (questsChanged) { - updateQuestAreas(); - } - - NPCRegistry registry = CitizensAPI.getNPCRegistry(); - - //Generation information about NPC's parts in each quest - for (IQuest quest : questsAPI.getLoadedQuests()) { - if (quest.getNpcStart() != null) { - getInfo(quest.getNpcStart()).addQuestStart(quest); - } - for (IStage stage : quest.getStages()) { - for (UUID npcId : stage.getNpcsToKill()) { - getInfo(npcId).addQuestKill(quest); - } - for (UUID npcId : stage.getItemDeliveryTargets()) { - getInfo(npcId).addQuestDeliver(quest); - } - for (UUID npcId : stage.getNpcsToInteract()) { - getInfo(npcId).addQuestInteract(quest); - } - } - } - - //Add markers for each NPC detected as part of a quest - for (UUID npcId : questGiverInfo.keySet()) { - NPCQuestInfo info = questGiverInfo.get(npcId); - MarkerIcon icon = markerIcons.get(info.getNPCIcon()); - List questStarts = info.getQuestStarts(); - List questKills = info.getQuestKills(); - List questInteractions = info.getQuestInteractions(); - List questDeliveries = info.getQuestDeliveries(); - StringBuilder markerDescription = new StringBuilder(); - - markerDescription.append("

    ").append(registry.getByUniqueId(npcId).getName()).append("

    "); - - if (!questStarts.isEmpty()) { - markerDescription.append("

    Quests offered:

      "); - for (IQuest quest : questStarts) { - markerDescription.append("
    • ").append(quest.getName()).append("

      - "); - markerDescription.append(quest.getDescription()).append("
      ").append(getQuestStagesInfo(quest)); - markerDescription.append(getQuestRewardsInfo(quest)).append(getQuestRequirementsInfo(quest)); - markerDescription.append(getQuestPlannerInfo(quest)).append("
    • "); - } - markerDescription.append("
    "); - } - - if (!questKills.isEmpty() || !questInteractions.isEmpty() || !questDeliveries.isEmpty()) { - markerDescription.append("

    Involved in quests:

      "); - - for (IQuest quest : new HashSet<>(questKills)) { - markerDescription.append("
    • Killed in: ").append(quest.getName()).append("
    • "); - } - for (IQuest quest : new HashSet<>(questDeliveries)) { - markerDescription.append("
    • Delivery target in: ").append(quest.getName()).append("
    • "); - } - for (IQuest quest : new HashSet<>(questInteractions)) { - markerDescription.append("
    • Interacted with in quest: ").append(quest.getName()).append("
    • "); - } - - markerDescription.append("
    "); - } - - addNPCMarker(npcId, getMarkerTitle(info.getQuestNPCType()), markerDescription.toString(), icon, questMarkerSet); - } - } - - /** - * Gets information about the time-availability of a quest - * - * @param quest

    The quest to get planner info from

    - * @return

    Information about when the quest is available

    - */ - private String getQuestPlannerInfo(IQuest quest) { - Planner planner = quest.getPlanner(); - StringBuilder plannerInfo = new StringBuilder(); - plannerInfo.append("Planner:
      "); - - //Quest can be repeated after a cool-down - if (planner.hasCooldown()) { - plannerInfo.append("
    • Quest repeatable after: ").append(getDurationString(planner.getCooldown() / 1000)); - plannerInfo.append("
    • "); - } else { - plannerInfo.append("
    • Quest cannot be repeated!
    • "); - } - - //Quest only becomes available after the start date - if (planner.hasStart()) { - DateFormat format = new SimpleDateFormat("dd MM yyyy HH:mm:ss"); - Date date = new Date(planner.getStartInMillis()); - plannerInfo.append("
    • Quest available from ").append(format.format(date)).append("
    • "); - } - - //Quest is only available until the end date - if (planner.hasEnd()) { - DateFormat format = new SimpleDateFormat("dd MM yyyy HH:mm:ss"); - Date date = new Date(planner.getEndInMillis()); - plannerInfo.append("
    • Quest available until ").append(format.format(date)).append("
    • "); - } - - //Quest availability repeats - if (planner.hasRepeat()) { - plannerInfo.append("
    • Quest will become available again after "); - plannerInfo.append(getDurationString(planner.getRepeat() / 1000)).append("
    • "); - } - - plannerInfo.append("
    "); - return plannerInfo.toString(); - } - - /** - * Gets the string used for displaying this sign's duration - * - * @return

    The string used for displaying this sign's duration

    - */ - public String getDurationString(long duration) { - if (duration == 0) { - return "immediately"; - } else { - double minute = 60; - double hour = minute * 60; - double day = hour * 24; - double week = day * 7; - double month = day * 30; - double year = day * 365; - double decade = year * 10; - - Map timeUnits = new HashMap<>(); - timeUnits.put(decade, new String[]{"decade", "decades"}); - timeUnits.put(year, new String[]{"year", "years"}); - timeUnits.put(month, new String[]{"month", "months"}); - timeUnits.put(week, new String[]{"week", "weeks"}); - timeUnits.put(day, new String[]{"day", "days"}); - timeUnits.put(hour, new String[]{"hour", "hours"}); - timeUnits.put(minute, new String[]{"minute", "minutes"}); - timeUnits.put(1D, new String[]{"second", "seconds"}); - - List sortedUnits = new ArrayList<>(timeUnits.keySet()); - Collections.sort(sortedUnits); - Collections.reverse(sortedUnits); - - for (Double unit : sortedUnits) { - if (duration / unit >= 1) { - double units = round(duration / unit); - return formatDurationString(units, timeUnits.get(unit)[units == 1 ? 0 : 1], - (units * 10) % 10 == 0); - } - } - return formatDurationString(duration, "seconds", false); - } - } - - /** - * Rounds a number to its last two digits - * - * @param number

    The number to round

    - * @return

    The rounded number

    - */ - private double round(double number) { - return Math.round(number * 100.0) / 100.0; - } - - /** - * Formats a duration string - * - * @param duration

    The duration to display

    - * @param translatableMessage

    The time unit to display

    - * @param castToInt

    Whether to cast the duration to an int

    - * @return

    The formatted duration string

    - */ - private String formatDurationString(double duration, String translatableMessage, boolean castToInt) { - String durationFormat = "{duration} {unit}"; - durationFormat = replacePlaceholder(durationFormat, "{unit}", translatableMessage); - return replacePlaceholder(durationFormat, "{duration}", castToInt ? String.valueOf((int) duration) : - String.valueOf(duration)); - } - - /** - * Gets information about all requirements for the given quest - * - * @param quest

    The quest to get requirements for

    - * @return

    Information about the quest's requirements

    - */ - private String getQuestRequirementsInfo(IQuest quest) { - Requirements requirements = quest.getRequirements(); - StringBuilder requirementInfo = new StringBuilder(); - if (!requirements.hasRequirement()) { - return requirementInfo.toString(); - } - - requirementInfo.append("Requirements:
      "); - - if (requirements.getQuestPoints() > 0) { - requirementInfo.append("
    • ").append(requirements.getQuestPoints()).append(" quest points
    • "); - } - - if (requirements.getExp() > 0) { - requirementInfo.append("
    • ").append(requirements.getExp()).append(" exp
    • "); - } - - if (!requirements.getBlockQuests().isEmpty()) { - requirementInfo.append("
    • Blocked by quests:
        "); - for (IQuest blockQuest : requirements.getBlockQuests()) { - requirementInfo.append("
      • ").append(blockQuest.getName()).append("
      • "); - } - requirementInfo.append("
    • "); - } - - if (!requirements.getNeededQuests().isEmpty()) { - requirementInfo.append("
    • Required quests:
        "); - for (IQuest neededQuest : requirements.getNeededQuests()) { - requirementInfo.append("
      • ").append(neededQuest.getName()).append("
      • "); - } - requirementInfo.append("
    • "); - } - - if (!requirements.getItems().isEmpty()) { - requirementInfo.append("
    • Required items:
        "); - for (ItemStack item : requirements.getItems()) { - requirementInfo.append("
      • ").append(uppercaseFirst(getItemStackString(item))).append("
      • "); - } - requirementInfo.append("
    • "); - } - - if (!requirements.getMcmmoSkills().isEmpty()) { - List skills = requirements.getMcmmoSkills(); - List amounts = requirements.getMcmmoAmounts(); - for (int i = 0; i < skills.size(); i++) { - requirementInfo.append("
    • Requires mcMMO skill ").append(skills.get(i)).append(" at level "); - requirementInfo.append(amounts.get(i)).append("
    • "); - } - } - - if (!requirements.getPermissions().isEmpty()) { - requirementInfo.append("
    • Required permissions:
        "); - for (String permission : requirements.getPermissions()) { - requirementInfo.append("
      • ").append(permission).append("
      • "); - } - requirementInfo.append("
    • "); - } - - Map> customRequirementPlugins = requirements.getCustomRequirements(); - for (String plugin : customRequirementPlugins.keySet()) { - requirementInfo.append("
    • ").append(plugin).append(":
        "); - //Note: The format of custom requirements is kind of weird. First, you have the key for which plugin the - // requirement belongs to. Getting the value of the key gives another map. The map contains as key, the type - // of value, like "Skill Amount" or "Skill Type". The value is the actual value of whatever it is. - Map customRequirementEntry = customRequirementPlugins.get(plugin); - for (String requirementDescription : customRequirementEntry.keySet()) { - requirementInfo.append("
      • ").append(requirementDescription).append(" ").append(customRequirementEntry.get(requirementDescription)).append("
      • "); - } - requirementInfo.append("
    • "); - } - - requirementInfo.append("
    "); - return requirementInfo.toString(); - } - - /** - * Gets information about all rewards for the given quest - * - * @param quest

    The quest to get reward information for

    - * @return

    Information about the quest's rewards

    - */ - private String getQuestRewardsInfo(IQuest quest) { - Rewards reward = quest.getRewards(); - StringBuilder rewardInfo = new StringBuilder(); - rewardInfo.append("Rewards:
      "); - - if (reward.getMoney() > 0) { - rewardInfo.append("
    • ").append(reward.getMoney()).append(" ").append(getCurrency(reward.getMoney())).append("
    • "); - } - - if (reward.getExp() > 0) { - rewardInfo.append("
    • ").append(reward.getExp()).append(" exp").append("
    • "); - } - - for (String permission : reward.getPermissions()) { - rewardInfo.append("
    • ").append("Permission: ").append(permission).append("
    • "); - } - - for (ItemStack item : reward.getItems()) { - rewardInfo.append("
    • ").append(uppercaseFirst(getItemStackString(item))).append("
    • "); - } - - for (String command : reward.getCommands()) { - rewardInfo.append("
    • Command: ").append(command).append("
    • "); - } - - rewardInfo.append("
    "); - return rewardInfo.toString(); - } - - /** - * Gets the currency to print for the given amount of money - * - * @param money

    The amount to pay/use

    - * @return

    The currency name to use

    - */ - private String getCurrency(double money) { - VaultHandler vaultHandler = DynmapCitizens.getInstance().getVaultHandler(); - if (vaultHandler.isEnabled()) { - return vaultHandler.getCurrency(money != 1); - } else { - return "money"; - } - } - - /** - * Gets the marker title to use for the given quest NPC type - * - * @param type

    The type of marker to get the title for

    - * @return

    The title to use for the marker

    - */ - private String getMarkerTitle(QuestNPCType type) { - return switch (type) { - case GIVER -> "Quest Start NPC: "; - case INTERACT -> "Quest Interact NPC: "; - case DELIVER -> "Quest Deliver NPC: "; - case KILL -> "Quest Kill NPC: "; - case CHAIN -> "Quest Chain NPC: "; - }; - } - - /** - * Gets the info object for the given NPC - * - * @param npcId

    The id of the NPC to get information about

    - * @return

    The NPC's info object

    - */ - private NPCQuestInfo getInfo(UUID npcId) { - if (questGiverInfo.get(npcId) == null) { - questGiverInfo.put(npcId, new NPCQuestInfo()); - } - return questGiverInfo.get(npcId); - } - - /** - * Updates all quest area markers - */ - private void updateQuestAreas() { - questAreaMarkerSet.getCircleMarkers().forEach(GenericMarker::deleteMarker); - for (IQuest quest : questsAPI.getLoadedQuests()) { - for (IStage stage : quest.getStages()) { - markKillLocations(quest, stage); - markReachLocations(quest, stage); - } - } - //TODO: Mark WorldGuard areas part of quests. Requires WorldGuard integration - } - - /** - * Gets information about a quest's stages - * - * @param quest

    The quest to get information about

    - * @return

    A string with information about the quest's stages

    - */ - private String getQuestStagesInfo(IQuest quest) { - StringBuilder questInfo = new StringBuilder(); - NPCRegistry registry = CitizensAPI.getNPCRegistry(); - for (IStage stage : quest.getStages()) { - questInfo.append("Tasks:
      "); - int mobTypes = stage.getMobsToKill().size(); - for (int i = 0; i < mobTypes; i++) { - questInfo.append("
    • Kill ").append(normalizeName(stage.getMobsToKill().get(i).name())).append( - " X ").append(stage.getMobNumToKill().get(i)).append("
    • "); - } - int deliveries = stage.getItemDeliveryTargets().size(); - for (int i = 0; i < deliveries; i++) { - NPC npc = registry.getByUniqueId(stage.getItemDeliveryTargets().get(i)); - questInfo.append("
    • Deliver ").append(getItemStackString(stage.getItemsToDeliver().get(i))).append( - " to ").append(npc.getName()).append("
    • "); - } - if (stage.getFishToCatch() != null) { - questInfo.append("
    • Catch ").append(stage.getFishToCatch()).append(" fish").append("
    • "); - } - for (UUID npcId : stage.getNpcsToKill()) { - questInfo.append("
    • Kill NPC ").append(registry.getByUniqueId(npcId).getName()).append("
    • "); - } - - questInfo.append(getQuestItemsTaskString(stage.getBlocksToBreak(), "
    • Break ")).append("
    • "); - questInfo.append(getQuestItemsTaskString(stage.getBlocksToCut(), "
    • Cut ")).append("
    • "); - questInfo.append(getQuestItemsTaskString(stage.getBlocksToDamage(), "
    • Damage ")).append("
    • "); - questInfo.append(getQuestItemsTaskString(stage.getBlocksToUse(), "
    • Use ")).append("
    • "); - questInfo.append(getQuestItemsTaskString(stage.getBlocksToPlace(), "
    • Place ")).append("
    • "); - - questInfo.append(getQuestItemsTaskString(stage.getItemsToBrew(), "
    • Brew ")).append("
    • "); - questInfo.append(getQuestItemsTaskString(stage.getItemsToConsume(), "
    • Consume ")).append("
    • "); - questInfo.append(getQuestItemsTaskString(stage.getItemsToCraft(), "
    • Craft ")).append("
    • "); - questInfo.append(getQuestItemsTaskString(stage.getItemsToEnchant(), "
    • Enchant ")).append("
    • "); - questInfo.append(getQuestItemsTaskString(stage.getItemsToSmelt(), "
    • Smelt ")).append("
    • "); - - int sheepTypes = stage.getSheepToShear().size(); - for (int i = 0; i < sheepTypes; i++) { - questInfo.append("
    • Shear ").append(stage.getSheepNumToShear().get(i)).append(" ").append( - normalizeName(stage.getSheepToShear().get(i).name())).append(" sheep").append("
    • "); - } - if (stage.getCowsToMilk() != null) { - questInfo.append("
    • Milk ").append(stage.getCowsToMilk()).append(" cows").append("
    • "); - } - - int mobTamingEntries = stage.getMobsToTame().size(); - for (int i = 0; i < mobTamingEntries; i++) { - questInfo.append("
    • Tame ").append(stage.getMobNumToTame().get(i)).append(" ").append( - normalizeName(stage.getMobsToTame().get(i).name())).append("
    • "); - } - - questInfo.append("
    "); - } - return questInfo.toString(); - } - - /** - * Gets a string to display a quest task involving some action on an item - * - * @param items

    The items that are part of the task

    - * @param explanation

    The explanation of what the player needs to do with the items

    - * @return

    A string describing the necessary tasks

    - */ - private String getQuestItemsTaskString(List items, String explanation) { - StringBuilder questInfo = new StringBuilder(); - for (ItemStack itemStack : items) { - questInfo.append(explanation).append(getItemStackString(itemStack)); - } - return questInfo.toString(); - } - - /** - * Gets the proper string representation of an item stack - * - * @param itemStack

    The item stack to print

    - * @return

    The string representation of the item stack

    - */ - private String getItemStackString(ItemStack itemStack) { - return normalizeName(itemStack.getType().name()) + " X " + itemStack.getAmount(); - } - - /** - * Makes the first character in a string uppercase - * - * @param string

    The string to run on

    - * @return

    The same string, with the first character converted to uppercase

    - */ - private String uppercaseFirst(String string) { - return string.substring(0, 1).toUpperCase() + string.substring(1); - } - - /** - * Normalizes an internal name to make it human-readable - * - * @param name

    The name to normalize

    - * @return

    The normalized name

    - */ - private String normalizeName(String name) { - return name.toLowerCase().replace("_", " "); - } - - /** - * Marks any reach locations found in the given stage - * - * @param quest

    The quest the stage belongs to

    - * @param stage

    The stage to search for reach locations

    - */ - private void markReachLocations(IQuest quest, IStage stage) { - markLocations(stage.getLocationsToReach(), stage.getRadiiToReachWithin(), - "Target location for: " + quest.getName()); - } - - /** - * Marks any kill locations found in the given stage - * - * @param quest

    The quest the stage belongs to

    - * @param stage

    The stage to search for kill locations

    - */ - private void markKillLocations(IQuest quest, IStage stage) { - markLocations(stage.getLocationsToKillWithin(), stage.getRadiiToKillWithin(), - "Kill location for: " + quest.getName()); - } - - /** - * Marks the given locations on the dynamic map - * - * @param locations

    The locations to mark

    - * @param radii

    The radius of each location's circle

    - * @param description

    The description for what the location means

    - */ - private void markLocations(List locations, List radii, String description) { - for (int i = 0; i < locations.size(); i++) { - Location location = locations.get(i); - int radius = radii.get(i); - - //Skip if location is invalid - World world = location.getWorld(); - if (world == null) { - continue; - } - - CircleMarker circleMarker = questAreaMarkerSet.createCircleMarker(null, description, true, - world.getName(), location.getX(), location.getY(), location.getZ(), radius, radius, false); - if (circleMarker == null) { - DynmapCitizens.getInstance().getLogger().log(Level.WARNING, "Unable to create circle marker at " + - location + " with radius " + radius); - } else { - circleMarker.setFillStyle(0.3, 0x75AFD2); - circleMarker.setLineStyle(1, 1.0, 0x36c90e); - } - } - } - -} diff --git a/src/main/java/net/knarcraft/dynmapcitizens/util/QuestsHelper.java b/src/main/java/net/knarcraft/dynmapcitizens/util/QuestsHelper.java new file mode 100644 index 0000000..21b06e3 --- /dev/null +++ b/src/main/java/net/knarcraft/dynmapcitizens/util/QuestsHelper.java @@ -0,0 +1,84 @@ +package net.knarcraft.dynmapcitizens.util; + +import net.knarcraft.dynmapcitizens.DynmapCitizens; +import net.knarcraft.dynmapcitizens.handler.VaultHandler; +import net.knarcraft.dynmapcitizens.handler.trait.quests.QuestNPCType; +import org.bukkit.inventory.ItemStack; + +/** + * A helper class for various quests-related tasks + */ +public class QuestsHelper { + + /** + * Gets an item stack string with the first character upper-cased + * + * @param itemStack

    The item stack to get the string for

    + * @return

    A string describing the item stack

    + */ + public static String getUpperCasedItemStackString(ItemStack itemStack) { + return uppercaseFirst(getItemStackString(itemStack)); + } + + /** + * Gets the proper string representation of an item stack + * + * @param itemStack

    The item stack to print

    + * @return

    The string representation of the item stack

    + */ + public static String getItemStackString(ItemStack itemStack) { + return normalizeName(itemStack.getType().name()) + " x " + itemStack.getAmount(); + } + + /** + * Makes the first character in a string uppercase + * + * @param string

    The string to run on

    + * @return

    The same string, with the first character converted to uppercase

    + */ + private static String uppercaseFirst(String string) { + return string.substring(0, 1).toUpperCase() + string.substring(1); + } + + /** + * Normalizes an internal name to make it human-readable + * + * @param name

    The name to normalize

    + * @return

    The normalized name

    + */ + public static String normalizeName(String name) { + return name.toLowerCase().replace("_", " "); + } + + /** + * Gets the currency to print for the given amount of money + * + * @param money

    The amount to pay/use

    + * @return

    The currency name to use

    + */ + public static String getCurrency(double money) { + VaultHandler vaultHandler = DynmapCitizens.getInstance().getVaultHandler(); + if (vaultHandler.isEnabled()) { + return vaultHandler.getCurrency(money != 1); + } else { + return "money"; + } + } + + /** + * Gets the marker title to use for the given quest NPC type + * + * @param type

    The type of marker to get the title for

    + * @return

    The title to use for the marker

    + */ + public static String getMarkerTitle(QuestNPCType type) { + return switch (type) { + case GIVER -> "Quest Start NPC: "; + case INTERACT -> "Quest Interact NPC: "; + case DELIVER -> "Quest Deliver NPC: "; + case KILL -> "Quest Kill NPC: "; + case CHAIN -> "Quest Chain NPC: "; + }; + } + +} diff --git a/src/main/java/net/knarcraft/dynmapcitizens/util/TimeFormatter.java b/src/main/java/net/knarcraft/dynmapcitizens/util/TimeFormatter.java new file mode 100644 index 0000000..5ebc8ba --- /dev/null +++ b/src/main/java/net/knarcraft/dynmapcitizens/util/TimeFormatter.java @@ -0,0 +1,98 @@ +package net.knarcraft.dynmapcitizens.util; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static net.knarcraft.blacksmith.formatting.StringFormatter.replacePlaceholder; + +/** + * A helper class for time formatting + */ +public class TimeFormatter { + + /** + * Gets a datetime string for the given timestamp + * + * @param timestamp

    A timestamp in milliseconds

    + * @return

    A datetime string

    + */ + public static String formatTimestamp(long timestamp) { + DateFormat format = new SimpleDateFormat("dd MM yyyy HH:mm:ss"); + Date date = new Date(timestamp); + return format.format(date); + } + + /** + * Gets the string used for displaying this sign's duration + * + * @return

    The string used for displaying this sign's duration

    + */ + public static String getDurationString(long duration) { + if (duration == 0) { + return "immediately"; + } else { + double minute = 60; + double hour = minute * 60; + double day = hour * 24; + double week = day * 7; + double month = day * 30; + double year = day * 365; + double decade = year * 10; + + Map timeUnits = new HashMap<>(); + timeUnits.put(decade, new String[]{"decade", "decades"}); + timeUnits.put(year, new String[]{"year", "years"}); + timeUnits.put(month, new String[]{"month", "months"}); + timeUnits.put(week, new String[]{"week", "weeks"}); + timeUnits.put(day, new String[]{"day", "days"}); + timeUnits.put(hour, new String[]{"hour", "hours"}); + timeUnits.put(minute, new String[]{"minute", "minutes"}); + timeUnits.put(1D, new String[]{"second", "seconds"}); + + List sortedUnits = new ArrayList<>(timeUnits.keySet()); + Collections.sort(sortedUnits); + Collections.reverse(sortedUnits); + + for (Double unit : sortedUnits) { + if (duration / unit >= 1) { + double units = round(duration / unit); + return formatDurationString(units, timeUnits.get(unit)[units == 1 ? 0 : 1], + (units * 10) % 10 == 0); + } + } + return formatDurationString(duration, "seconds", false); + } + } + + /** + * Rounds a number to its last two digits + * + * @param number

    The number to round

    + * @return

    The rounded number

    + */ + private static double round(double number) { + return Math.round(number * 100.0) / 100.0; + } + + /** + * Formats a duration string + * + * @param duration

    The duration to display

    + * @param translatableMessage

    The time unit to display

    + * @param castToInt

    Whether to cast the duration to an int

    + * @return

    The formatted duration string

    + */ + private static String formatDurationString(double duration, String translatableMessage, boolean castToInt) { + String durationFormat = "{duration} {unit}"; + durationFormat = replacePlaceholder(durationFormat, "{unit}", translatableMessage); + return replacePlaceholder(durationFormat, "{duration}", castToInt ? String.valueOf((int) duration) : + String.valueOf(duration)); + } + +}