commit c3c52634255ec1612cdf2109120f0b968ae6f9ad Author: EpicKnarvik97 Date: Wed Oct 19 02:44:44 2022 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4788b4b --- /dev/null +++ b/.gitignore @@ -0,0 +1,113 @@ +# User-specific stuff +.idea/ + +*.iml +*.ipr +*.iws + +# IntelliJ +out/ + +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +target/ + +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next + +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +.mvn/wrapper/maven-wrapper.jar +.flattened-pom.xml + +# Common working directory +run/ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..2c5bb09 --- /dev/null +++ b/pom.xml @@ -0,0 +1,123 @@ + + + 4.0.0 + + net.knarcraft + DynmapCitizens + 1.0-SNAPSHOT + jar + + Dynmap-Citizens + + A plugin for displaying citizens on the dynmap map + + 17 + UTF-8 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 17 + 17 + + + + org.apache.maven.plugins + maven-shade-plugin + 3.2.4 + + + package + + shade + + + false + + + + + + + + src/main/resources + true + + + + + + + codemc-repo + https://repo.codemc.io/repository/maven-public/ + + + spigotmc-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + sonatype + https://oss.sonatype.org/content/groups/public/ + + + dynmap + https://repo.mikeprimm.com/ + + + citizens-repo + http://repo.citizensnpcs.co/ + + + + + + org.spigotmc + spigot-api + 1.19.2-R0.1-SNAPSHOT + provided + + + net.citizensnpcs + citizens-main + 2.0.30-SNAPSHOT + jar + provided + + + * + * + + + + + me.blackvein.quests + quests-api + 4.6.0 + provided + + + me.blackvein.quests + quests-core + 4.6.0 + provided + + + us.dynmap + dynmap-api + 3.4 + provided + + + net.knarcraft + blacksmith + 1.0.0-SNAPSHOT + + + diff --git a/src/main/java/net/knarcraft/questsdynmap/DynmapCitizens.java b/src/main/java/net/knarcraft/questsdynmap/DynmapCitizens.java new file mode 100644 index 0000000..6a3f936 --- /dev/null +++ b/src/main/java/net/knarcraft/questsdynmap/DynmapCitizens.java @@ -0,0 +1,99 @@ +package net.knarcraft.questsdynmap; + +import me.blackvein.quests.QuestsAPI; +import org.bukkit.Bukkit; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginManager; +import org.bukkit.plugin.java.JavaPlugin; +import org.dynmap.DynmapAPI; +import org.dynmap.markers.MarkerAPI; +import org.dynmap.markers.MarkerIcon; +import org.dynmap.markers.MarkerSet; + +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; + +@SuppressWarnings("unused") +public final class DynmapCitizens extends JavaPlugin { + + private static DynmapCitizens instance; + + @Override + public void onEnable() { + instance = this; + //Initialize quest and dynmap APIs + PluginManager pluginManager = Bukkit.getPluginManager(); + Plugin dynmapPlugin = pluginManager.getPlugin("dynmap"); + if (!(dynmapPlugin instanceof DynmapAPI dynmapAPI) || dynmapAPI.getMarkerAPI() == null) { + this.getLogger().log(Level.SEVERE, "Could not initialize Dynmap"); + this.onDisable(); + return; + } + + QuestsAPI questsAPI = (QuestsAPI) Bukkit.getServer().getPluginManager().getPlugin("Quests"); + + MarkerSet questMarkerSet = getMarkerSet(dynmapAPI, "quests", "Quests"); + MarkerSet questAreaMarkerSet = getMarkerSet(dynmapAPI, "quest_areas", "Quest areas"); + MarkerSet blacksmithSet = getMarkerSet(dynmapAPI, "blacksmiths", "Blacksmiths"); + if (questMarkerSet == null || questAreaMarkerSet == null || blacksmithSet == null) { + return; + } + + //TODO: Perhaps make this configurable + questMarkerSet.setHideByDefault(false); + questAreaMarkerSet.setHideByDefault(true); + blacksmithSet.setHideByDefault(false); + //TODO: Make every icon configurable + MarkerAPI markerAPI = dynmapAPI.getMarkerAPI(); + Map markerIcons = new HashMap<>(); + markerIcons.put(Icon.QUEST_GIVER, markerAPI.getMarkerIcon("exclamation")); + markerIcons.put(Icon.QUEST_DELIVER, markerAPI.getMarkerIcon("basket")); + markerIcons.put(Icon.QUEST_KILL, markerAPI.getMarkerIcon("skull")); + markerIcons.put(Icon.QUEST_INTERACT, markerAPI.getMarkerIcon("comment")); + markerIcons.put(Icon.BLACKSMITH, markerAPI.getMarkerIcon("hammer")); + DynmapDrawer.initialize(questsAPI, questMarkerSet, questAreaMarkerSet, blacksmithSet, markerIcons); + + Bukkit.getScheduler().runTaskTimer(this, this::updateIcons, 10 * 20, 120 * 20); + } + + @Override + public void onDisable() { + // Plugin shutdown logic + } + + /** + * Gets an instance of this plugin + * + * @return

