diff --git a/src/main/java/org/dynmap/markers/Marker.java b/src/main/java/org/dynmap/markers/Marker.java index 46f7b5b7..adb37c0a 100644 --- a/src/main/java/org/dynmap/markers/Marker.java +++ b/src/main/java/org/dynmap/markers/Marker.java @@ -29,17 +29,17 @@ public interface Marker { * Get marker's X coordinate * @return x coordinate */ - public int getX(); + public double getX(); /** * Get marker's Y coordinate * @return y coordinate */ - public int getY(); + public double getY(); /** * Get marker's Z coordinate * @return z coordinate */ - public int getZ(); + public double getZ(); /** * Update the marker's location * @param worldid - world ID @@ -47,7 +47,7 @@ public interface Marker { * @param y - y coord * @param z - z coord */ - public void setLocation(String worldid, int x, int y, int z); + public void setLocation(String worldid, double x, double y, double z); /** * Get the marker's icon * @return marker icon diff --git a/src/main/java/org/dynmap/markers/MarkerSet.java b/src/main/java/org/dynmap/markers/MarkerSet.java index 011527fd..4d0f6d68 100644 --- a/src/main/java/org/dynmap/markers/MarkerSet.java +++ b/src/main/java/org/dynmap/markers/MarkerSet.java @@ -28,7 +28,7 @@ public interface MarkerSet { * @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); + public Marker createMarker(String id, String label, String world, double x, double y, double z, MarkerIcon icon, boolean is_persistent); /** * Get marker by ID * @param id - ID of the marker diff --git a/src/main/java/org/dynmap/markers/impl/MarkerAPIImpl.java b/src/main/java/org/dynmap/markers/impl/MarkerAPIImpl.java index 7838b9d6..74ab33fc 100644 --- a/src/main/java/org/dynmap/markers/impl/MarkerAPIImpl.java +++ b/src/main/java/org/dynmap/markers/impl/MarkerAPIImpl.java @@ -68,7 +68,7 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener { public static class MarkerUpdated extends MarkerComponentMessage { public String msg; - public int x, y, z; + public double x, y, z; public String id; public String label; public String icon; @@ -115,26 +115,29 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener { /* Initialize persistence file name */ api.markerpersist = new File(plugin.getDataFolder(), "markers.yml"); api.markerpersist_old = new File(plugin.getDataFolder(), "markers.yml.old"); - /* 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); - } + api.createBuiltinMarkerIcon(id, id); } + /* Load persistence */ + api.loadMarkers(); + /* Initialize default marker set, if needed */ 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()); + if(api.markerdir.isDirectory() == false) { + 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()); + if(api.markertiledir.isDirectory() == false) { + 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()) { @@ -403,9 +406,63 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener { } private static final Set commands = new HashSet(Arrays.asList(new String[] { - "add", "update", "delete", "list" + "add", "movehere", "update", "delete", "list", "icons" })); + /* Parse argument strings : handle 'attrib=value' and quoted strings */ + private static Map parseArgs(String[] args, CommandSender snd) { + HashMap rslt = new HashMap(); + /* Build command line, so we can parse our way - make sure there is trailing space */ + String cmdline = ""; + for(int i = 1; i < args.length; i++) { + cmdline += args[i] + " "; + } + boolean inquote = false; + StringBuilder sb = new StringBuilder(); + String varid = null; + for(int i = 0; i < cmdline.length(); i++) { + char c = cmdline.charAt(i); + if(inquote) { /* If in quote, accumulate until end or another quote */ + if(c == '\"') { /* End quote */ + inquote = false; + if(varid == null) { /* No varid? */ + rslt.put("label", sb.toString()); + } + else { + rslt.put(varid, sb.toString()); + varid = null; + } + sb.setLength(0); + } + else { + sb.append(c); + } + } + else if(c == '=') { /* var=value */ + varid = sb.toString(); /* Save variable ID */ + sb.setLength(0); + } + else if(c == ' ') { /* Ending space? */ + if(varid == null) { /* No varid? */ + rslt.put("label", sb.toString()); + } + else { + rslt.put(varid, sb.toString()); + varid = null; + } + sb.setLength(0); + } + else { + sb.append(c); + } + } + if(inquote) { /* If still in quote, syntax error */ + snd.sendMessage("Error: unclosed doublequote"); + return null; + } + return rslt; + } + public static boolean onCommand(DynmapPlugin plugin, CommandSender sender, Command cmd, String commandLabel, String[] args) { if(api == null) { sender.sendMessage("Markers component is not enabled."); @@ -427,38 +484,172 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener { 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); - } + /* Parse arguements */ + Map parms = parseArgs(args, sender); + if(parms == null) return true; + 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); + /* Fill in defaults for missing parameters */ + if(parms.get("icon") == null) { + parms.put("icon", MarkerIcon.DEFAULT); + } + if(parms.get("set") == null) { + parms.put("set", MarkerSet.DEFAULT); + } + /* Add new marker */ + MarkerSet set = api.getMarkerSet(parms.get("set")); + if(set == null) { + sender.sendMessage("Error: invalid marker set - " + parms.get("set")); + return true; + } + MarkerIcon ico = api.getMarkerIcon(parms.get("icon")); + if(ico == null) { + sender.sendMessage("Error: invalid icon - " + parms.get("icon")); + return true; + } + Marker m = set.createMarker(parms.get("id"), parms.get("label"), + loc.getWorld().getName(), loc.getX(), loc.getY(), loc.getZ(), 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()); + sender.sendMessage("Added marker id='" + m.getMarkerID() + "' (" + m.getLabel() + ") to set '" + set.getMarkerSetID() + "'"); } } else { sender.sendMessage("Marker label required"); } } + /* Update position of bookmark - must have ID parameter */ + else if(c.equals("movehere") && plugin.checkPlayerPermission(sender, "marker.movehere")) { + if(player == null) { + sender.sendMessage("Command can only be used by player"); + } + else if(args.length > 1) { + /* Parse arguements */ + Map parms = parseArgs(args, sender); + if(parms == null) return true; + if(parms.get("id") == null) { + sender.sendMessage("id= required"); + return true; + } + if(parms.get("set") == null) { + parms.put("set", MarkerSet.DEFAULT); + } + MarkerSet set = api.getMarkerSet(parms.get("set")); + if(set == null) { + sender.sendMessage("Error: invalid marker set - " + parms.get("set")); + return true; + } + Marker marker = set.findMarker(parms.get("id")); + if(marker == null) { /* No marker */ + sender.sendMessage("Error: marker not found - " + parms.get("id")); + return true; + } + Location loc = player.getLocation(); + marker.setLocation(loc.getWorld().getName(), loc.getX(), loc.getY(), loc.getZ()); + sender.sendMessage("Updated location of marker id=" + parms.get("id") + " (" + marker.getLabel() + ")"); + } + else { + sender.sendMessage("id= required"); + } + } + /* Update other attributes of marker - must have ID parameter */ + else if(c.equals("update") && plugin.checkPlayerPermission(sender, "marker.update")) { + if(args.length > 1) { + /* Parse arguements */ + Map parms = parseArgs(args, sender); + if(parms == null) return true; + if(parms.get("id") == null) { + sender.sendMessage("id= required"); + return true; + } + if(parms.get("set") == null) { + parms.put("set", MarkerSet.DEFAULT); + } + MarkerSet set = api.getMarkerSet(parms.get("set")); + if(set == null) { + sender.sendMessage("Error: invalid marker set - " + parms.get("set")); + return true; + } + Marker marker = set.findMarker(parms.get("id")); + if(marker == null) { /* No marker */ + sender.sendMessage("Error: marker not found - " + parms.get("id")); + return true; + } + if(parms.get("label") != null) { /* Label set? */ + marker.setLabel(parms.get("label")); + } + if(parms.get("icon") != null) { + MarkerIcon ico = api.getMarkerIcon(parms.get("icon")); + if(ico == null) { + sender.sendMessage("Error: invalid icon - " + parms.get("icon")); + return true; + } + marker.setMarkerIcon(ico); + } + sender.sendMessage("Updated marker id=" + parms.get("id") + " (" + marker.getLabel() + ")"); + } + else { + sender.sendMessage("id= required"); + } + } + /* Delete marker - must have ID parameter */ + else if(c.equals("delete") && plugin.checkPlayerPermission(sender, "marker.delete")) { + if(args.length > 1) { + /* Parse arguements */ + Map parms = parseArgs(args, sender); + if(parms == null) return true; + if(parms.get("id") == null) { + sender.sendMessage("id= required"); + return true; + } + if(parms.get("set") == null) { + parms.put("set", MarkerSet.DEFAULT); + } + MarkerSet set = api.getMarkerSet(parms.get("set")); + if(set == null) { + sender.sendMessage("Error: invalid marker set - " + parms.get("set")); + return true; + } + Marker marker = set.findMarker(parms.get("id")); + if(marker == null) { /* No marker */ + sender.sendMessage("Error: marker not found - " + parms.get("id")); + return true; + } + marker.deleteMarker(); + sender.sendMessage("Deleted marker id=" + parms.get("id")); + } + else { + sender.sendMessage("id= required"); + } + } + /* List markers */ + else if(c.equals("list") && plugin.checkPlayerPermission(sender, "marker.list")) { + /* Parse arguements */ + Map parms = parseArgs(args, sender); + if(parms == null) return true; + if(parms.get("set") == null) { + parms.put("set", MarkerSet.DEFAULT); + } + MarkerSet set = api.getMarkerSet(parms.get("set")); + if(set == null) { + sender.sendMessage("Error: invalid marker set - " + parms.get("set")); + return true; + } + Set markers = set.getMarkers(); + for(Marker m : markers) { + sender.sendMessage(m.getMarkerID() + ": label=\"" + m.getLabel() + "\", set=" + m.getMarkerSet().getMarkerSetID() + + ", world=" + m.getWorld() + ", x=" + m.getX() + ", y=" + m.getY() + ", z=" + m.getZ()); + } + } + /* List icons */ + else if(c.equals("icons") && plugin.checkPlayerPermission(sender, "marker.icons")) { + Set icons = api.getMarkerIcons(); + for(MarkerIcon ico : icons) { + sender.sendMessage(ico.getMarkerIconID() + ": label=\"" + ico.getMarkerIconLabel() + "\", builtin=" + ico.isBuiltIn()); + } + } else { return false; } diff --git a/src/main/java/org/dynmap/markers/impl/MarkerImpl.java b/src/main/java/org/dynmap/markers/impl/MarkerImpl.java index 0b88230b..da8bc443 100644 --- a/src/main/java/org/dynmap/markers/impl/MarkerImpl.java +++ b/src/main/java/org/dynmap/markers/impl/MarkerImpl.java @@ -15,7 +15,7 @@ class MarkerImpl implements Marker { private String markerid; private String label; private MarkerSetImpl markerset; - private int x, y, z; + private double x, y, z; private String world; private MarkerIconImpl icon; private boolean ispersistent; @@ -31,7 +31,7 @@ class MarkerImpl implements Marker { * @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) { + MarkerImpl(String id, String lbl, String world, double x, double y, double z, MarkerIconImpl icon, boolean persistent, MarkerSetImpl set) { markerid = id; if(lbl != null) label = lbl; @@ -61,9 +61,9 @@ class MarkerImpl implements Marker { */ boolean loadPersistentData(ConfigurationNode node) { label = node.getString("label", markerid); - x = node.getInt("x", 0); - y = node.getInt("y", 64); - z = node.getInt("z", 0); + x = node.getDouble("x", 0); + y = node.getDouble("y", 64); + z = node.getDouble("z", 0); world = node.getString("world", "world"); icon = MarkerAPIImpl.getMarkerIconImpl(node.getString("icon", MarkerIcon.DEFAULT)); ispersistent = true; /* Loaded from config, so must be */ @@ -142,9 +142,9 @@ class MarkerImpl implements Marker { 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("x", Double.valueOf(x)); + node.put("y", Double.valueOf(y)); + node.put("z", Double.valueOf(z)); node.put("world", world); node.put("icon", icon.getMarkerIconID()); @@ -155,19 +155,19 @@ class MarkerImpl implements Marker { return world; } @Override - public int getX() { + public double getX() { return x; } @Override - public int getY() { + public double getY() { return y; } @Override - public int getZ() { + public double getZ() { return z; } @Override - public void setLocation(String worldid, int x, int y, int z) { + public void setLocation(String worldid, double x, double y, double z) { this.world = worldid; this.x = x; this.y = y; diff --git a/src/main/java/org/dynmap/markers/impl/MarkerSetImpl.java b/src/main/java/org/dynmap/markers/impl/MarkerSetImpl.java index 9c248c1b..a9fe6568 100644 --- a/src/main/java/org/dynmap/markers/impl/MarkerSetImpl.java +++ b/src/main/java/org/dynmap/markers/impl/MarkerSetImpl.java @@ -57,7 +57,7 @@ class MarkerSetImpl implements MarkerSet { } @Override - public Marker createMarker(String id, String label, String world, int x, int y, int z, MarkerIcon icon, boolean is_persistent) { + public Marker createMarker(String id, String label, String world, double x, double y, double z, MarkerIcon icon, boolean is_persistent) { if(id == null) { /* If not defined, generate unique one */ int i = 0; do { diff --git a/src/main/resources/configuration.txt b/src/main/resources/configuration.txt index e7d00042..00be9d74 100644 --- a/src/main/resources/configuration.txt +++ b/src/main/resources/configuration.txt @@ -43,6 +43,8 @@ components: # 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 + # If set, shows labels all the time (default is only on hover) + #showlabel: true - class: org.dynmap.ClientComponent type: chat diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 39d88f46..70a89102 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -26,7 +26,13 @@ commands: dmarker: description: Manipulate map markers usage: | - / add