Add area marker API implementation

This commit is contained in:
Mike Primm 2011-10-20 11:43:07 +08:00 committed by mikeprimm
parent d70ea37b31
commit c0309fb36a
7 changed files with 676 additions and 25 deletions

View File

@ -0,0 +1,123 @@
package org.dynmap.markers;
/**
* This defines the public interface to an area marker object, for use with the MarkerAPI
*/
public interface AreaMarker extends GenericMarker {
/**
* Get the marker's label
*/
public String getLabel();
/**
* Update the marker's label (plain text)
*/
public void setLabel(String lbl);
/**
* Update the marker's label and markup flag
* @param label - label string
* @param markup - if true, label is processed as HTML (innerHTML for <span> used for label); false implies plaintext
*/
public void setLabel(String lbl, boolean markup);
/**
* Test if marker label is processed as HTML
*/
public boolean isLabelMarkup();
/**
* Set marker description (HTML markup shown in popup when clicked)
* @param desc - HTML markup description
*/
public void setDescription(String desc);
/**
* Get marker description
* @return descrption
*/
public String getDescription();
/**
* Get top Y coordinate
* @return coordinate
*/
public double getTopY();
/**
* Get bottom Y coordinate
* @return coordinate
*/
public double getBottomY();
/**
* Set Y coordinate range
* @param ytop - y coordinate of top
* @param ybottom - y coordinate of bottom (=top for 2D)
*/
public void setRangeY(double ytop, double ybottom);
/**
* Get corner location count
*/
public int getCornerCount();
/**
* Get X coordinate of corner N
* @param n - corner index
* @return coordinate
*/
public double getCornerX(int n);
/**
* Get Z coordinate of corner N
* @param n - corner index
* @return coordinate
*/
public double getCornerZ(int n);
/**
* Set coordinates of corner N
* @param n - index of corner: append new corner if >= corner count, else replace existing
* @param x - x coordinate
* @param z - z coordinate
*/
public void setCornerLocation(int n, double x, double z);
/**
* Set/replace all corners
* @param x - list of x coordinates
* @param z - list of z coordinates
*/
public void setCornerLocations(double[] x, double[] z);
/**
* Delete corner N - shift corners after N forward
* @param n - index of corner
*/
public void deleteCorner(int n);
/**
* Set line style
* @param weight - stroke weight
* @param opacity - stroke opacity
* @param color - stroke color (0xRRGGBB)
*/
public void setLineStyle(int weight, double opacity, int color);
/**
* Get line weight
* @return weight
*/
public int getLineWeight();
/**
* Get line opacity
* @return opacity (0.0-1.0)
*/
public double getLineOpacity();
/**
* Get line color
* @return color (0xRRGGBB)
*/
public int getLineColor();
/**
* Set fill style
* @param opacity - fill color opacity
* @param color - fill color (0xRRGGBB)
*/
public void setFillStyle(double opacity, int color);
/**
* Get fill opacity
* @return opacity (0.0-1.0)
*/
public double getFillOpacity();
/**
* Get fill color
* @return color (0xRRGGBB)
*/
public int getFillColor();
}

View File

@ -0,0 +1,32 @@
package org.dynmap.markers;
import org.bukkit.Location;
/**
* This defines the public interface to a generic marker object, for use with the MarkerAPI
*/
public interface GenericMarker {
/**
* 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();
/**
* Test if marker is persistent
*/
public boolean isPersistentMarker();
}

View File

