Merge branch 'custom-formatting'
All checks were successful
KnarCraft/DynmapCitizens/pipeline/head This commit looks good

This commit is contained in:
2023-10-17 04:11:43 +02:00
19 changed files with 696 additions and 183 deletions

View File

@ -0,0 +1,53 @@
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.property.Icon;
import net.knarcraft.dynmapcitizens.settings.DTLTradersSettings;
import net.knarcraft.dynmapcitizens.settings.TraitSettings;
import org.dynmap.markers.GenericMarker;
/**
* A handler class for the minstrel trait
*/
public class DTLTradersHandler extends AbstractTraitHandler {
private final DTLTradersSettings settings = new DTLTradersSettings();
@Override
public void initialize() {
super.isEnabled = false;
CitizensAPI.getTraitFactory().getRegisteredTraits().forEach(traitInfo -> {
if (traitInfo.getTraitName().equals("trader")) {
super.isEnabled = true;
}
});
if (this.isEnabled) {
super.initializeMarkerSet();
}
}
@Override
public TraitSettings getSettings() {
return this.settings;
}
@Override
public void updateMarkers() {
//Remove existing markers
super.markerSet.getMarkers().forEach(GenericMarker::deleteMarker);
Class<? extends Trait> traderTrait = CitizensAPI.getTraitFactory().getTraitClass("trader");
for (NPC npc : CitizensAPI.getNPCRegistry()) {
if (npc.hasTrait(traderTrait)) {
String description = "<h2>" + npc.getName() + "</h2>";
addNPCMarker(npc.getUniqueId(), "Trader NPC: ", description,
DynmapCitizens.getInstance().getGlobalSettings().getMarkerIcons().get(Icon.TRADER), super.markerSet);
}
}
}
}

View File

@ -47,12 +47,14 @@ public class SentinelHandler extends AbstractTraitHandler {
description += "<br><b>Squad:</b> " + trait.squad;
}
if (settings.displaySentinelStats()) {
description += "<br><b>Invincible:</b> " + trait.invincible + "<br><b>Armor:</b> " +
trait.armor + "<br><b>Health:</b> " + trait.health + "<br><b>Accuracy:</b> " + trait.accuracy +
"<br><b>Damage:</b> " + trait.damage + "<br><b>Allow knockback:</b> " + trait.allowKnockback;
description += "<br><b>Invincible:</b> " + trait.invincible + "<br><b>Armor:</b> " + trait.armor;
description += "<br><b>Health:</b> " + trait.health + "<br><b>Accuracy:</b> " + trait.accuracy;
description += "<br><b>Damage:</b> " + trait.damage + "<br><b>Speed:</b> " + trait.speed;
description += "<br><b>Allow knockback:</b> " + trait.allowKnockback;
description += "<br><b>Range:</b> " + trait.range + "<br><b>Reach:</b> " + trait.reach;
description += "<br><b>Targets:</b> " + trait.allTargets.toAllInOneString() + "<br><b>Avoids:</b> " +
trait.allAvoids.toAllInOneString() + "<br><b>Ignores:</b> " + trait.allIgnores.toAllInOneString();
description += "<br><b>Targets:</b> " + trait.allTargets.toAllInOneString();
description += "<br><b>Avoids:</b> " + trait.allAvoids.toAllInOneString();
description += "<br><b>Ignores:</b> " + trait.allIgnores.toAllInOneString();
}
addNPCMarker(npc.getUniqueId(), "Sentinel NPC: ", description,
DynmapCitizens.getInstance().getGlobalSettings().getMarkerIcons().get(Icon.SENTINEL), super.markerSet);

View File