An instance of this plugin

+ */ + public static DynmapCitizens getInstance() { + return instance; + } + + /** + * Gets the given marker set (and creates it if necessary) + * + * @param dynmapAPI

A reference to dynmap's API

+ * @param setId

The id of the marker set to get

+ * @param label

The label of the marker set if creation is necessary

+ * @return

The marker set, or null if something went wrong

+ */ + private MarkerSet getMarkerSet(DynmapAPI dynmapAPI, String setId, String label) { + MarkerSet markerSet = dynmapAPI.getMarkerAPI().getMarkerSet(setId); + if (markerSet == null) { + markerSet = dynmapAPI.getMarkerAPI().createMarkerSet(setId, label, null, false); + if (markerSet == null) { + this.getLogger().log(Level.SEVERE, "Unable to get or create " + setId + " marker set"); + this.onDisable(); + return null; + } + } + return markerSet; + } + + private void updateIcons() { + DynmapDrawer.updateCitizensMarkers(); + } + +} diff --git a/src/main/java/net/knarcraft/questsdynmap/DynmapDrawer.java b/src/main/java/net/knarcraft/questsdynmap/DynmapDrawer.java new file mode 100644 index 0000000..48937bc --- /dev/null +++ b/src/main/java/net/knarcraft/questsdynmap/DynmapDrawer.java @@ -0,0 +1,211 @@ +package net.knarcraft.questsdynmap; + +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.NPC; +import net.citizensnpcs.api.trait.Trait; +import org.bukkit.Location; +import org.bukkit.World; +import org.dynmap.markers.CircleMarker; +import org.dynmap.markers.GenericMarker; +import org.dynmap.markers.Marker; +import org.dynmap.markers.MarkerIcon; +import org.dynmap.markers.MarkerSet; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.logging.Level; + +/** + * A class for rendering icons and areas on dynmap + */ +public class DynmapDrawer { + + private static MarkerSet questMarkerSet; + private static MarkerSet questAreaMarkerSet; + private static MarkerSet blacksmithSet; + private static QuestsAPI questsAPI; + private static Map markerIcons; + + private DynmapDrawer() { + + } + + /** + * Initializes the dynmap drawer + * + * @param questsAPI

The quests API to get quest information from

+ * @param questMarkerSet

The marker set for quests

+ * @param questAreaMarkerSet

The marker set for quest areas

+ * @param blacksmithSet

The marker set for blacksmiths

+ * @param markerIcons

The marker icons to use

+ */ + public static void initialize(QuestsAPI questsAPI, MarkerSet questMarkerSet, MarkerSet questAreaMarkerSet, + MarkerSet blacksmithSet, Map markerIcons) { + if (DynmapDrawer.questsAPI != null || DynmapDrawer.questMarkerSet != null || + DynmapDrawer.questAreaMarkerSet != null || DynmapDrawer.markerIcons != null) { + throw new IllegalStateException("The dynmap drawer has already been initialized"); + } + + DynmapDrawer.questsAPI = questsAPI; + DynmapDrawer.questMarkerSet = questMarkerSet; + DynmapDrawer.questAreaMarkerSet = questAreaMarkerSet; + DynmapDrawer.blacksmithSet = blacksmithSet; + DynmapDrawer.markerIcons = new HashMap<>(markerIcons); + } + + /** + * Updates markers for all quests + */ + public static void updateCitizensMarkers() { + if (questsAPI.isLoading()) { + return; + } + + //Remove old quest markers + questMarkerSet.getMarkers().forEach(GenericMarker::deleteMarker); + blacksmithSet.getMarkers().forEach(GenericMarker::deleteMarker); + questAreaMarkerSet.getCircleMarkers().forEach(GenericMarker::deleteMarker); + + for (IQuest quest : questsAPI.getLoadedQuests()) { + UUID npcStartId = quest.getNpcStart(); + if (npcStartId != null) { + String markerDescription = "Quest name: " + quest.getName() + "
Quest description: " + quest.getDescription(); + addNPCMarker(npcStartId, "Quest Start NPC: ", markerDescription, markerIcons.get(Icon.QUEST_GIVER), questMarkerSet); + } + for (IStage stage : quest.getStages()) { + markNPCsInQuest(quest, stage, npcStartId); + markKillLocations(quest, stage); + markReachLocations(quest, stage); + //TODO: Mark WorldGuard areas part of quests. Requires WorldGuard integration + //TODO: See if there is anything to do against overlapping markers + } + } + + //Mark all blacksmiths on the map + Class blacksmithTrait = CitizensAPI.getTraitFactory().getTraitClass("blacksmith"); + for (NPC npc : CitizensAPI.getNPCRegistry()) { + if (npc.hasTrait(blacksmithTrait)) { + addNPCMarker(npc.getUniqueId(), "Blacksmith NPC: ", "", + markerIcons.get(Icon.BLACKSMITH), blacksmithSet); + } + } + } + + /** + * 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 static void markReachLocations(IQuest quest, IStage stage) { + markLocations(stage.getLocationsToReach(), stage.getRadiiToReachWithin(), + "Target location for: " + quest.getName() + "
Description: " + + quest.getDescription()); + } + + /** + * 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 static void markKillLocations(IQuest quest, IStage stage) { + markLocations(stage.getLocationsToKillWithin(), stage.getRadiiToKillWithin(), + "Kill location for: " + quest.getName() + "
Description: " + + quest.getDescription()); + } + + /** + * 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 static 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); + } + } + } + + /** + * Marks all NPCs which has interactions as part of this stage + * + * @param quest

The quest to mark NPCs for

+ * @param stage

The quest stage to mark NPCs for

+ * @param npcStartId

The id of the quest's start NPC

+ */ + private static void markNPCsInQuest(IQuest quest, IStage stage, UUID npcStartId) { + String markerDescription = "Part of quest: " + quest.getName(); + //Mark all interaction targets + for (UUID interactNpcId : stage.getNpcsToInteract()) { + addNPCMarker(interactNpcId, "Quest Interact NPC: ", markerDescription, + markerIcons.get(Icon.QUEST_INTERACT), questMarkerSet); + } + //Mark all kill targets + for (UUID killNPCId : stage.getNpcsToKill()) { + addNPCMarker(killNPCId, "Quest Kill NPC: ", markerDescription, markerIcons.get(Icon.QUEST_KILL), + questMarkerSet); + } + //Mark all delivery targets + for (UUID deliveryTargetNPCId : stage.getItemDeliveryTargets()) { + if (!deliveryTargetNPCId.equals(npcStartId)) { + addNPCMarker(deliveryTargetNPCId, "Quest Delivery NPC: ", markerDescription, + markerIcons.get(Icon.QUEST_DELIVER), questMarkerSet); + } + } + } + + /** + * Adds a marker for an NPC + * + * @param npcId

The if of the NPC

+ * @param markerName

The name of the NPC marker

+ * @param markerDescription

The description of the NPC marker

+ * @param icon

The icon used for the marker

+ * @param markerSet

The marker set to add the marker to

+ */ + private static void addNPCMarker(UUID npcId, String markerName, String markerDescription, MarkerIcon icon, MarkerSet markerSet) { + NPC npc = CitizensAPI.getNPCRegistry().getByUniqueId(npcId); + //If the NPC has been removed, abort + if (npc == null) { + return; + } + + //Skip if not a proper location + Location npcLocation = npc.getStoredLocation(); + World world = npcLocation.getWorld(); + if (world == null) { + return; + } + + Marker marker = markerSet.createMarker(null, markerName + npc.getName(), npcLocation.getWorld().getName(), + npcLocation.getX(), npcLocation.getY(), npcLocation.getZ(), icon, false); + if (marker != null) { + marker.setDescription(markerDescription); + } + } + +} diff --git a/src/main/java/net/knarcraft/questsdynmap/Icon.java b/src/main/java/net/knarcraft/questsdynmap/Icon.java new file mode 100644 index 0000000..fe50267 --- /dev/null +++ b/src/main/java/net/knarcraft/questsdynmap/Icon.java @@ -0,0 +1,11 @@ +package net.knarcraft.questsdynmap; + +public enum Icon { + + QUEST_GIVER, + QUEST_INTERACT, + QUEST_KILL, + QUEST_DELIVER, + BLACKSMITH + +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..c360e2c --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,8 @@ +name: DynmapCitizens +version: '${project.version}' +main: net.knarcraft.questsdynmap.DynmapCitizens +api-version: 1.19 +prefix: DynmapCitizens +depend: [ dynmap, Quests, Citizens, Blacksmith ] +authors: [ EpicKnarvik97 ] +description: A plugin for displaying citizens info on the dynmap map