@ -5,26 +5,7 @@ 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();
public interface Marker extends GenericMarker {
/**
* Get marker's X coordinate
* @return x coordinate
@ -59,10 +40,6 @@ public interface Marker {
* @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
*/

View File

@ -15,6 +15,11 @@ public interface MarkerSet {
* @return set of markers (set is copy - safe to iterate)
*/
public Set<Marker> getMarkers();
/**
* Get set of all area markers currently in the set
* @return set of area markers (set is copy - safe to iterate)
*/
public Set<AreaMarker> getAreaMarkers();
/**
* Create a new marker in the marker set
*
@ -56,6 +61,31 @@ public interface MarkerSet {
* @return marker, or null if none found
*/
public Marker findMarkerByLabel(String lbl);
/**
* Create area marker
* @param id - marker ID
* @param lbl - label
* @param markup - if true, label is HTML markup
* @param world - world id
* @param x - x coord list
* @param z - z coord list
* @param ytop - top y coordinate
* @param ybottom - bottom y coordinate
* @param persistent - true if persistent
*/
public AreaMarker createAreaMarker(String id, String lbl, boolean markup, String world, double x[], double z[], double ytop, double ybottom, boolean persistent);
/**
* Get area marker by ID
* @param id - ID of the area marker
* @return marker, or null if cannot be found
*/
public AreaMarker findAreaMarker(String id);
/**
* Find area marker by label - best matching substring
* @param lbl - label to find (same = best match)
* @return marker, or null if none found
*/
public AreaMarker findAreaMarkerByLabel(String lbl);
/**
* Get ID of marker set - unique among marker sets
* @return ID

View File

@ -0,0 +1,326 @@
package org.dynmap.markers.impl;
import java.util.ArrayList;
import java.util.HashMap;
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.markers.AreaMarker;
import org.dynmap.markers.MarkerIcon;
import org.dynmap.markers.MarkerSet;
import org.dynmap.markers.impl.MarkerAPIImpl.MarkerUpdate;
class AreaMarkerImpl implements AreaMarker {
private String markerid;
private String label;
private boolean markup;
private String desc;
private MarkerSetImpl markerset;
private String world;
private boolean ispersistent;
private ArrayList<Coord> corners;
private int lineweight = 3;
private double lineopacity = 0.8;
private int linecolor = 0xFF0000;
private double fillopacity = 0.35;
private int fillcolor = 0xFF0000;
private double ytop = 64.0;
private double ybottom = 64.0;
private static class Coord {
double x, z;
Coord(double x, double z) {
this.x = x; this.z = z;
}
}
/**
* Create area marker
* @param id - marker ID
* @param lbl - label
* @param markup - if true, label is HTML markup
* @param world - world id
* @param x - x coord list
* @param z - z coord list
* @param ytop - top y coordinate
* @param ybottom - bottom y coordinate
* @param persistent - true if persistent
* @param set - marker set
*/
AreaMarkerImpl(String id, String lbl, boolean markup, String world, double x[], double z[], double ytop, double ybottom, boolean persistent, MarkerSetImpl set) {
markerid = id;
if(lbl != null)
label = lbl;
else
label = id;
this.markup = markup;
this.corners = new ArrayList<Coord>();
for(int i = 0; i < x.length; i++) {
this.corners.add(new Coord(x[i], z[i]));
}
this.ytop = ytop;
this.ybottom = ybottom;
this.world = world;
this.desc = null;
ispersistent = persistent;
markerset = set;
}
/**
* Make bare area marker - used for persistence load
* @param id - marker ID
* @param set - marker set
*/
AreaMarkerImpl(String id, MarkerSetImpl set) {
markerid = id;
markerset = set;
label = id;
markup = false;
desc = null;
corners = new ArrayList<Coord>();
world = "world";
}
/**
* Load marker from configuration node
* @param node - configuration node
*/
boolean loadPersistentData(ConfigurationNode node) {
label = node.getString("label", markerid);
markup = node.getBoolean("markup", false);
ytop = node.getDouble("ytop", 64.0);
ybottom = node.getDouble("ybottom", 64.0);
List<Double> xx = node.getDoubleList("x", null);
List<Double> zz = node.getDoubleList("z", null);
corners.clear();
if((xx != null) && (zz != null)) {
for(int i = 0; (i < xx.size()) && (i < zz.size()); i++)
corners.add(new Coord(xx.get(i), zz.get(i)));
}
world = node.getString("world", "world");
desc = node.getString("desc", null);
lineweight = node.getInt("strokeWeight", 3);
lineopacity = node.getDouble("strokeOpacity", 0.8);
linecolor = node.getInt("strokeColor", 0xFF0000);
fillopacity = node.getDouble("fillOpacity", 0.35);
fillcolor = node.getInt("fillColor", 0xFF0000);
ispersistent = true; /* Loaded from config, so must be */
return true;
}
void cleanup() {
corners.clear();
markerset = null;
}
@Override
public String getMarkerID() {
return markerid;
}
@Override
public MarkerSet getMarkerSet() {
return markerset;
}
@Override
public void deleteMarker() {
markerset.removeAreaMarker(this); /* Remove from our marker set (notified by set) */
cleanup();
}
@Override
public boolean isPersistentMarker() {
return ispersistent;
}
@Override
public String getLabel() {
return label;
}
@Override
public void setLabel(String lbl) {
setLabel(lbl, false);
}
@Override
public void setLabel(String lbl, boolean markup) {
label = lbl;
this.markup = markup;
MarkerAPIImpl.areaMarkerUpdated(this, MarkerUpdate.UPDATED);
if(ispersistent)
MarkerAPIImpl.saveMarkers();
}
/**
* Get configuration node to be saved
* @return node
*/
Map<String, Object> getPersistentData() {
if(!ispersistent) /* Nothing if not persistent */
return null;
HashMap<String, Object> node = new HashMap<String, Object>();
node.put("label", label);
node.put("markup", markup);
double[] xx = new double[corners.size()];
double[] zz = new double[corners.size()];
for(int i = 0; i < xx.length; i++) {
xx[i] = corners.get(i).x;
zz[i] = corners.get(i).z;
}
node.put("x", xx);
node.put("ytop", Double.valueOf(ytop));
node.put("ybottom", Double.valueOf(ybottom));
node.put("z", zz);
node.put("world", world);
if(desc != null)
node.put("desc", desc);
node.put("stokeWeight", lineweight);
node.put("strokeOpacity", lineopacity);
node.put("strokeColor", linecolor);
node.put("fillOpacity", fillopacity);
node.put("fillColor", fillcolor);
return node;
}
@Override
public String getWorld() {
return world;
}
@Override
public boolean isLabelMarkup() {
return markup;
}
@Override
public void setDescription(String desc) {
if((this.desc == null) || (this.desc.equals(desc) == false)) {
this.desc = desc;
MarkerAPIImpl.areaMarkerUpdated(this, MarkerUpdate.UPDATED);
if(ispersistent)
MarkerAPIImpl.saveMarkers();
}
}
/**
* Get marker description
* @return descrption
*/
public String getDescription() {
return this.desc;
}
@Override
public double getTopY() {
return ytop;
}
@Override
public double getBottomY() {
return ybottom;
}
@Override
public void setRangeY(double ytop, double ybottom) {
if((this.ytop != ytop) || (this.ybottom != ybottom)) {
this.ytop = ytop;
this.ybottom = ybottom;
MarkerAPIImpl.areaMarkerUpdated(this, MarkerUpdate.UPDATED);
if(ispersistent)
MarkerAPIImpl.saveMarkers();
}
}
@Override
public int getCornerCount() {
return corners.size();
}
@Override
public double getCornerX(int n) {
Coord c = corners.get(n);
if(c != null)
return c.x;
return 0;
}
@Override
public double getCornerZ(int n) {
Coord c = corners.get(n);
if(c != null)
return c.z;
return 0;
}
@Override
public void setCornerLocation(int n, double x, double z) {
Coord c;
if(n >= corners.size()) {
corners.add(new Coord(x, z));
}
else {
c = corners.get(n);
if((c.x == x) && (c.z == z))
return;
c.x = x;
c.z = z;
}
MarkerAPIImpl.areaMarkerUpdated(this, MarkerUpdate.UPDATED);
if(ispersistent)
MarkerAPIImpl.saveMarkers();
}
@Override
public void deleteCorner(int n) {
if(n < corners.size()) {
corners.remove(n);
MarkerAPIImpl.areaMarkerUpdated(this, MarkerUpdate.UPDATED);
if(ispersistent)
MarkerAPIImpl.saveMarkers();
}
}
@Override
public void setCornerLocations(double[] x, double[] z) {
corners.clear();
for(int i = 0; (i < x.length) && (i < z.length); i++) {
corners.add(new Coord(x[i], z[i]));
}
MarkerAPIImpl.areaMarkerUpdated(this, MarkerUpdate.UPDATED);
if(ispersistent)
MarkerAPIImpl.saveMarkers();
}
@Override
public void setLineStyle(int weight, double opacity, int color) {
if((weight != lineweight) || (opacity != lineopacity) || (color != linecolor)) {
lineweight = weight;
lineopacity = opacity;
linecolor = color;
MarkerAPIImpl.areaMarkerUpdated(this, MarkerUpdate.UPDATED);
if(ispersistent)
MarkerAPIImpl.saveMarkers();
}
}
@Override
public int getLineWeight() {
return lineweight;
}
@Override
public double getLineOpacity() {
return lineopacity;
}
@Override
public int getLineColor() {
return linecolor;
}
@Override
public void setFillStyle(double opacity, int color) {
if((opacity != fillopacity) || (color != fillcolor)) {
fillopacity = opacity;
fillcolor = color;
MarkerAPIImpl.areaMarkerUpdated(this, MarkerUpdate.UPDATED);
if(ispersistent)
MarkerAPIImpl.saveMarkers();
}
}
@Override
public double getFillOpacity() {
return fillopacity;
}
@Override
public int getFillColor() {
return fillcolor;
}
}

View File

@ -31,6 +31,7 @@ import org.dynmap.Event;
import org.dynmap.Log;
import org.dynmap.MapManager;
import org.dynmap.Client.ComponentMessage;
import org.dynmap.markers.AreaMarker;
import org.dynmap.markers.Marker;
import org.dynmap.markers.MarkerAPI;
import org.dynmap.markers.MarkerIcon;
@ -91,6 +92,46 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
}
}
public static class AreaMarkerUpdated extends MarkerComponentMessage {
public String msg;
public double ytop, ybottom;
public double[] x;
public double[] z;
public int strokeWeight;
public double strokeOpacity;
public int strokeColor;
public double fillOpacity;
public int fillColor;
public String id;
public String label;
public String set;
public AreaMarkerUpdated(AreaMarker m, boolean deleted) {
this.id = m.getMarkerID();
this.label = m.getLabel();
this.ytop = m.getTopY();
this.ybottom = m.getBottomY();
int cnt = m.getCornerCount();
x = new double[cnt];
z = new double[cnt];
for(int i = 0; i < cnt; i++) {
x[i] = m.getCornerX(i);
z[i] = m.getCornerZ(i);
}
strokeColor = m.getLineColor();
strokeWeight = m.getLineWeight();
strokeOpacity = m.getFillOpacity();
fillColor = m.getFillColor();
fillOpacity = m.getFillOpacity();
this.set = m.getMarkerSet().getMarkerSetID();
if(deleted)
msg = "areamarkerdeleted";
else
msg = "areamarkerupdated";
}
}
public static class MarkerSetUpdated extends MarkerComponentMessage {
public String msg;
public String id;
@ -386,6 +427,19 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
if(MapManager.mapman != null)
MapManager.mapman.pushUpdate(marker.getWorld(), new MarkerUpdated(marker, update == MarkerUpdate.DELETED));
}
/**
* Signal area marker update
* @param marker - updated marker
* @param update - type of update
*/
static void areaMarkerUpdated(AreaMarkerImpl marker, MarkerUpdate 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 AreaMarkerUpdated(marker, update == MarkerUpdate.DELETED));
}
/**
* Signal marker set update
* @param markerset - updated marker set
@ -1061,6 +1115,31 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
}
msdata.put("markers", markers); /* Add markers to set data */
HashMap<String, Object> areas = new HashMap<String, Object>();
for(AreaMarker m : ms.getAreaMarkers()) {
if(m.getWorld().equals(wname) == false) continue;
HashMap<String, Object> mdata = new HashMap<String, Object>();
int cnt = m.getCornerCount();
double xx[] = new double[cnt];
double zz[] = new double[cnt];
for(int i = 0; i < cnt; i++) {
xx[i] = m.getCornerX(i);
zz[i] = m.getCornerZ(i);
}
mdata.put("x", xx);
mdata.put("ytop", m.getTopY());
mdata.put("ybottom", m.getBottomY());
mdata.put("z", zz);
mdata.put("label", m.getLabel());
mdata.put("markup", m.isLabelMarkup());
if(m.getDescription() != null)
mdata.put("desc", m.getDescription());
/* Add to markers */
areas.put(m.getMarkerID(), mdata);
}
msdata.put("areas", areas); /* Add areamarkers to set data */
markerdata.put(ms.getMarkerSetID(), msdata); /* Add marker set data to world marker data */
}
worlddata.put("sets", markerdata);