@ -3,9 +3,13 @@ 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.knarcraft.dynmapcitizens.DynmapCitizens;
import net.knarcraft.dynmapcitizens.settings.QuestsSettings;
import net.knarcraft.dynmapcitizens.util.DynmapHelper;
import net.knarcraft.dynmapcitizens.util.QuestsHelper;
import net.knarcraft.knarlib.formatting.StringFormatter;
import net.knarcraft.knarlib.formatting.StringReplacer;
import net.knarcraft.knarlib.formatting.Translator;
import org.bukkit.Location;
import org.bukkit.entity.EntityType;
import org.dynmap.DynmapAPI;
@ -14,6 +18,11 @@ import org.dynmap.markers.MarkerSet;
import java.util.List;
import static net.knarcraft.dynmapcitizens.formatting.QuestsTranslatableMessage.QUESTS_KILL_AREA_DESCRIPTION_FORMAT;
import static net.knarcraft.dynmapcitizens.formatting.QuestsTranslatableMessage.QUESTS_KILL_AREA_NAME_FORMAT;
import static net.knarcraft.dynmapcitizens.formatting.QuestsTranslatableMessage.QUESTS_REACH_AREA_DESCRIPTION_FORMAT;
import static net.knarcraft.dynmapcitizens.formatting.QuestsTranslatableMessage.QUESTS_REACH_AREA_NAME_FORMAT;
/**
* A handler class for quest areas
*/
@ -24,6 +33,7 @@ public class QuestAreaHandler {
private final MarkerSet reachAreaMarkerSet;
private final QuestsSettings settings;
private final List<IQuest> unavailableQuests;
private final StringFormatter formatter;
/**
* Instantiates a new quest area handler
@ -38,6 +48,7 @@ public class QuestAreaHandler {
this.questsAPI = questsAPI;
this.settings = settings;
this.unavailableQuests = unavailableQuests;
this.formatter = DynmapCitizens.getFormatter();
killAreaMarkerSet = DynmapHelper.initializeMarkerSet(dynmapAPI, settings.getKillAreaSettings());
reachAreaMarkerSet = DynmapHelper.initializeMarkerSet(dynmapAPI, settings.getReachAreaSettings());
}
@ -75,11 +86,16 @@ public class QuestAreaHandler {
Location location = stage.getLocationsToReach().get(i);
int radius = stage.getRadiiToReachWithin().get(i);
String areaName = stage.getLocationNames().get(i);
String description = "";
String formattedAreaName;
if (areaName != null) {
description += "<b>" + areaName + "</b><br>";
formattedAreaName = formatter.replacePlaceholder(QUESTS_REACH_AREA_NAME_FORMAT, "{name}", areaName);
} else {
formattedAreaName = "";
}
description += "Target location for " + quest.getName();
String description = formatter.replacePlaceholders(QUESTS_REACH_AREA_DESCRIPTION_FORMAT,
new String[]{"{areaName}", "{questName}"}, new String[]{formattedAreaName, quest.getName()});
DynmapHelper.markLocation(location, radius, description, reachAreaMarkerSet, settings.getReachAreaSettings());
}
}
@ -101,13 +117,20 @@ public class QuestAreaHandler {
int mobAmount = stage.getMobNumToKill().get(i);
String areaName = stage.getKillNames().get(i);
String description = "";
String formattedAreaName;
if (areaName != null) {
description += "<b>" + areaName + "</b><br>";
formattedAreaName = formatter.replacePlaceholder(QUESTS_KILL_AREA_NAME_FORMAT, "{name}", areaName);
} else {
formattedAreaName = "";
}
description += "Kill location for " + quest.getName() +
"<br>Kill " + QuestsHelper.normalizeName(mob.name()) + " x " + mobAmount;
DynmapHelper.markLocation(location, radius, description, killAreaMarkerSet, settings.getKillAreaSettings());
Translator translator = DynmapCitizens.getTranslator();
StringReplacer replacer = new StringReplacer(translator.getTranslatedMessage(QUESTS_KILL_AREA_DESCRIPTION_FORMAT));
replacer.add("{areaName}", formattedAreaName);
replacer.add("{questName}", quest.getName());
replacer.add("{mobName}", QuestsHelper.normalizeName(mob.name()));
replacer.add("{mobAmount}", String.valueOf(mobAmount));
DynmapHelper.markLocation(location, radius, replacer.replace(), killAreaMarkerSet, settings.getKillAreaSettings());
}
}

View File

@ -2,7 +2,12 @@ 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;
import net.knarcraft.dynmapcitizens.DynmapCitizens;
import net.knarcraft.knarlib.formatting.TimeFormatter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* A class to generate a string containing all information about a quest's planner info
@ -33,7 +38,8 @@ public class QuestPlannerInfoGenerator {
//Quest can be repeated after a cool-down
if (planner.hasCooldown()) {
plannerInfo.append("<li>Quest repeatable after: ");
plannerInfo.append(TimeFormatter.getDurationString(planner.getCooldown() / 1000));
plannerInfo.append(TimeFormatter.getDurationString(DynmapCitizens.getTranslator(),
planner.getCooldown() / 1000));
plannerInfo.append("</li>");
} else {
plannerInfo.append("<li>Quest cannot be repeated!</li>");
@ -42,23 +48,36 @@ public class QuestPlannerInfoGenerator {
//Quest only becomes available after the start date
if (planner.hasStart()) {
plannerInfo.append("<li>Quest available from ");
plannerInfo.append(TimeFormatter.formatTimestamp(planner.getStartInMillis())).append("</li>");
plannerInfo.append(formatTimestamp(planner.getStartInMillis())).append("</li>");
}
//Quest is only available until the end date
if (planner.hasEnd()) {
plannerInfo.append("<li>Quest available until ");
plannerInfo.append(TimeFormatter.formatTimestamp(planner.getEndInMillis())).append("</li>");
plannerInfo.append(formatTimestamp(planner.getEndInMillis())).append("</li>");
}
//Quest availability repeats
if (planner.hasRepeat()) {
plannerInfo.append("<li>Quest will become available again after ");
plannerInfo.append(TimeFormatter.getDurationString(planner.getRepeat() / 1000)).append("</li>");
plannerInfo.append(TimeFormatter.getDurationString(DynmapCitizens.getTranslator(),
planner.getRepeat() / 1000)).append("</li>");
}
plannerInfo.append("</ul>");
return plannerInfo.toString();
}
/**
* Gets a datetime string for the given timestamp
*
* @param timestamp <p>A timestamp in milliseconds</p>
* @return <p>A datetime string</p>
*/
private String formatTimestamp(long timestamp) {
DateFormat format = new SimpleDateFormat("dd MM yyyy HH:mm:ss");
Date date = new Date(timestamp);
return format.format(date);
}
}

