Merge remote branch 'origin/master'

This commit is contained in:
Mike Primm 2011-09-04 02:05:58 -05:00
commit 6b301b2208
98 changed files with 1380 additions and 8 deletions

View File

@ -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' */
}
}

View File

@ -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.Type, List<Listener>> event_handlers = new HashMap<Event.Type, List<Listener>>();
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.<Object>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;
}
}

View File

@ -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) {

View File

@ -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;
}
}
}

View File

@ -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);
}

View File

@ -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<MarkerSet> 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<MarkerIcon> iconlimit, boolean persistent);
/**
* Get set of defined marker icons
* @return set of marker icons
*/
public Set<MarkerIcon> 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);
}

View File

@ -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();
}

View File

@ -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<Marker> 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<MarkerIcon> 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<MarkerIcon> getMarkerIconsInUse();
/**
* Delete marker set
*/
public void deleteMarkerSet();
}

View File

@ -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<DynmapWorld> {
private File markerpersist;
private File markerdir; /* Local store for markers (internal) */
private File markertiledir; /* Marker directory for web server (under tiles) */
private HashMap<String, MarkerIconImpl> markericons = new HashMap<String, MarkerIconImpl>();
private HashMap<String, MarkerSetImpl> markersets = new HashMap<String, MarkerSetImpl>();
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<MarkerSet> getMarkerSets() {
return new HashSet<MarkerSet>(markersets.values());
}
@Override
public MarkerSet getMarkerSet(String id) {
return markersets.get(id);
}
@Override
public MarkerSet createMarkerSet(String id, String lbl, Set<MarkerIcon> 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<MarkerIcon> getMarkerIcons() {
return new HashSet<MarkerIcon>(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<String, Object> icons = new HashMap<String,Object>();
for(String id : api.markericons.keySet()) {
MarkerIconImpl ico = api.markericons.get(id);
Map<String,Object> dat = ico.getPersistentData();
if(dat != null) {
icons.put(id, dat);
}
}
conf.setProperty("icons", icons);
/* Then, save persistent sets */
HashMap<String, Object> sets = new HashMap<String, Object>();
for(String id : api.markersets.keySet()) {
MarkerSetImpl set = api.markersets.get(id);
if(set.isMarkerSetPersistent()) {
Map<String, Object> 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<String,ConfigurationNode> 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<String,ConfigurationNode> 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<String> commands = new HashSet<String>(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<String, Object> markerdata = new HashMap<String, Object>();
File f = new File(markertiledir, "marker_" + wname + ".json");
Map<String, Object> worlddata = new HashMap<String, Object>();
worlddata.put("timestamp", Long.valueOf(System.currentTimeMillis())); /* Add timestamp */
for(MarkerSet ms : markersets.values()) {
HashMap<String, Object> msdata = new HashMap<String, Object>();
msdata.put("label", ms.getMarkerSetLabel());
HashMap<String, Object> markers = new HashMap<String, Object>();
for(Marker m : ms.getMarkers()) {
if(m.getWorld().equals(wname) == false) continue;
HashMap<String, Object> mdata = new HashMap<String, Object>();
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());
}
}

View File

@ -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<String, Object> getPersistentData() {
if(is_builtin)
return null;
HashMap<String, Object> node = new HashMap<String, Object>();
node.put("label", label);
return node;
}
boolean loadPersistentData(ConfigurationNode node) {
if(is_builtin)
return false;
label = node.getString("label", iconid);
return true;
}
}

View File

@ -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<MarkerIcon> 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<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("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();
}
}

View File

@ -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<String, MarkerImpl> markers = new HashMap<String, MarkerImpl>();
private String setid;
private String label;
private HashMap<String, MarkerIconImpl> allowedicons = null;
private boolean ispersistent;
MarkerSetImpl(String id) {
setid = id;
label = id;
}
MarkerSetImpl(String id, String lbl, Set<MarkerIcon> iconlimit, boolean persistent) {
setid = id;
if(lbl != null)
label = lbl;
else
label = id;
if(iconlimit != null) {
allowedicons = new HashMap<String, MarkerIconImpl>();
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<Marker> getMarkers() {
return new HashSet<Marker>(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<MarkerIcon> getAllowedMarkerIcons() {
if(allowedicons != null)
return new HashSet<MarkerIcon>(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<MarkerIcon> getMarkerIconsInUse() {
HashSet<String> ids = new HashSet<String>();
HashSet<MarkerIcon> icons = new HashSet<MarkerIcon>();
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<String, Object> getPersistentData() {
if(!ispersistent) /* Nothing if not persistent */
return null;
HashMap<String, Object> node = new HashMap<String, Object>();
for(String id : markers.keySet()) {
MarkerImpl m = markers.get(id);
if(m.isPersistentMarker()) {
node.put(id, m.getPersistentData());
}
}
/* Make top level node */
HashMap<String, Object> setnode = new HashMap<String, Object>();
setnode.put("label", label);
if(allowedicons != null) {
ArrayList<String> allowed = new ArrayList<String>(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<String> 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;
}
}

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 831 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 771 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 639 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 609 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 756 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 726 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 871 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 719 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 959 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 657 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 692 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 630 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 792 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 729 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 745 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 543 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 608 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 672 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 695 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 906 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 654 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 473 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 724 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 584 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 781 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 555 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 879 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 606 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 381 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 773 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 732 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 710 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 637 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 920 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 777 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 664 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 699 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 722 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 814 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 742 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 727 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 664 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 691 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 685 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 781 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 689 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 709 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 521 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 711 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 753 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 659 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 617 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 620 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 637 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 744 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 694 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 737 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 363 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 568 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 664 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 650 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 635 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 717 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 798 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 611 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 621 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 815 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 854 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 747 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 716 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 623 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 700 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 652 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 910 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 660 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 671 B

View File

@ -23,6 +23,11 @@ commands:
/<command> stats world - Show render statistics for maps on world 'world'.
/<command> resetstats - Reset render statistics.
/<command> resetstats world - Reset render statistics for maps on world 'world'.
dmarker:
description: Manipulate map markers
usage: |
/<command> add <label> - add new marker at current location (use double-quotes if spaces needed)
permissions:
dynmap.*:
description: Gives access to all dynmap functions
@ -39,6 +44,7 @@ permissions:
dynmap.reload: true
dynmap.stats: true
dynmap.resetstats: true
dynmap.marker.add: true
dynmap.render:
description: Allows /dynmap render command
default: true
@ -72,3 +78,7 @@ permissions:
dynmap.resetstats:
description: Allows /dynmap resetstats or /dynmap resetstats <world>
default: op
dynmap.marker.add:
description: Allows /dmarker add
default: op

View File

@ -499,6 +499,9 @@ DynMap.prototype = {
},
playerquit: function() {
$(me).trigger('playerquit', [ update.playerName ]);
},
component: function() {
$(me).trigger('component.' + update.ctype, [ update ]);
}
});
}

34
web/js/markers.js Normal file
View File

@ -0,0 +1,34 @@
var dynmapmarkersets = {};
componentconstructors['markers'] = function(dynmap, configuration) {
var me = this;
function loadmarkers(world) {
dynmapmarkersets = {};
$.getJSON(dynmap.options.tileUrl+'_markers_/marker_'+world+'.json', function(data) {
var ts = data.timestamp;
$.each(data.sets, function(name, markerset) {
dynmapmarkersets[name] = markerset;
});
});
}
$(dynmap).bind('component.markers', function(event, msg) {
console.log('got marker event - ' + msg.ctype + ', ' + msg.msg);
});
// Remove marker on start of map change
$(dynmap).bind('mapchanging', function(event) {
});
// Remove marker on map change - let update place it again
$(dynmap).bind('mapchanged', function(event) {
});
// Load markers for new world
$(dynmap).bind('worldchanged', function(event) {
loadmarkers(this.world.name);
});
loadmarkers(dynmap.world.name);
};

View File

@ -9,12 +9,44 @@ function createMinecraftHead(player,size,completed,failed) {
faceImage.src = dynmap.options.tileUrl + 'faces/' + size + 'x' + size + '/' + player + '.png';
}
var playerHeads = {};
function getMinecraftHead(player,size,completed) {
createMinecraftHead(player, size, completed, function() {
console.error('Failed to retrieve face of "', player, '" with size "', size, '"!')
});
var key = player + '.' + size;
var head = playerHeads[key];
// Synchronous
if (!completed) {
return (!head || head.working) ? null : head;
}
// Asynchronous
if (!head) {
playerHeads[key] = { working: true, hooks: [{f:completed}] };
createMinecraftHead(player, size, function(head) {
hooks = playerHeads[key].hooks;
playerHeads[key] = head;
var i;
for(i=0;i<hooks.length;i++) {
hooks[i].f(head);
}
head.working = false;
}, function() {
});
} else if (head.working) {
//console.log('Other process working on head of ',player,', will add myself to hooks...');
head.hooks[head.hooks.length] = {f:completed};
} else {
completed(head);
}
}
//function getMinecraftHead(player,size,completed) {
// createMinecraftHead(player, size, completed, function() {
// console.error('Failed to retrieve face of "', player, '" with size "', size, '"!')
// });
//}
function getMinecraftTime(servertime) {
servertime = parseInt(servertime);
var day = servertime >= 0 && servertime < 13700;