diff --git a/src/main/java/org/dynmap/DynmapPlugin.java b/src/main/java/org/dynmap/DynmapPlugin.java index 804db87b..c0973188 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 MarkerAPI markerapi; + public static File dataDirectory; public static File tilesDirectory; @@ -208,6 +212,9 @@ public class DynmapPlugin extends JavaPlugin { permissions = new OpPermissions(new String[] { "fullrender", "cancelrender", "radiusrender", "resetstats", "reload" }); dataDirectory = this.getDataFolder(); + + /* Initialize marker API, if not already done */ + MarkerAPI m_api = getMarkerAPI(); /* Load block models */ HDBlockModels.loadModels(dataDirectory); /* Load texture mappings */ @@ -278,11 +285,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); } @@ -640,6 +647,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 +778,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 +1173,10 @@ public class DynmapPlugin extends JavaPlugin { } ll.add(listener); } + + public MarkerAPI getMarkerAPI() { + if(markerapi == null) + markerapi = MarkerAPIImpl.initializeMarkerAPI(this); + return markerapi; + } } 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..a5a5c1d0 --- /dev/null +++ b/src/main/java/org/dynmap/markers/MarkerAPI.java @@ -0,0 +1,49 @@ +package org.dynmap.markers; + +import java.io.File; +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 markerfile - file containing PNG encoded icon for marker (will be copied) + * @return marker icon object, or null if failed + */ + public MarkerIcon createMarkerIcon(String id, String label, File markerfile); +} 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..2612ca9a --- /dev/null +++ b/src/main/java/org/dynmap/markers/MarkerIcon.java @@ -0,0 +1,20 @@ +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(); +} 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..a723f465 --- /dev/null +++ b/src/main/java/org/dynmap/markers/impl/MarkerAPIImpl.java @@ -0,0 +1,278 @@ +package org.dynmap.markers.impl; + +import java.io.File; +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.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.DynmapPlugin; +import org.dynmap.Log; +import org.dynmap.markers.Marker; +import org.dynmap.markers.MarkerAPI; +import org.dynmap.markers.MarkerIcon; +import org.dynmap.markers.MarkerSet; + +/** + * Implementation class for MarkerAPI - should not be called directly + */ +public class MarkerAPIImpl implements MarkerAPI { + private File markerpersist; + private HashMap markericons = new HashMap(); + private HashMap markersets = new HashMap(); + + static MarkerAPIImpl api; + + /** + * Singleton initializer + */ + public static MarkerAPI initializeMarkerAPI(DynmapPlugin plugin) { + if(api != null) { + api.cleanup(); + } + api = new MarkerAPIImpl(); + /* Initialize persistence file name */ + api.markerpersist = new File(plugin.getDataFolder(), "markers.yml"); + /* Load persistence */ + api.loadMarkers(); + /* Fill in default icons and sets, if needed */ + if(api.getMarkerIcon(MarkerIcon.DEFAULT) == null) { + api.createMarkerIcon(MarkerIcon.DEFAULT, "Marker", null); + } + if(api.getMarkerSet(MarkerSet.DEFAULT) == null) { + api.createMarkerSet(MarkerSet.DEFAULT, "Markers", null, true); + } + return api; + } + + /** + * Cleanup + */ + private void cleanup() { + for(MarkerIconImpl icn : markericons.values()) + icn.cleanup(); + markericons.clear(); + for(MarkerSetImpl set : markersets.values()) + set.cleanup(); + markersets.clear(); + } + + @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, File markerfile) { + if(markericons.containsKey(id)) return null; /* Exists? */ + MarkerIconImpl ico = new MarkerIconImpl(id, label); + + markericons.put(id, ico); /* Add to set */ + + 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) { + Log.info("saveMarkers()"); + 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()); + } + } + + /** + * Load persistence + */ + private boolean loadMarkers() { + cleanup(); + + 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 + ")"); + } + /** + * 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 + ")"); + } + + /** + * 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(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; + } + if(api == null) 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; + } +} 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..0b15f4f2 --- /dev/null +++ b/src/main/java/org/dynmap/markers/impl/MarkerIconImpl.java @@ -0,0 +1,57 @@ +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; + + MarkerIconImpl(String id) { + iconid = id; + label = id; + } + + MarkerIconImpl(String id, String lbl) { + iconid = id; + if(lbl != null) + label = lbl; + else + label = id; + } + + void cleanup() { + + } + + @Override + public String getMarkerIconID() { + return iconid; + } + + @Override + public String getMarkerIconLabel() { + return label; + } + + /** + * Get configuration node to be saved + * @return node + */ + Map getPersistentData() { + HashMap node = new HashMap(); + node.put("label", label); + + return node; + } + + boolean loadPersistentData(ConfigurationNode node) { + 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/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