View File

@ -10,6 +10,7 @@ import java.util.Set;
import org.bukkit.Location;
import org.bukkit.util.config.ConfigurationNode;
import org.dynmap.Log;
import org.dynmap.markers.AreaMarker;
import org.dynmap.markers.Marker;
import org.dynmap.markers.MarkerIcon;
import org.dynmap.markers.MarkerSet;
@ -17,6 +18,7 @@ import org.dynmap.markers.impl.MarkerAPIImpl.MarkerUpdate;
class MarkerSetImpl implements MarkerSet {
private HashMap<String, MarkerImpl> markers = new HashMap<String, MarkerImpl>();
private HashMap<String, AreaMarkerImpl> areamarkers = new HashMap<String, AreaMarkerImpl>();
private String setid;
private String label;
private HashMap<String, MarkerIconImpl> allowedicons = null;
@ -49,6 +51,8 @@ class MarkerSetImpl implements MarkerSet {
void cleanup() {
for(MarkerImpl m : markers.values())
m.cleanup();
for(AreaMarkerImpl m : areamarkers.values())
m.cleanup();
markers.clear();
}
@ -57,6 +61,11 @@ class MarkerSetImpl implements MarkerSet {
return new HashSet<Marker>(markers.values());
}
@Override
public Set<AreaMarker> getAreaMarkers() {
return new HashSet<AreaMarker>(areamarkers.values());
}
@Override
public Marker createMarker(String id, String label, String world, double x, double y, double z, MarkerIcon icon, boolean is_persistent) {
return createMarker(id, label, false, world, x, y, z, icon, is_persistent);
@ -196,6 +205,18 @@ class MarkerSetImpl implements MarkerSet {
}
MarkerAPIImpl.markerUpdated(marker, MarkerUpdate.DELETED);
}
/**
* Remove marker from set
*
* @param marker
*/
void removeAreaMarker(AreaMarkerImpl marker) {
markers.remove(marker.getMarkerID()); /* Remove from set */
if(ispersistent && marker.isPersistentMarker()) { /* If persistent */
MarkerAPIImpl.saveMarkers(); /* Drive save */
}
MarkerAPIImpl.areaMarkerUpdated(marker, MarkerUpdate.DELETED);
}
/**
* Get configuration node to be saved
@ -211,6 +232,13 @@ class MarkerSetImpl implements MarkerSet {
node.put(id, m.getPersistentData());
}
}
HashMap<String, Object> anode = new HashMap<String, Object>();
for(String id : areamarkers.keySet()) {
AreaMarkerImpl m = areamarkers.get(id);
if(m.isPersistentMarker()) {
anode.put(id, m.getPersistentData());
}
}
/* Make top level node */
HashMap<String, Object> setnode = new HashMap<String, Object>();
setnode.put("label", label);
@ -219,6 +247,7 @@ class MarkerSetImpl implements MarkerSet {
setnode.put("allowedicons", allowed);
}
setnode.put("markers", node);
setnode.put("areas", anode);
setnode.put("hide", hide_by_def);
setnode.put("layerprio", prio);
return setnode;
@ -243,6 +272,19 @@ class MarkerSetImpl implements MarkerSet {
}
}
}
ConfigurationNode areamarkernode = node.getNode("areas");
if(areamarkernode != null) {
for(String id : areamarkernode.getKeys()) {
AreaMarkerImpl marker = new AreaMarkerImpl(id, this); /* Make and load marker */
if(marker.loadPersistentData(areamarkernode.getNode(id))) {
areamarkers.put(id, marker);
}
else {
Log.info("Error loading area marker '" + id + "' for set '" + setid + "'");
marker.cleanup();
}
}
}
List<String> allowed = node.getStringList("allowedicons", null);
if(allowed != null) {
for(String id : allowed) {
@ -286,4 +328,46 @@ class MarkerSetImpl implements MarkerSet {
return this.prio;
}
@Override
public AreaMarker createAreaMarker(String id, String lbl, boolean markup, String world, double[] x, double[] z, double ytop, double ybottom, boolean persistent) {
if(id == null) { /* If not defined, generate unique one */
int i = 0;
do {
i++;
id = "area_" + i;
} while(areamarkers.containsKey(id));
}
if(areamarkers.containsKey(id)) return null; /* Duplicate ID? */
/* Create marker */
persistent = persistent && this.ispersistent;
AreaMarkerImpl marker = new AreaMarkerImpl(id, label, markup, world, x, z, ytop, ybottom, persistent, this);
areamarkers.put(id, marker); /* Add to set */
if(persistent)
MarkerAPIImpl.saveMarkers();
MarkerAPIImpl.areaMarkerUpdated(marker, MarkerUpdate.CREATED); /* Signal create */
return marker;
}
@Override
public AreaMarker findAreaMarker(String id) {
return areamarkers.get(id);
}
@Override
public AreaMarker findAreaMarkerByLabel(String lbl) {
AreaMarker match = null;
int matchlen = Integer.MAX_VALUE;
for(AreaMarker m : areamarkers.values()) {
if(m.getLabel().contains(lbl)) {
if(matchlen > m.getLabel().length()) {
match = m;
matchlen = m.getLabel().length();
}
}
}
return match;
}
}