diff --git a/src/main/java/org/dynmap/Client.java b/src/main/java/org/dynmap/Client.java index dbf882fc..5f7e905f 100644 --- a/src/main/java/org/dynmap/Client.java +++ b/src/main/java/org/dynmap/Client.java @@ -4,6 +4,8 @@ import java.io.IOException; import java.io.Writer; import org.bukkit.ChatColor; +import org.dynmap.markers.Marker; +import org.dynmap.markers.MarkerSet; import org.json.simple.JSONAware; import org.json.simple.JSONStreamAware; @@ -77,4 +79,8 @@ public class Client { } } + public static class ComponentMessage extends Update { + public String type = "component"; + /* Each subclass must provide 'ctype' string for component 'type' */ + } } diff --git a/src/main/java/org/dynmap/DynmapPlugin.java b/src/main/java/org/dynmap/DynmapPlugin.java index 804db87b..e91c964e 100644 --- a/src/main/java/org/dynmap/DynmapPlugin.java +++ b/src/main/java/org/dynmap/DynmapPlugin.java @@ -59,6 +59,8 @@ import org.dynmap.debug.Debug; import org.dynmap.debug.Debugger; import org.dynmap.hdmap.HDBlockModels; import org.dynmap.hdmap.TexturePack; +import org.dynmap.markers.MarkerAPI; +import org.dynmap.markers.impl.MarkerAPIImpl; import org.dynmap.permissions.BukkitPermissions; import org.dynmap.permissions.NijikokunPermissions; import org.dynmap.permissions.OpPermissions; @@ -85,6 +87,8 @@ public class DynmapPlugin extends JavaPlugin { private HashMap> event_handlers = new HashMap>(); + private MarkerAPIImpl markerapi; + public static File dataDirectory; public static File tilesDirectory; @@ -208,6 +212,7 @@ public class DynmapPlugin extends JavaPlugin { permissions = new OpPermissions(new String[] { "fullrender", "cancelrender", "radiusrender", "resetstats", "reload" }); dataDirectory = this.getDataFolder(); + /* Load block models */ HDBlockModels.loadModels(dataDirectory); /* Load texture mappings */ @@ -278,11 +283,11 @@ public class DynmapPlugin extends JavaPlugin { if (!configuration.getBoolean("disable-webserver", false)) { startWebserver(); } - + /* Print version info */ PluginDescriptionFile pdfFile = this.getDescription(); Log.info("version " + pdfFile.getVersion() + " is enabled" ); - + events.trigger("initialized", null); } @@ -360,7 +365,10 @@ public class DynmapPlugin extends JavaPlugin { ll.clear(); /* Empty list - we use presence of list to remember that we've registered with Bukkit */ } playerfacemgr = null; - + if(markerapi != null) { + markerapi.cleanup(this); + markerapi = null; + } Debug.clearDebuggers(); } @@ -640,6 +648,9 @@ public class DynmapPlugin extends JavaPlugin { @Override public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) { + if(cmd.getName().equalsIgnoreCase("dmarker")) { + return MarkerAPIImpl.onCommand(this, sender, cmd, commandLabel, args); + } if (!cmd.getName().equalsIgnoreCase("dynmap")) return false; Player player = null; @@ -768,7 +779,7 @@ public class DynmapPlugin extends JavaPlugin { return false; } - private boolean checkPlayerPermission(CommandSender sender, String permission) { + public boolean checkPlayerPermission(CommandSender sender, String permission) { if (!(sender instanceof Player) || sender.isOp()) { return true; } else if (!permissions.has(sender, permission.toLowerCase())) { @@ -1163,4 +1174,24 @@ public class DynmapPlugin extends JavaPlugin { } ll.add(listener); } + /** + * ** This is the public API for other plugins to use for accessing the Marker API ** + * This method can return null if the 'markers' component has not been configured - + * a warning message will be issued to the server.log in this event. + * + * @return MarkerAPI, or null if not configured + */ + public MarkerAPI getMarkerAPI() { + if(markerapi == null) { + Log.warning("Marker API has been requested, but is not enabled. Uncomment or add 'markers' component to configuration.txt."); + } + return markerapi; + } + + /** + * Register markers API - used by component to supply marker API to plugin + */ + public void registerMarkerAPI(MarkerAPIImpl api) { + markerapi = api; + } } diff --git a/src/main/java/org/dynmap/MapManager.java b/src/main/java/org/dynmap/MapManager.java index 42c3d851..d5dd3621 100644 --- a/src/main/java/org/dynmap/MapManager.java +++ b/src/main/java/org/dynmap/MapManager.java @@ -790,7 +790,8 @@ public class MapManager { public void pushUpdate(String worldName, Object update) { DynmapWorld world = getWorld(worldName); - world.updates.pushUpdate(update); + if(world != null) + world.updates.pushUpdate(update); } public Object[] getWorldUpdates(String worldName, long since) { diff --git a/src/main/java/org/dynmap/MarkersComponent.java b/src/main/java/org/dynmap/MarkersComponent.java new file mode 100644 index 00000000..a6d189b5 --- /dev/null +++ b/src/main/java/org/dynmap/MarkersComponent.java @@ -0,0 +1,26 @@ +package org.dynmap; + +import org.dynmap.markers.impl.MarkerAPIImpl; + +/** + * Markers component - ties in the component system, both on the server and client + */ +public class MarkersComponent extends ClientComponent { + private MarkerAPIImpl api; + public MarkersComponent(DynmapPlugin plugin, ConfigurationNode configuration) { + super(plugin, configuration); + /* Register API with plugin */ + api = MarkerAPIImpl.initializeMarkerAPI(plugin); + plugin.registerMarkerAPI(api); + + } + @Override + public void dispose() { + if(api != null) { + /* Clean up API registered with plugin */ + plugin.registerMarkerAPI(null); + api.cleanup(this.plugin); + api = null; + } + } +} diff --git a/src/main/java/org/dynmap/markers/Marker.java b/src/main/java/org/dynmap/markers/Marker.java new file mode 100644 index 00000000..46f7b5b7 --- /dev/null +++ b/src/main/java/org/dynmap/markers/Marker.java @@ -0,0 +1,74 @@ +package org.dynmap.markers; + +import org.bukkit.Location; + +/** + * This defines the public interface to a marker object, for use with the MarkerAPI + */ +public interface Marker { + /** + * Get ID of the marker (unique string within the MarkerSet) + * @return id of marker + */ + public String getMarkerID(); + /** + * Get the marker set for the marker + * @return marker set + */ + public MarkerSet getMarkerSet(); + /** + * Delete the marker + */ + public void deleteMarker(); + /** + * Get marker's world ID + * @return world id + */ + public String getWorld(); + /** + * Get marker's X coordinate + * @return x coordinate + */ + public int getX(); + /** + * Get marker's Y coordinate + * @return y coordinate + */ + public int getY(); + /** + * Get marker's Z coordinate + * @return z coordinate + */ + public int getZ(); + /** + * Update the marker's location + * @param worldid - world ID + * @param x - x coord + * @param y - y coord + * @param z - z coord + */ + public void setLocation(String worldid, int x, int y, int z); + /** + * Get the marker's icon + * @return marker icon + */ + public MarkerIcon getMarkerIcon(); + /** + * Set the marker's icon + * @param icon - new marker icon + * @return true if new marker icon set, false if not allowed + */ + public boolean setMarkerIcon(MarkerIcon icon); + /** + * Test if marker is persistent + */ + public boolean isPersistentMarker(); + /** + * Get the marker's label + */ + public String getLabel(); + /** + * Update the marker's label + */ + public void setLabel(String lbl); +} diff --git a/src/main/java/org/dynmap/markers/MarkerAPI.java b/src/main/java/org/dynmap/markers/MarkerAPI.java new file mode 100644 index 00000000..19c5bcc9 --- /dev/null +++ b/src/main/java/org/dynmap/markers/MarkerAPI.java @@ -0,0 +1,50 @@ +package org.dynmap.markers; + +import java.io.File; +import java.io.InputStream; +import java.util.Set; + +/** + * This defines the public interface to the MarkerAPI (as retrieved by the getMarkerAPI() method in the DynmapPlugin class). + */ +public interface MarkerAPI { + /** + * Get set of defined marker sets + * @return set of marker sets + */ + public Set getMarkerSets(); + /** + * Find marker set by ID + * @param id - ID of marker set + * @return marker set, or null if not found + */ + public MarkerSet getMarkerSet(String id); + /** + * Create marker set + * @param id - ID for marker set (must be unique among marker set - limit to alphanumerics, periods, underscores) + * @param lbl - Label for marker set + * @param iconlimit - set of allowed marker icons (if null, any marker icon can be used in set) + * @param persistent - if true, set is persistent (and can contain persistent markers) + * @return marker set, or null if failed to be created + */ + public MarkerSet createMarkerSet(String id, String lbl, Set iconlimit, boolean persistent); + /** + * Get set of defined marker icons + * @return set of marker icons + */ + public Set getMarkerIcons(); + /** + * Find marker icon by ID + * @param id - ID of marker icon + * @return marker icon, or null if not found + */ + public MarkerIcon getMarkerIcon(String id); + /** + * Register a new marker icon + * @param id - ID of marker icon (must be unique among marker icons - letters, numbers, periods, underscores only) + * @param label - label for marker icon + * @param marker_png - stream containing PNG encoded icon for marker (will be read and copied) + * @return marker icon object, or null if failed + */ + public MarkerIcon createMarkerIcon(String id, String label, InputStream marker_png); +} diff --git a/src/main/java/org/dynmap/markers/MarkerIcon.java b/src/main/java/org/dynmap/markers/MarkerIcon.java new file mode 100644 index 00000000..a253a421 --- /dev/null +++ b/src/main/java/org/dynmap/markers/MarkerIcon.java @@ -0,0 +1,26 @@ +package org.dynmap.markers; + +/** + * This defines the public interface to a marker icon, for use with the MarkerAPI + */ +public interface MarkerIcon { + /** Default marker icon - always exists */ + public static final String DEFAULT = "default"; + + + /** + * Get ID of the marker icon (unique among marker icons) + * @return ID + */ + public String getMarkerIconID(); + /** + * Get label for marker icon (descriptive - for helping select icon, or for legend/key) + * @return icon label + */ + public String getMarkerIconLabel(); + /** + * Is builtin marker + * @return true + */ + public boolean isBuiltIn(); +} diff --git a/src/main/java/org/dynmap/markers/MarkerSet.java b/src/main/java/org/dynmap/markers/MarkerSet.java new file mode 100644 index 00000000..011527fd --- /dev/null +++ b/src/main/java/org/dynmap/markers/MarkerSet.java @@ -0,0 +1,83 @@ +package org.dynmap.markers; + +import java.util.Set; + +/** + * This defines the public interface to a marker set object, for use with the MarkerAPI. + * This represents a logical set of markers, which are presented as a labelled layer on the web UI. + * Marker sets can be created as persistent or non-persistent, but only persistent marker sets can contain persistent markers. + */ +public interface MarkerSet { + public static final String DEFAULT = "markers"; /* Default set - always exists */ + + /** + * Get set of all markers currently in the set + * @return set of markers (set is copy - safe to iterate) + */ + public Set getMarkers(); + /** + * Create a new marker in the marker set + * + * @param id - ID of the marker - must be unique within the set: if null, unique ID is generated + * @param label - Label for the marker + * @param world - world ID + * @param x - x coord + * @param y - y coord + * @param z - z coord + * @param icon - Icon for the marker + * @param is_persistent - if true, marker is persistent (saved and reloaded on restart). If set is not persistent, this must be false. + * @return created marker, or null if cannot be created. + */ + public Marker createMarker(String id, String label, String world, int x, int y, int z, MarkerIcon icon, boolean is_persistent); + /** + * Get marker by ID + * @param id - ID of the marker + * @return marker, or null if cannot be found + */ + public Marker findMarker(String id); + /** + * Get ID of marker set - unique among marker sets + * @return ID + */ + public String getMarkerSetID(); + /** + * Get label for marker set + * @return label + */ + public String getMarkerSetLabel(); + /** + * Update label for marker set + * @param lbl - label for marker set + */ + public void setMarketSetLabel(String lbl); + /** + * Test if marker set is persistent + * @return true if the set is persistent + */ + public boolean isMarkerSetPersistent(); + /** + * Get marker icons allowed in set (if restricted) + * @return set of allowed marker icons + */ + public Set getAllowedMarkerIcons(); + /** + * Add marker icon to allowed set (must have been created restricted) + * @param icon - icon to be added + */ + public void addAllowedMarkerIcon(MarkerIcon icon); + /** + * Test if marker icon is allowed + * @param icon - marker icon + * @return true if allowed, false if not + */ + public boolean isAllowedMarkerIcon(MarkerIcon icon); + /** + * Get distinct set of marker icons used by set (based on markers currently in set) + * @return set of marker icons + */ + public Set getMarkerIconsInUse(); + /** + * Delete marker set + */ + public void deleteMarkerSet(); +} diff --git a/src/main/java/org/dynmap/markers/impl/MarkerAPIImpl.java b/src/main/java/org/dynmap/markers/impl/MarkerAPIImpl.java new file mode 100644 index 00000000..b5a46d65 --- /dev/null +++ b/src/main/java/org/dynmap/markers/impl/MarkerAPIImpl.java @@ -0,0 +1,514 @@ +package org.dynmap.markers.impl; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.bukkit.Location; +import org.bukkit.Server; +import org.bukkit.World; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.util.config.Configuration; +import org.bukkit.util.config.ConfigurationNode; +import org.dynmap.Client; +import org.dynmap.ClientUpdateEvent; +import org.dynmap.DynmapPlugin; +import org.dynmap.DynmapWorld; +import org.dynmap.Event; +import org.dynmap.Log; +import org.dynmap.MapManager; +import org.dynmap.Client.ComponentMessage; +import org.dynmap.markers.Marker; +import org.dynmap.markers.MarkerAPI; +import org.dynmap.markers.MarkerIcon; +import org.dynmap.markers.MarkerSet; +import org.dynmap.web.Json; + +/** + * Implementation class for MarkerAPI - should not be called directly + */ +public class MarkerAPIImpl implements MarkerAPI, Event.Listener { + private File markerpersist; + private File markerdir; /* Local store for markers (internal) */ + private File markertiledir; /* Marker directory for web server (under tiles) */ + private HashMap markericons = new HashMap(); + private HashMap markersets = new HashMap(); + + private Server server; + static MarkerAPIImpl api; + + /* Built-in icons */ + private static final String[] builtin_icons = { + "anchor", "bank", "basket", "beer", "bighouse", "blueflag", "bomb", "bookshelf", "bricks", "bronzemedal", "bronzestar", + "building", "cake", "camera", "cart", "caution", "chest", "church", "coins", "comment", "compass", "construction", + "cross", "cup", "cutlery", "default", "diamond", "dog", "door", "down", "drink", "exclamation", "factory", + "fire", "flower", "gear", "goldmedal", "goldstar", "greenflag", "hammer", "heart", "house", "key", "king", + "left", "lightbulb", "lighthouse", "lock", "orangeflag", "pin", "pinkflag", "pirateflag", "pointdown", "pointleft", + "pointright", "pointup", "purpleflag", "queen", "redflag", "right", "ruby", "scales", "skull", "shield", "sign", + "silvermedal", "silverstar", "star", "sun", "temple", "theater", "tornado", "tower", "tree", "truck", "up", + "walk", "warning", "world", "wrench", "yellowflag" + }; + + /* Component messages for client updates */ + public static class MarkerComponentMessage extends ComponentMessage { + public String ctype = "markers"; + } + + public static class MarkerUpdated extends MarkerComponentMessage { + public String msg; + public int x, y, z; + public String id; + public String label; + public String icon; + public String set; + + public MarkerUpdated(Marker m, boolean deleted) { + this.id = m.getMarkerID(); + this.label = m.getLabel(); + this.x = m.getX(); + this.y = m.getY(); + this.z = m.getZ(); + this.set = m.getMarkerSet().getMarkerSetID(); + this.icon = m.getMarkerIcon().getMarkerIconID(); + if(deleted) + msg = "markerdeleted"; + else + msg = "markerupdated"; + } + } + + public static class MarkerSetUpdated extends MarkerComponentMessage { + public String msg; + public String id; + public String label; + public MarkerSetUpdated(MarkerSet markerset, boolean deleted) { + this.id = markerset.getMarkerSetID(); + this.label = markerset.getMarkerSetLabel(); + if(deleted) + msg = "setdeleted"; + else + msg = "setupdated"; + } + } + + /** + * Singleton initializer + */ + public static MarkerAPIImpl initializeMarkerAPI(DynmapPlugin plugin) { + if(api != null) { + api.cleanup(plugin); + } + api = new MarkerAPIImpl(); + api.server = plugin.getServer(); + /* Initialize persistence file name */ + api.markerpersist = new File(plugin.getDataFolder(), "markers.yml"); + /* Load persistence */ + api.loadMarkers(); + /* Fill in default icons and sets, if needed */ + for(int i = 0; i < builtin_icons.length; i++) { + String id = builtin_icons[i]; + if(api.getMarkerIcon(id) == null) { + api.createBuiltinMarkerIcon(id, id); + } + } + if(api.getMarkerSet(MarkerSet.DEFAULT) == null) { + api.createMarkerSet(MarkerSet.DEFAULT, "Markers", null, true); + } + /* Build paths for markers */ + api.markerdir = new File(plugin.getDataFolder(), "markers"); + if(api.markerdir.mkdirs() == false) { /* Create directory if needed */ + Log.severe("Error creating markers directory - " + api.markerdir.getPath()); + } + api.markertiledir = new File(DynmapPlugin.tilesDirectory, "_markers_"); + if(api.markertiledir.mkdirs() == false) { /* Create directory if needed */ + Log.severe("Error creating markers directory - " + api.markertiledir.getPath()); + } + /* Now publish marker files to the tiles directory */ + for(MarkerIcon ico : api.getMarkerIcons()) { + api.publishMarkerIcon(ico); + } + /* Freshen files */ + api.freshenMarkerFiles(); + /* Add listener so we update marker files for other worlds as they become active */ + plugin.events.addListener("worldactivated", api); + + return api; + } + + /** + * Cleanup + */ + public void cleanup(DynmapPlugin plugin) { + plugin.events.removeListener("worldactivated", api); + + for(MarkerIconImpl icn : markericons.values()) + icn.cleanup(); + markericons.clear(); + for(MarkerSetImpl set : markersets.values()) + set.cleanup(); + markersets.clear(); + } + + private MarkerIcon createBuiltinMarkerIcon(String id, String label) { + if(markericons.containsKey(id)) return null; /* Exists? */ + MarkerIconImpl ico = new MarkerIconImpl(id, label, true); + markericons.put(id, ico); /* Add to set */ + return ico; + } + + private void publishMarkerIcon(MarkerIcon ico) { + byte[] buf = new byte[512]; + InputStream in = null; + File infile = new File(markerdir, ico.getMarkerIconID() + ".png"); /* Get source file name */ + File outfile = new File(markertiledir, ico.getMarkerIconID() + ".png"); /* Destination */ + OutputStream out = null; + try { + out = new FileOutputStream(outfile); + } catch (IOException iox) { + Log.severe("Cannot write marker to tilespath - " + outfile.getPath()); + return; + } + if(ico.isBuiltIn()) { + in = getClass().getResourceAsStream("/markers/" + ico.getMarkerIconID() + ".png"); + } + else if(infile.canRead()) { /* If it exists and is readable */ + try { + in = new FileInputStream(infile); + } catch (IOException iox) { + Log.severe("Error opening marker " + infile.getPath() + " - " + iox); + } + } + if(in == null) { /* Not found, use default marker */ + in = getClass().getResourceAsStream("/markers/marker.png"); + if(in == null) + return; + } + /* Copy to destination */ + try { + int len; + while((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + } catch (IOException iox) { + Log.severe("Error writing marker to tilespath - " + outfile.getPath()); + } finally { + if(in != null) try { in.close(); } catch (IOException x){} + if(out != null) try { out.close(); } catch (IOException x){} + } + } + + @Override + public Set getMarkerSets() { + return new HashSet(markersets.values()); + } + + @Override + public MarkerSet getMarkerSet(String id) { + return markersets.get(id); + } + + @Override + public MarkerSet createMarkerSet(String id, String lbl, Set iconlimit, boolean persistent) { + if(markersets.containsKey(id)) return null; /* Exists? */ + + MarkerSetImpl set = new MarkerSetImpl(id, lbl, iconlimit, persistent); + + markersets.put(id, set); /* Add to list */ + if(persistent) { + saveMarkers(); + } + markerSetUpdated(set, MarkerUpdate.CREATED); /* Notify update */ + + return set; + } + + @Override + public Set getMarkerIcons() { + return new HashSet(markericons.values()); + } + + @Override + public MarkerIcon getMarkerIcon(String id) { + return markericons.get(id); + } + + @Override + public MarkerIcon createMarkerIcon(String id, String label, InputStream marker_png) { + if(markericons.containsKey(id)) return null; /* Exists? */ + MarkerIconImpl ico = new MarkerIconImpl(id, label, false); + /* Copy icon resource into marker directory */ + File f = new File(markerdir, id + ".png"); + FileOutputStream fos = null; + try { + byte[] buf = new byte[512]; + int len; + fos = new FileOutputStream(f); + while((len = marker_png.read(buf)) > 0) { + fos.write(buf, 0, len); + } + } catch (IOException iox) { + Log.severe("Error copying marker - " + f.getPath()); + return null; + } finally { + if(fos != null) try { fos.close(); } catch (IOException x) {} + } + markericons.put(id, ico); /* Add to set */ + + /* Publish the marker */ + publishMarkerIcon(ico); + + saveMarkers(); /* Save results */ + + return ico; + } + + static MarkerIconImpl getMarkerIconImpl(String id) { + if(api != null) { + return api.markericons.get(id); + } + return null; + } + + /** + * Save persistence for markers + */ + static void saveMarkers() { + if(api != null) { + Configuration conf = new Configuration(api.markerpersist); /* Make configuration object */ + /* First, save icon definitions */ + HashMap icons = new HashMap(); + for(String id : api.markericons.keySet()) { + MarkerIconImpl ico = api.markericons.get(id); + Map dat = ico.getPersistentData(); + if(dat != null) { + icons.put(id, dat); + } + } + conf.setProperty("icons", icons); + /* Then, save persistent sets */ + HashMap sets = new HashMap(); + for(String id : api.markersets.keySet()) { + MarkerSetImpl set = api.markersets.get(id); + if(set.isMarkerSetPersistent()) { + Map dat = set.getPersistentData(); + if(dat != null) { + sets.put(id, dat); + } + } + } + conf.setProperty("sets", sets); + /* And write it out */ + if(!conf.save()) + Log.severe("Error writing markers - " + api.markerpersist.getPath()); + /* Refresh JSON files */ + api.freshenMarkerFiles(); + } + } + + private void freshenMarkerFiles() { + if(MapManager.mapman != null) { + for(DynmapWorld w : MapManager.mapman.worlds) { + writeMarkersFile(w.world.getName()); + } + } + } + + /** + * Load persistence + */ + private boolean loadMarkers() { + Configuration conf = new Configuration(api.markerpersist); /* Make configuration object */ + conf.load(); /* Load persistence */ + /* Get icons */ + Map icons = conf.getNodes("icons"); + if(icons == null) return false; + for(String id : icons.keySet()) { + MarkerIconImpl ico = new MarkerIconImpl(id); + if(ico.loadPersistentData(icons.get(id))) { + markericons.put(id, ico); + } + } + /* Get marker sets */ + Map sets = conf.getNodes("sets"); + if(sets != null) { + for(String id: sets.keySet()) { + MarkerSetImpl set = new MarkerSetImpl(id); + if(set.loadPersistentData(sets.get(id))) { + markersets.put(id, set); + } + } + } + + return true; + } + + enum MarkerUpdate { CREATED, UPDATED, DELETED }; + + /** + * Signal marker update + * @param marker - updated marker + * @param update - type of update + */ + static void markerUpdated(MarkerImpl marker, MarkerUpdate update) { + Log.info("markerUpdated(" + marker.getMarkerID() + "," + update + ")"); + /* Freshen marker file for the world for this marker */ + if(api != null) + api.writeMarkersFile(marker.getWorld()); + /* Enqueue client update */ + if(MapManager.mapman != null) + MapManager.mapman.pushUpdate(marker.getWorld(), new MarkerUpdated(marker, update == MarkerUpdate.DELETED)); + } + /** + * Signal marker set update + * @param markerset - updated marker set + * @param update - type of update + */ + static void markerSetUpdated(MarkerSetImpl markerset, MarkerUpdate update) { + Log.info("markerSetUpdated(" + markerset.getMarkerSetID() + "," + update + ")"); + /* Freshen all marker files */ + if(api != null) + api.freshenMarkerFiles(); + /* Enqueue client update */ + if(MapManager.mapman != null) + MapManager.mapman.pushUpdate(new MarkerSetUpdated(markerset, update == MarkerUpdate.DELETED)); + } + + /** + * Remove marker set + */ + static void removeMarkerSet(MarkerSetImpl markerset) { + if(api != null) { + api.markersets.remove(markerset.getMarkerSetID()); /* Remove set from list */ + if(markerset.isMarkerSetPersistent()) { /* If persistent */ + MarkerAPIImpl.saveMarkers(); /* Drive save */ + } + markerSetUpdated(markerset, MarkerUpdate.DELETED); /* Signal delete of set */ + } + } + + private static final Set commands = new HashSet(Arrays.asList(new String[] { + "add", "update", "delete", "list" + })); + + public static boolean onCommand(DynmapPlugin plugin, CommandSender sender, Command cmd, String commandLabel, String[] args) { + if(api == null) { + sender.sendMessage("Markers component is not enabled."); + return false; + } + if(args.length == 0) + return false; + Player player = null; + if (sender instanceof Player) + player = (Player) sender; + /* Check if valid command */ + String c = args[0]; + if (!commands.contains(c)) { + return false; + } + /* Process commands */ + if(c.equals("add") && plugin.checkPlayerPermission(sender, "marker.add")) { + if(player == null) { + sender.sendMessage("Command can only be used by player"); + } + else if(args.length > 1) { + String lbl = args[1]; + if(lbl.charAt(0) == '"') { /* Starts with doublequote */ + lbl = lbl.substring(1); /* Trim it off */ + int idx = 2; + while(lbl.indexOf('"') < 0) { + if(idx < args.length) { + lbl = lbl + " " + args[idx]; + idx++; + } + else { + break; + } + } + idx = lbl.indexOf('"'); + if(idx >= 0) lbl = lbl.substring(0, idx); + } + Location loc = player.getLocation(); + /* Add new marker (generic ID and default set) */ + MarkerSet set = api.getMarkerSet(MarkerSet.DEFAULT); + MarkerIcon ico = api.getMarkerIcon(MarkerIcon.DEFAULT); + Marker m = set.createMarker(null, lbl, loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), ico, true); + if(m == null) { + sender.sendMessage("Error creating marker"); + } + else { + sender.sendMessage("Added marker id='" + m.getMarkerID() + "' (" + m.getLabel() + ") to marker set " + set.getMarkerSetID()); + } + } + else { + sender.sendMessage("Marker label required"); + } + } + else { + return false; + } + return true; + } + + /** + * Write markers file for given world + */ + public void writeMarkersFile(String wname) { + Map markerdata = new HashMap(); + + File f = new File(markertiledir, "marker_" + wname + ".json"); + + Map worlddata = new HashMap(); + worlddata.put("timestamp", Long.valueOf(System.currentTimeMillis())); /* Add timestamp */ + + for(MarkerSet ms : markersets.values()) { + HashMap msdata = new HashMap(); + msdata.put("label", ms.getMarkerSetLabel()); + HashMap markers = new HashMap(); + for(Marker m : ms.getMarkers()) { + if(m.getWorld().equals(wname) == false) continue; + + HashMap mdata = new HashMap(); + mdata.put("x", m.getX()); + mdata.put("y", m.getY()); + mdata.put("z", m.getZ()); + mdata.put("icon", m.getMarkerIcon().getMarkerIconID()); + mdata.put("label", m.getLabel()); + /* Add to markers */ + markers.put(m.getMarkerID(), mdata); + } + msdata.put("markers", markers); /* Add markers to set data */ + + markerdata.put(ms.getMarkerSetID(), msdata); /* Add marker set data to world marker data */ + } + worlddata.put("sets", markerdata); + + FileOutputStream fos = null; + try { + fos = new FileOutputStream(f); + fos.write(Json.stringifyJson(worlddata).getBytes()); + } catch (FileNotFoundException ex) { + Log.severe("Exception while writing JSON-file.", ex); + } catch (IOException ioe) { + Log.severe("Exception while writing JSON-file.", ioe); + } finally { + if(fos != null) try { fos.close(); } catch (IOException x) {} + } + } + + @Override + public void triggered(DynmapWorld t) { + /* Update markers for now-active world */ + writeMarkersFile(t.world.getName()); + } +} diff --git a/src/main/java/org/dynmap/markers/impl/MarkerIconImpl.java b/src/main/java/org/dynmap/markers/impl/MarkerIconImpl.java new file mode 100644 index 00000000..7adcccb1 --- /dev/null +++ b/src/main/java/org/dynmap/markers/impl/MarkerIconImpl.java @@ -0,0 +1,71 @@ +package org.dynmap.markers.impl; + +import java.util.HashMap; +import java.util.Map; + +import org.bukkit.util.config.ConfigurationNode; +import org.dynmap.markers.MarkerIcon; + +class MarkerIconImpl implements MarkerIcon { + private String iconid; + private String label; + private boolean is_builtin; + + MarkerIconImpl(String id) { + iconid = id; + label = id; + is_builtin = false; + } + + MarkerIconImpl(String id, String lbl, boolean is_builtin) { + iconid = id; + if(lbl != null) + label = lbl; + else + label = id; + this.is_builtin = is_builtin; + } + + void cleanup() { + + } + + @Override + public String getMarkerIconID() { + return iconid; + } + + @Override + public String getMarkerIconLabel() { + return label; + } + + @Override + public boolean isBuiltIn() { + return is_builtin; + } + + /** + * Get configuration node to be saved + * @return node + */ + Map getPersistentData() { + if(is_builtin) + return null; + + HashMap node = new HashMap(); + node.put("label", label); + + return node; + } + + boolean loadPersistentData(ConfigurationNode node) { + if(is_builtin) + return false; + + label = node.getString("label", iconid); + + return true; + } + +} diff --git a/src/main/java/org/dynmap/markers/impl/MarkerImpl.java b/src/main/java/org/dynmap/markers/impl/MarkerImpl.java new file mode 100644 index 00000000..0b88230b --- /dev/null +++ b/src/main/java/org/dynmap/markers/impl/MarkerImpl.java @@ -0,0 +1,179 @@ +package org.dynmap.markers.impl; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.bukkit.Location; +import org.bukkit.util.config.ConfigurationNode; +import org.dynmap.markers.Marker; +import org.dynmap.markers.MarkerIcon; +import org.dynmap.markers.MarkerSet; +import org.dynmap.markers.impl.MarkerAPIImpl.MarkerUpdate; + +class MarkerImpl implements Marker { + private String markerid; + private String label; + private MarkerSetImpl markerset; + private int x, y, z; + private String world; + private MarkerIconImpl icon; + private boolean ispersistent; + + /** + * Create marker + * @param id - marker ID + * @param lbl - label + * @param world - world id + * @param x - x coord + * @param y - y coord + * @param z - z coord + * @param icon - marker icon + * @param persistent - true if persistent + */ + MarkerImpl(String id, String lbl, String world, int x, int y, int z, MarkerIconImpl icon, boolean persistent, MarkerSetImpl set) { + markerid = id; + if(lbl != null) + label = lbl; + else + label = id; + this.x = x; this.y = y; this.z = z; + this.world = world; + this.icon = icon; + ispersistent = persistent; + markerset = set; + } + /** + * Make bare marker - used for persistence load + * @param id - marker ID + * @param set - marker set + */ + MarkerImpl(String id, MarkerSetImpl set) { + markerid = id; + markerset = set; + label = id; + x = z = 0; y = 64; world = "world"; + icon = MarkerAPIImpl.getMarkerIconImpl(MarkerIcon.DEFAULT); + } + /** + * Load marker from configuration node + * @param node - configuration node + */ + boolean loadPersistentData(ConfigurationNode node) { + label = node.getString("label", markerid); + x = node.getInt("x", 0); + y = node.getInt("y", 64); + z = node.getInt("z", 0); + world = node.getString("world", "world"); + icon = MarkerAPIImpl.getMarkerIconImpl(node.getString("icon", MarkerIcon.DEFAULT)); + ispersistent = true; /* Loaded from config, so must be */ + + return true; + } + + void cleanup() { + icon = null; + markerset = null; + } + + @Override + public String getMarkerID() { + return markerid; + } + + @Override + public MarkerSet getMarkerSet() { + return markerset; + } + + @Override + public void deleteMarker() { + markerset.removeMarker(this); /* Remove from our marker set (notified by set) */ + cleanup(); + } + + @Override + public MarkerIcon getMarkerIcon() { + return icon; + } + + @Override + public boolean setMarkerIcon(MarkerIcon icon) { + if(!(icon instanceof MarkerIconImpl)) { + return false; + } + /* Check if icons restricted for this set */ + Set icns = markerset.getAllowedMarkerIcons(); + if((icns != null) && (icns.contains(icon) == false)) { + return false; + } + this.icon = (MarkerIconImpl)icon; + MarkerAPIImpl.markerUpdated(this, MarkerUpdate.UPDATED); + if(ispersistent) + MarkerAPIImpl.saveMarkers(); + + return true; + } + + @Override + public boolean isPersistentMarker() { + return ispersistent; + } + + @Override + public String getLabel() { + return label; + } + + @Override + public void setLabel(String lbl) { + label = lbl; + MarkerAPIImpl.markerUpdated(this, MarkerUpdate.UPDATED); + if(ispersistent) + MarkerAPIImpl.saveMarkers(); + } + + /** + * Get configuration node to be saved + * @return node + */ + Map getPersistentData() { + if(!ispersistent) /* Nothing if not persistent */ + return null; + HashMap node = new HashMap(); + node.put("label", label); + node.put("x", Integer.valueOf(x)); + node.put("y", Integer.valueOf(y)); + node.put("z", Integer.valueOf(z)); + node.put("world", world); + node.put("icon", icon.getMarkerIconID()); + + return node; + } + @Override + public String getWorld() { + return world; + } + @Override + public int getX() { + return x; + } + @Override + public int getY() { + return y; + } + @Override + public int getZ() { + return z; + } + @Override + public void setLocation(String worldid, int x, int y, int z) { + this.world = worldid; + this.x = x; + this.y = y; + this.z = z; + MarkerAPIImpl.markerUpdated(this, MarkerUpdate.UPDATED); + if(ispersistent) + MarkerAPIImpl.saveMarkers(); + } +} diff --git a/src/main/java/org/dynmap/markers/impl/MarkerSetImpl.java b/src/main/java/org/dynmap/markers/impl/MarkerSetImpl.java new file mode 100644 index 00000000..9c248c1b --- /dev/null +++ b/src/main/java/org/dynmap/markers/impl/MarkerSetImpl.java @@ -0,0 +1,228 @@ +package org.dynmap.markers.impl; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.bukkit.Location; +import org.bukkit.util.config.ConfigurationNode; +import org.dynmap.Log; +import org.dynmap.markers.Marker; +import org.dynmap.markers.MarkerIcon; +import org.dynmap.markers.MarkerSet; +import org.dynmap.markers.impl.MarkerAPIImpl.MarkerUpdate; + +class MarkerSetImpl implements MarkerSet { + private HashMap markers = new HashMap(); + private String setid; + private String label; + private HashMap allowedicons = null; + + private boolean ispersistent; + + MarkerSetImpl(String id) { + setid = id; + label = id; + } + + MarkerSetImpl(String id, String lbl, Set iconlimit, boolean persistent) { + setid = id; + if(lbl != null) + label = lbl; + else + label = id; + if(iconlimit != null) { + allowedicons = new HashMap(); + for(MarkerIcon ico : iconlimit) { + if(ico instanceof MarkerIconImpl) { + allowedicons.put(ico.getMarkerIconID(), (MarkerIconImpl)ico); + } + } + } + ispersistent = persistent; + } + + void cleanup() { + for(MarkerImpl m : markers.values()) + m.cleanup(); + markers.clear(); + } + + @Override + public Set getMarkers() { + return new HashSet(markers.values()); + } + + @Override + public Marker createMarker(String id, String label, String world, int x, int y, int z, MarkerIcon icon, boolean is_persistent) { + if(id == null) { /* If not defined, generate unique one */ + int i = 0; + do { + i++; + id = "marker_" + i; + } while(markers.containsKey(id)); + } + if(markers.containsKey(id)) return null; /* Duplicate ID? */ + if(!(icon instanceof MarkerIconImpl)) return null; + /* If limited icons, and this isn't valid one, quit */ + if((allowedicons != null) && (allowedicons.containsKey(icon.getMarkerIconID()) == false)) return null; + /* Create marker */ + is_persistent = is_persistent && this.ispersistent; + MarkerImpl marker = new MarkerImpl(id, label, world, x, y, z, (MarkerIconImpl)icon, is_persistent, this); + markers.put(id, marker); /* Add to set */ + if(is_persistent) + MarkerAPIImpl.saveMarkers(); + + MarkerAPIImpl.markerUpdated(marker, MarkerUpdate.CREATED); /* Signal create */ + + return marker; + } + + @Override + public Marker findMarker(String id) { + return markers.get(id); + } + + @Override + public String getMarkerSetID() { + return setid; + } + + @Override + public String getMarkerSetLabel() { + return label; + } + + @Override + public void setMarketSetLabel(String lbl) { + label = lbl; + MarkerAPIImpl.markerSetUpdated(this, MarkerUpdate.UPDATED); + if(ispersistent) + MarkerAPIImpl.saveMarkers(); + } + + @Override + public boolean isMarkerSetPersistent() { + return ispersistent; + } + + @Override + public Set getAllowedMarkerIcons() { + if(allowedicons != null) + return new HashSet(allowedicons.values()); + else + return null; + } + + @Override + public void addAllowedMarkerIcon(MarkerIcon icon) { + if(!(icon instanceof MarkerIconImpl)) return; + if(allowedicons == null) return; + allowedicons.put(icon.getMarkerIconID(), (MarkerIconImpl)icon); + MarkerAPIImpl.markerSetUpdated(this, MarkerUpdate.UPDATED); + if(ispersistent) + MarkerAPIImpl.saveMarkers(); + } + + @Override + public boolean isAllowedMarkerIcon(MarkerIcon icon) { + if(allowedicons == null) return true; + return allowedicons.containsKey(icon.getMarkerIconID()); + } + + @Override + public Set getMarkerIconsInUse() { + HashSet ids = new HashSet(); + HashSet icons = new HashSet(); + for(Marker m : markers.values()) { + MarkerIcon mi = m.getMarkerIcon(); + if(!ids.contains(mi.getMarkerIconID())) { + ids.add(mi.getMarkerIconID()); + icons.add(mi); + } + } + return icons; + } + + @Override + public void deleteMarkerSet() { + MarkerAPIImpl.removeMarkerSet(this); /* Remove from top level sets (notification from there) */ + if(ispersistent) + MarkerAPIImpl.saveMarkers(); + cleanup(); + } + /** + * Remove marker from set + * + * @param marker + */ + void removeMarker(MarkerImpl marker) { + markers.remove(marker.getMarkerID()); /* Remove from set */ + if(ispersistent && marker.isPersistentMarker()) { /* If persistent */ + MarkerAPIImpl.saveMarkers(); /* Drive save */ + } + MarkerAPIImpl.markerUpdated(marker, MarkerUpdate.DELETED); + } + + /** + * Get configuration node to be saved + * @return node + */ + Map getPersistentData() { + if(!ispersistent) /* Nothing if not persistent */ + return null; + HashMap node = new HashMap(); + for(String id : markers.keySet()) { + MarkerImpl m = markers.get(id); + if(m.isPersistentMarker()) { + node.put(id, m.getPersistentData()); + } + } + /* Make top level node */ + HashMap setnode = new HashMap(); + setnode.put("label", label); + if(allowedicons != null) { + ArrayList allowed = new ArrayList(allowedicons.keySet()); + setnode.put("allowedicons", allowed); + } + setnode.put("markers", node); + return setnode; + } + + /** + * Load marker from configuration node + * @param node - configuration node + */ + boolean loadPersistentData(ConfigurationNode node) { + label = node.getString("label", setid); /* Get label */ + ConfigurationNode markernode = node.getNode("markers"); + if(markernode != null) { + for(String id : markernode.getKeys()) { + MarkerImpl marker = new MarkerImpl(id, this); /* Make and load marker */ + if(marker.loadPersistentData(markernode.getNode(id))) { + markers.put(id, marker); + } + else { + Log.info("Error loading marker '" + id + "' for set '" + setid + "'"); + marker.cleanup(); + } + } + } + List allowed = node.getStringList("allowedicons", null); + if(allowed != null) { + for(String id : allowed) { + MarkerIconImpl icon = MarkerAPIImpl.getMarkerIconImpl(id); + if(icon != null) + allowedicons.put(id, icon); + else + Log.info("Error loading allowed icon '" + id + "' for set '" + setid + "'"); + } + } + ispersistent = true; + + return true; + } +} diff --git a/src/main/resources/configuration.txt b/src/main/resources/configuration.txt index ee397ffd..e7d00042 100644 --- a/src/main/resources/configuration.txt +++ b/src/main/resources/configuration.txt @@ -40,6 +40,10 @@ components: # #- Trade # #- Haggle + # Note: this component is needed for the dmarker commands, and for the Marker API to be available to other plugins + - class: org.dynmap.MarkersComponent + type: markers + - class: org.dynmap.ClientComponent type: chat - class: org.dynmap.ClientComponent diff --git a/src/main/resources/markers/anchor.png b/src/main/resources/markers/anchor.png new file mode 100644 index 00000000..870ebf63 Binary files /dev/null and b/src/main/resources/markers/anchor.png differ diff --git a/src/main/resources/markers/bank.png b/src/main/resources/markers/bank.png new file mode 100644 index 00000000..f3185794 Binary files /dev/null and b/src/main/resources/markers/bank.png differ diff --git a/src/main/resources/markers/basket.png b/src/main/resources/markers/basket.png new file mode 100644 index 00000000..1ff455e0 Binary files /dev/null and b/src/main/resources/markers/basket.png differ diff --git a/src/main/resources/markers/beer.png b/src/main/resources/markers/beer.png new file mode 100644 index 00000000..1113e7a8 Binary files /dev/null and b/src/main/resources/markers/beer.png differ diff --git a/src/main/resources/markers/bighouse.png b/src/main/resources/markers/bighouse.png new file mode 100644 index 00000000..9723cf0e Binary files /dev/null and b/src/main/resources/markers/bighouse.png differ diff --git a/src/main/resources/markers/blueflag.png b/src/main/resources/markers/blueflag.png new file mode 100644 index 00000000..1a79762a Binary files /dev/null and b/src/main/resources/markers/blueflag.png differ diff --git a/src/main/resources/markers/bomb.png b/src/main/resources/markers/bomb.png new file mode 100644 index 00000000..6e8e3a33 Binary files /dev/null and b/src/main/resources/markers/bomb.png differ diff --git a/src/main/resources/markers/bookshelf.png b/src/main/resources/markers/bookshelf.png new file mode 100644 index 00000000..c589cadf Binary files /dev/null and b/src/main/resources/markers/bookshelf.png differ diff --git a/src/main/resources/markers/bricks.png b/src/main/resources/markers/bricks.png new file mode 100644 index 00000000..c7d1ee03 Binary files /dev/null and b/src/main/resources/markers/bricks.png differ diff --git a/src/main/resources/markers/bronzemedal.png b/src/main/resources/markers/bronzemedal.png new file mode 100644 index 00000000..83c06af3 Binary files /dev/null and b/src/main/resources/markers/bronzemedal.png differ diff --git a/src/main/resources/markers/bronzestar.png b/src/main/resources/markers/bronzestar.png new file mode 100644 index 00000000..0cec9251 Binary files /dev/null and b/src/main/resources/markers/bronzestar.png differ diff --git a/src/main/resources/markers/building.png b/src/main/resources/markers/building.png new file mode 100644 index 00000000..6646b815 Binary files /dev/null and b/src/main/resources/markers/building.png differ diff --git a/src/main/resources/markers/cake.png b/src/main/resources/markers/cake.png new file mode 100644 index 00000000..0e69b3fa Binary files /dev/null and b/src/main/resources/markers/cake.png differ diff --git a/src/main/resources/markers/camera.png b/src/main/resources/markers/camera.png new file mode 100644 index 00000000..0a7ef900 Binary files /dev/null and b/src/main/resources/markers/camera.png differ diff --git a/src/main/resources/markers/cart.png b/src/main/resources/markers/cart.png new file mode 100644 index 00000000..72425907 Binary files /dev/null and b/src/main/resources/markers/cart.png differ diff --git a/src/main/resources/markers/caution.png b/src/main/resources/markers/caution.png new file mode 100644 index 00000000..dbfda229 Binary files /dev/null and b/src/main/resources/markers/caution.png differ diff --git a/src/main/resources/markers/chest.png b/src/main/resources/markers/chest.png new file mode 100644 index 00000000..a33977e3 Binary files /dev/null and b/src/main/resources/markers/chest.png differ diff --git a/src/main/resources/markers/church.png b/src/main/resources/markers/church.png new file mode 100644 index 00000000..e1642d0b Binary files /dev/null and b/src/main/resources/markers/church.png differ diff --git a/src/main/resources/markers/coins.png b/src/main/resources/markers/coins.png new file mode 100644 index 00000000..28d59ee7 Binary files /dev/null and b/src/main/resources/markers/coins.png differ diff --git a/src/main/resources/markers/comment.png b/src/main/resources/markers/comment.png new file mode 100644 index 00000000..a5bab32f Binary files /dev/null and b/src/main/resources/markers/comment.png differ diff --git a/src/main/resources/markers/compass.png b/src/main/resources/markers/compass.png new file mode 100644 index 00000000..6576ced9 Binary files /dev/null and b/src/main/resources/markers/compass.png differ diff --git a/src/main/resources/markers/construction.png b/src/main/resources/markers/construction.png new file mode 100644 index 00000000..6dd0b2aa Binary files /dev/null and b/src/main/resources/markers/construction.png differ diff --git a/src/main/resources/markers/cross.png b/src/main/resources/markers/cross.png new file mode 100644 index 00000000..33a38374 Binary files /dev/null and b/src/main/resources/markers/cross.png differ diff --git a/src/main/resources/markers/cup.png b/src/main/resources/markers/cup.png new file mode 100644 index 00000000..9e234da1 Binary files /dev/null and b/src/main/resources/markers/cup.png differ diff --git a/src/main/resources/markers/cutlery.png b/src/main/resources/markers/cutlery.png new file mode 100644 index 00000000..ab33e5b8 Binary files /dev/null and b/src/main/resources/markers/cutlery.png differ diff --git a/src/main/resources/markers/default.png b/src/main/resources/markers/default.png new file mode 100644 index 00000000..55c76802 Binary files /dev/null and b/src/main/resources/markers/default.png differ diff --git a/src/main/resources/markers/diamond.png b/src/main/resources/markers/diamond.png new file mode 100644 index 00000000..e25a7168 Binary files /dev/null and b/src/main/resources/markers/diamond.png differ diff --git a/src/main/resources/markers/dog.png b/src/main/resources/markers/dog.png new file mode 100644 index 00000000..fb2dc26f Binary files /dev/null and b/src/main/resources/markers/dog.png differ diff --git a/src/main/resources/markers/door.png b/src/main/resources/markers/door.png new file mode 100644 index 00000000..2b4651e5 Binary files /dev/null and b/src/main/resources/markers/door.png differ diff --git a/src/main/resources/markers/down.png b/src/main/resources/markers/down.png new file mode 100644 index 00000000..691f6e0c Binary files /dev/null and b/src/main/resources/markers/down.png differ diff --git a/src/main/resources/markers/drink.png b/src/main/resources/markers/drink.png new file mode 100644 index 00000000..f2c33e77 Binary files /dev/null and b/src/main/resources/markers/drink.png differ diff --git a/src/main/resources/markers/exclamation.png b/src/main/resources/markers/exclamation.png new file mode 100644 index 00000000..d49653ad Binary files /dev/null and b/src/main/resources/markers/exclamation.png differ diff --git a/src/main/resources/markers/factory.png b/src/main/resources/markers/factory.png new file mode 100644 index 00000000..a27b9dd1 Binary files /dev/null and b/src/main/resources/markers/factory.png differ diff --git a/src/main/resources/markers/fire.png b/src/main/resources/markers/fire.png new file mode 100644 index 00000000..0a2029f9 Binary files /dev/null and b/src/main/resources/markers/fire.png differ diff --git a/src/main/resources/markers/flower.png b/src/main/resources/markers/flower.png new file mode 100644 index 00000000..ba4b0ab7 Binary files /dev/null and b/src/main/resources/markers/flower.png differ diff --git a/src/main/resources/markers/gear.png b/src/main/resources/markers/gear.png new file mode 100644 index 00000000..8f4eeb76 Binary files /dev/null and b/src/main/resources/markers/gear.png differ diff --git a/src/main/resources/markers/goldmedal.png b/src/main/resources/markers/goldmedal.png new file mode 100644 index 00000000..aba79c3b Binary files /dev/null and b/src/main/resources/markers/goldmedal.png differ diff --git a/src/main/resources/markers/goldstar.png b/src/main/resources/markers/goldstar.png new file mode 100644 index 00000000..3200f51f Binary files /dev/null and b/src/main/resources/markers/goldstar.png differ diff --git a/src/main/resources/markers/greenflag.png b/src/main/resources/markers/greenflag.png new file mode 100644 index 00000000..c8c61b07 Binary files /dev/null and b/src/main/resources/markers/greenflag.png differ diff --git a/src/main/resources/markers/hammer.png b/src/main/resources/markers/hammer.png new file mode 100644 index 00000000..06d69a55 Binary files /dev/null and b/src/main/resources/markers/hammer.png differ diff --git a/src/main/resources/markers/heart.png b/src/main/resources/markers/heart.png new file mode 100644 index 00000000..53e1013a Binary files /dev/null and b/src/main/resources/markers/heart.png differ diff --git a/src/main/resources/markers/house.png b/src/main/resources/markers/house.png new file mode 100644 index 00000000..da024e5a Binary files /dev/null and b/src/main/resources/markers/house.png differ diff --git a/src/main/resources/markers/key.png b/src/main/resources/markers/key.png new file mode 100644 index 00000000..b6ad1af4 Binary files /dev/null and b/src/main/resources/markers/key.png differ diff --git a/src/main/resources/markers/king.png b/src/main/resources/markers/king.png new file mode 100644 index 00000000..109b8dba Binary files /dev/null and b/src/main/resources/markers/king.png differ diff --git a/src/main/resources/markers/left.png b/src/main/resources/markers/left.png new file mode 100644 index 00000000..d9c50c4d Binary files /dev/null and b/src/main/resources/markers/left.png differ diff --git a/src/main/resources/markers/lightbulb.png b/src/main/resources/markers/lightbulb.png new file mode 100644 index 00000000..117285ff Binary files /dev/null and b/src/main/resources/markers/lightbulb.png differ diff --git a/src/main/resources/markers/lighthouse.png b/src/main/resources/markers/lighthouse.png new file mode 100644 index 00000000..be1b9c78 Binary files /dev/null and b/src/main/resources/markers/lighthouse.png differ diff --git a/src/main/resources/markers/lock.png b/src/main/resources/markers/lock.png new file mode 100644 index 00000000..ddf83d95 Binary files /dev/null and b/src/main/resources/markers/lock.png differ diff --git a/src/main/resources/markers/orangeflag.png b/src/main/resources/markers/orangeflag.png new file mode 100644 index 00000000..945dfa98 Binary files /dev/null and b/src/main/resources/markers/orangeflag.png differ diff --git a/src/main/resources/markers/pin.png b/src/main/resources/markers/pin.png new file mode 100644 index 00000000..c4578263 Binary files /dev/null and b/src/main/resources/markers/pin.png differ diff --git a/src/main/resources/markers/pinkflag.png b/src/main/resources/markers/pinkflag.png new file mode 100644 index 00000000..2cdae017 Binary files /dev/null and b/src/main/resources/markers/pinkflag.png differ diff --git a/src/main/resources/markers/pirateflag.png b/src/main/resources/markers/pirateflag.png new file mode 100644 index 00000000..3eeab004 Binary files /dev/null and b/src/main/resources/markers/pirateflag.png differ diff --git a/src/main/resources/markers/pointdown.png b/src/main/resources/markers/pointdown.png new file mode 100644 index 00000000..c66cf8a9 Binary files /dev/null and b/src/main/resources/markers/pointdown.png differ diff --git a/src/main/resources/markers/pointleft.png b/src/main/resources/markers/pointleft.png new file mode 100644 index 00000000..cd36a6c3 Binary files /dev/null and b/src/main/resources/markers/pointleft.png differ diff --git a/src/main/resources/markers/pointright.png b/src/main/resources/markers/pointright.png new file mode 100644 index 00000000..7efc7c6c Binary files /dev/null and b/src/main/resources/markers/pointright.png differ diff --git a/src/main/resources/markers/pointup.png b/src/main/resources/markers/pointup.png new file mode 100644 index 00000000..8c761f76 Binary files /dev/null and b/src/main/resources/markers/pointup.png differ diff --git a/src/main/resources/markers/purpleflag.png b/src/main/resources/markers/purpleflag.png new file mode 100644 index 00000000..0cb00ee8 Binary files /dev/null and b/src/main/resources/markers/purpleflag.png differ diff --git a/src/main/resources/markers/queen.png b/src/main/resources/markers/queen.png new file mode 100644 index 00000000..6fbe5a26 Binary files /dev/null and b/src/main/resources/markers/queen.png differ diff --git a/src/main/resources/markers/redflag.png b/src/main/resources/markers/redflag.png new file mode 100644 index 00000000..b99e36b2 Binary files /dev/null and b/src/main/resources/markers/redflag.png differ diff --git a/src/main/resources/markers/right.png b/src/main/resources/markers/right.png new file mode 100644 index 00000000..8d204afe Binary files /dev/null and b/src/main/resources/markers/right.png differ diff --git a/src/main/resources/markers/ruby.png b/src/main/resources/markers/ruby.png new file mode 100644 index 00000000..24755ce6 Binary files /dev/null and b/src/main/resources/markers/ruby.png differ diff --git a/src/main/resources/markers/scales.png b/src/main/resources/markers/scales.png new file mode 100644 index 00000000..cf099e96 Binary files /dev/null and b/src/main/resources/markers/scales.png differ diff --git a/src/main/resources/markers/shield.png b/src/main/resources/markers/shield.png new file mode 100644 index 00000000..4eb8031c Binary files /dev/null and b/src/main/resources/markers/shield.png differ diff --git a/src/main/resources/markers/sign.png b/src/main/resources/markers/sign.png new file mode 100644 index 00000000..668becee Binary files /dev/null and b/src/main/resources/markers/sign.png differ diff --git a/src/main/resources/markers/silvermedal.png b/src/main/resources/markers/silvermedal.png new file mode 100644 index 00000000..bcf9fe92 Binary files /dev/null and b/src/main/resources/markers/silvermedal.png differ diff --git a/src/main/resources/markers/silverstar.png b/src/main/resources/markers/silverstar.png new file mode 100644 index 00000000..d405d12c Binary files /dev/null and b/src/main/resources/markers/silverstar.png differ diff --git a/src/main/resources/markers/skull.png b/src/main/resources/markers/skull.png new file mode 100644 index 00000000..7eadc96c Binary files /dev/null and b/src/main/resources/markers/skull.png differ diff --git a/src/main/resources/markers/star.png b/src/main/resources/markers/star.png new file mode 100644 index 00000000..883e4dec Binary files /dev/null and b/src/main/resources/markers/star.png differ diff --git a/src/main/resources/markers/sun.png b/src/main/resources/markers/sun.png new file mode 100644 index 00000000..b38797a1 Binary files /dev/null and b/src/main/resources/markers/sun.png differ diff --git a/src/main/resources/markers/temple.png b/src/main/resources/markers/temple.png new file mode 100644 index 00000000..9ab1e9b5 Binary files /dev/null and b/src/main/resources/markers/temple.png differ diff --git a/src/main/resources/markers/theater.png b/src/main/resources/markers/theater.png new file mode 100644 index 00000000..13053e09 Binary files /dev/null and b/src/main/resources/markers/theater.png differ diff --git a/src/main/resources/markers/tornado.png b/src/main/resources/markers/tornado.png new file mode 100644 index 00000000..41040e11 Binary files /dev/null and b/src/main/resources/markers/tornado.png differ diff --git a/src/main/resources/markers/tower.png b/src/main/resources/markers/tower.png new file mode 100644 index 00000000..3c1bc75a Binary files /dev/null and b/src/main/resources/markers/tower.png differ diff --git a/src/main/resources/markers/tree.png b/src/main/resources/markers/tree.png new file mode 100644 index 00000000..70264e06 Binary files /dev/null and b/src/main/resources/markers/tree.png differ diff --git a/src/main/resources/markers/truck.png b/src/main/resources/markers/truck.png new file mode 100644 index 00000000..4b15248b Binary files /dev/null and b/src/main/resources/markers/truck.png differ diff --git a/src/main/resources/markers/up.png b/src/main/resources/markers/up.png new file mode 100644 index 00000000..30d005f2 Binary files /dev/null and b/src/main/resources/markers/up.png differ diff --git a/src/main/resources/markers/walk.png b/src/main/resources/markers/walk.png new file mode 100644 index 00000000..c1d95616 Binary files /dev/null and b/src/main/resources/markers/walk.png differ diff --git a/src/main/resources/markers/warning.png b/src/main/resources/markers/warning.png new file mode 100644 index 00000000..f5362a7e Binary files /dev/null and b/src/main/resources/markers/warning.png differ diff --git a/src/main/resources/markers/world.png b/src/main/resources/markers/world.png new file mode 100644 index 00000000..8ec6efe8 Binary files /dev/null and b/src/main/resources/markers/world.png differ diff --git a/src/main/resources/markers/wrench.png b/src/main/resources/markers/wrench.png new file mode 100644 index 00000000..7c8cc7a2 Binary files /dev/null and b/src/main/resources/markers/wrench.png differ diff --git a/src/main/resources/markers/yellowflag.png b/src/main/resources/markers/yellowflag.png new file mode 100644 index 00000000..8f087bbb Binary files /dev/null and b/src/main/resources/markers/yellowflag.png differ diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index d3e825c1..39d88f46 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -23,6 +23,11 @@ commands: / stats world - Show render statistics for maps on world 'world'. / resetstats - Reset render statistics. / resetstats world - Reset render statistics for maps on world 'world'. + dmarker: + description: Manipulate map markers + usage: | + / add