View File

@ -1,27 +1,51 @@
package net.knarcraft.dynmapcitizens.handler.trait.quests;
import me.blackvein.quests.QuestsAPI;
import me.blackvein.quests.quests.IQuest;
import me.blackvein.quests.quests.Requirements;
import net.knarcraft.dynmapcitizens.DynmapCitizens;
import net.knarcraft.dynmapcitizens.util.QuestsHelper;
import net.knarcraft.knarlib.formatting.StringFormatter;
import net.knarcraft.knarlib.formatting.StringReplacer;
import net.knarcraft.knarlib.formatting.TranslatableMessage;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static net.knarcraft.dynmapcitizens.formatting.QuestsTranslatableMessage.QUESTS_REQUIREMENTS_BLOCKED_BY_QUEST_FORMAT;
import static net.knarcraft.dynmapcitizens.formatting.QuestsTranslatableMessage.QUESTS_REQUIREMENTS_BLOCKED_BY_QUEST_ITEM;
import static net.knarcraft.dynmapcitizens.formatting.QuestsTranslatableMessage.QUESTS_REQUIREMENTS_EXP;
import static net.knarcraft.dynmapcitizens.formatting.QuestsTranslatableMessage.QUESTS_REQUIREMENTS_FORMAT;
import static net.knarcraft.dynmapcitizens.formatting.QuestsTranslatableMessage.QUESTS_REQUIREMENTS_MC_MMO_SKILL;
import static net.knarcraft.dynmapcitizens.formatting.QuestsTranslatableMessage.QUESTS_REQUIREMENTS_QUEST_POINTS;
import static net.knarcraft.dynmapcitizens.formatting.QuestsTranslatableMessage.QUESTS_REQUIREMENTS_REQUIRED_ITEM_FORMAT;
import static net.knarcraft.dynmapcitizens.formatting.QuestsTranslatableMessage.QUESTS_REQUIREMENTS_REQUIRED_ITEM_ITEM;
import static net.knarcraft.dynmapcitizens.formatting.QuestsTranslatableMessage.QUESTS_REQUIREMENTS_REQUIRED_PERMISSION_FORMAT;
import static net.knarcraft.dynmapcitizens.formatting.QuestsTranslatableMessage.QUESTS_REQUIREMENTS_REQUIRED_PERMISSION_ITEM;
import static net.knarcraft.dynmapcitizens.formatting.QuestsTranslatableMessage.QUESTS_REQUIREMENTS_REQUIRED_QUEST_FORMAT;
import static net.knarcraft.dynmapcitizens.formatting.QuestsTranslatableMessage.QUESTS_REQUIREMENTS_REQUIRED_QUEST_ITEM;
/**
* A class to generate a string containing all information about a quest's requirements
*/
public class QuestRequirementsInfoGenerator {
private final QuestsAPI questsAPI;
private final IQuest quest;
private final StringFormatter formatter;
/**
* Instantiates a new quest requirement info generator
*
* @param quest <p>The quest to generate information about</p>
* @param questsAPI <p>The API to use for getting quest information</p>
* @param quest <p>The quest to generate information about</p>
*/
public QuestRequirementsInfoGenerator(IQuest quest) {
public QuestRequirementsInfoGenerator(QuestsAPI questsAPI, IQuest quest) {
this.questsAPI = questsAPI;
this.quest = quest;
formatter = DynmapCitizens.getFormatter();
}
/**
@ -31,78 +55,140 @@ public class QuestRequirementsInfoGenerator {
*/
public String getQuestRequirementsInfo() {
Requirements requirements = quest.getRequirements();
StringBuilder requirementInfo = new StringBuilder();
if (!requirements.hasRequirement()) {
return requirementInfo.toString();
return "";
}
requirementInfo.append("<b>Requirements: </b><ul>");
StringReplacer replacer = new StringReplacer(DynmapCitizens.getTranslator().getTranslatedMessage(
QUESTS_REQUIREMENTS_FORMAT));
if (requirements.getQuestPoints() > 0) {
requirementInfo.append("<li>").append(requirements.getQuestPoints()).append(" quest points</li>");
}
//Add info about quest point requirement
replacer.add("{requirementQuestPoints}", requirements.getQuestPoints() > 0 ?
formatter.replacePlaceholder(QUESTS_REQUIREMENTS_QUEST_POINTS,
"{questPoints}", String.valueOf(requirements.getQuestPoints())) : "");
if (requirements.getExp() > 0) {
requirementInfo.append("<li>").append(requirements.getExp()).append(" exp</li>");
}
//Add info about exp requirement
replacer.add("{requirementExp}", requirements.getExp() > 0 ? formatter.replacePlaceholder(
QUESTS_REQUIREMENTS_EXP, "{exp}", String.valueOf(requirements.getExp())) : "");
if (!requirements.getBlockQuests().isEmpty()) {
requirementInfo.append("<li>Blocked by quests:<ul>");
for (IQuest blockQuest : requirements.getBlockQuests()) {
requirementInfo.append("<li>").append(blockQuest.getName()).append("</li>");
}
requirementInfo.append("</ul></li>");
}
//Add info about blocking quests
replacer.add("{requirementBlockedByQuests}", !requirements.getBlockQuestIds().isEmpty() ?
getRequirementList(getQuestNames(requirements.getBlockQuestIds()),
QUESTS_REQUIREMENTS_BLOCKED_BY_QUEST_FORMAT, "{blockingQuests}",
QUESTS_REQUIREMENTS_BLOCKED_BY_QUEST_ITEM, "{questName}") : "");
if (!requirements.getNeededQuests().isEmpty()) {
requirementInfo.append("<li>Required quests:<ul>");
for (IQuest neededQuest : requirements.getNeededQuests()) {
requirementInfo.append("<li>").append(neededQuest.getName()).append("</li>");
}
requirementInfo.append("</ul></li>");
}
//Add info about required quests
replacer.add("{requirementRequiredQuests}", !requirements.getBlockQuestIds().isEmpty() ?
getRequirementList(getQuestNames(requirements.getBlockQuestIds()),
QUESTS_REQUIREMENTS_REQUIRED_QUEST_FORMAT, "{requiredQuests}",
QUESTS_REQUIREMENTS_REQUIRED_QUEST_ITEM, "{questName}") : "");
if (!requirements.getItems().isEmpty()) {
requirementInfo.append("<li>Required items:<ul>");
for (ItemStack item : requirements.getItems()) {
requirementInfo.append("<li>").append(QuestsHelper.getUpperCasedItemStackString(item)).append("</li>");
}
requirementInfo.append("</ul></li>");
}
//Add info about required items
replacer.add("{requirementRequiredItems}", !requirements.getItems().isEmpty() ?
getRequirementList(getItemNames(requirements.getItems()), QUESTS_REQUIREMENTS_REQUIRED_ITEM_FORMAT,
"{requiredItems}", QUESTS_REQUIREMENTS_REQUIRED_ITEM_ITEM, "{itemName}") : "");
//Add info about required mcMMO skills
if (!requirements.getMcmmoSkills().isEmpty()) {
List<String> skills = requirements.getMcmmoSkills();
List<Integer> amounts = requirements.getMcmmoAmounts();
StringBuilder mcMMOSkillsBuilder = new StringBuilder();
for (int i = 0; i < skills.size(); i++) {
requirementInfo.append("<li>Requires mcMMO skill ").append(skills.get(i)).append(" at level ");
requirementInfo.append(amounts.get(i)).append("</li>");
mcMMOSkillsBuilder.append(formatter.replacePlaceholders(QUESTS_REQUIREMENTS_MC_MMO_SKILL, new String[]{
"{skill}", "{level}"}, new String[]{skills.get(i), String.valueOf(amounts.get(i))}));
}
replacer.add("{requirementMCMMOSkills}", mcMMOSkillsBuilder.toString());
} else {
replacer.add("{requirementMCMMOSkills}", "");
}
if (!requirements.getPermissions().isEmpty()) {
requirementInfo.append("<li>Required permissions:<ul>");
for (String permission : requirements.getPermissions()) {
requirementInfo.append("<li>").append(permission).append("</li>");
}
requirementInfo.append("</ul></li>");
}
//Add info about required permissions
replacer.add("{requirementPermissions}", !requirements.getPermissions().isEmpty() ?
getRequirementList(requirements.getPermissions(), QUESTS_REQUIREMENTS_REQUIRED_PERMISSION_FORMAT,
"{permissions}", QUESTS_REQUIREMENTS_REQUIRED_PERMISSION_ITEM, "{permission}") : "");
Map<String, Map<String, Object>> customRequirementPlugins = requirements.getCustomRequirements();
StringBuilder customRequirementsBuilder = new StringBuilder();
for (String plugin : customRequirementPlugins.keySet()) {
requirementInfo.append("<li>").append(plugin).append(":<ul>");
customRequirementsBuilder.append("<li>").append(plugin).append(":<ul>");
//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<String, Object> customRequirementEntry = customRequirementPlugins.get(plugin);
for (String requirementDescription : customRequirementEntry.keySet()) {
requirementInfo.append("<li>").append(requirementDescription).append(" ");
requirementInfo.append(customRequirementEntry.get(requirementDescription)).append("</li>");
customRequirementsBuilder.append("<li>").append(requirementDescription).append(" ");
customRequirementsBuilder.append(customRequirementEntry.get(requirementDescription)).append("</li>");
}
requirementInfo.append("</ul></li>");
customRequirementsBuilder.append("</ul></li>");
}
replacer.add("{requirementCustom}", customRequirementsBuilder.toString());
return replacer.replace();
}
requirementInfo.append("</ul>");
return requirementInfo.toString();
/**
* Gets a list of item names from the given list of items
*
* @param items <p>The items to get the names of</p>
* @return <p>The names of the given items</p>
*/
private List<String> getItemNames(List<ItemStack> items) {
List<String> itemNames = new ArrayList<>();
for (ItemStack itemStack : items) {
itemNames.add(QuestsHelper.getUpperCasedItemStackString(itemStack));
}
return itemNames;
}
/**
* Gets a list of the quest names for the given quests
*
* @param questIds <p>The quests to get names for</p>
* @return <p>A list of quest names</p>
*/
private List<String> getQuestNames(List<String> questIds) {
List<String> questNames = new ArrayList<>(questIds.size());
for (String questId : questIds) {
IQuest quest = getQuest(questId);
if (quest != null) {
questNames.add(quest.getName());
}
}
return questNames;
}
/**
* Gets the quest with the given id
*
* @param questId <p>The id of the quest to get</p>
* @return <p>The quest, or null if not found</p>
*/
private IQuest getQuest(String questId) {
for (IQuest quest : questsAPI.getLoadedQuests()) {
if (quest.getId().equals(questId)) {
return quest;
}
}
return null;
}
/**
* Gets a string for the given list of requirements
*
* @param itemList <p>The items to display in the list of requirements</p>
* @param formatMessage <p>The translatable message describing the list format</p>
* @param formatPlaceholder <p>The placeholder to replace with the list items</p>
* @param itemMessage <p>The translatable message describing each item's format</p>
* @param itemPlaceholder <p>The placeholder to replace with each item in the list</p>
* @return <p>The string corresponding to the given requirement list</p>
*/
private String getRequirementList(List<String> itemList, TranslatableMessage formatMessage, String formatPlaceholder,
TranslatableMessage itemMessage, String itemPlaceholder) {
StringBuilder blockedBuilder = new StringBuilder();
for (Object requirements : itemList) {
blockedBuilder.append(formatter.replacePlaceholder(itemMessage, itemPlaceholder,
String.valueOf(requirements)));
}
return formatter.replacePlaceholder(formatMessage, formatPlaceholder, blockedBuilder.toString());
}
}

View File

@ -94,6 +94,9 @@ public class QuestStagesInfoGenerator {
for (UUID npcId : stage.getNpcsToKill()) {
questInfo.append("<li>Kill NPC ").append(registry.getByUniqueId(npcId).getName()).append("</li>");
}
for (UUID npcId : stage.getNpcsToInteract()) {
questInfo.append("<li>Talk to ").append(registry.getByUniqueId(npcId).getName()).append("</li>");
}
questInfo.append(getQuestItemsTaskString(stage.getBlocksToBreak(), "<li>Break ")).append("</li>");
questInfo.append(getQuestItemsTaskString(stage.getBlocksToCut(), "<li>Cut ")).append("</li>");

View File

@ -163,7 +163,7 @@ public class QuestsHandler extends AbstractTraitHandler {
stringBuilder.append(new QuestRewardsInfoGenerator(quest).getQuestRewardsInfo());
}
if (settings.displayRequirementInfo()) {
stringBuilder.append(new QuestRequirementsInfoGenerator(quest).getQuestRequirementsInfo());
stringBuilder.append(new QuestRequirementsInfoGenerator(questsAPI, quest).getQuestRequirementsInfo());
}
if (settings.displayPlannerInfo()) {
stringBuilder.append(new QuestPlannerInfoGenerator(quest).getQuestPlannerInfo());