Finish split of dynmap and DynmapCore

This commit is contained in:
Mike Primm 2012-01-17 23:58:11 -06:00
parent aa5d73ea09
commit fc319a2d32
363 changed files with 77 additions and 31180 deletions

View file

@ -1,161 +0,0 @@
package org.dynmap;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
public class AsynchronousQueue<T> {
private Object lock = new Object();
private Thread thread;
private LinkedBlockingQueue<T> queue = new LinkedBlockingQueue<T>();
private Set<T> set = new HashSet<T>();
private Handler<T> handler;
private int dequeueTime;
private int accelDequeueTime;
private int accelDequeueThresh;
private int pendingcnt;
private int pendinglimit;
private boolean normalprio;
public AsynchronousQueue(Handler<T> handler, int dequeueTime, int accelDequeueThresh, int accelDequeueTime, int pendinglimit, boolean normalprio) {
this.handler = handler;
this.dequeueTime = dequeueTime;
this.accelDequeueTime = accelDequeueTime;
this.accelDequeueThresh = accelDequeueThresh;
if(pendinglimit < 1) pendinglimit = 1;
this.pendinglimit = pendinglimit;
this.normalprio = normalprio;
}
public boolean push(T t) {
synchronized (lock) {
if (!set.add(t)) {
return false;
}
}
queue.offer(t);
return true;
}
private T pop() {
try {
T t = queue.take();
synchronized (lock) {
set.remove(t);
}
return t;
} catch (InterruptedException ix) {
return null;
}
}
public boolean remove(T t) {
synchronized (lock) {
if (set.remove(t)) {
queue.remove(t);
return true;
}
}
return false;
}
public int size() {
return set.size();
}
public List<T> popAll() {
List<T> s;
synchronized(lock) {
s = new ArrayList<T>(queue);
queue.clear();
set.clear();
}
return s;
}
public void start() {
synchronized (lock) {
thread = new Thread(new Runnable() {
@Override
public void run() {
running();
}
});
thread.start();
try {
if(!normalprio)
thread.setPriority(Thread.MIN_PRIORITY);
} catch (SecurityException e) {
Log.info("Failed to set minimum priority for worker thread!");
}
}
}
public void stop() {
synchronized (lock) {
if (thread == null)
return;
Thread oldThread = thread;
thread = null;
Log.info("Stopping map renderer...");
oldThread.interrupt();
try {
oldThread.join(1000);
} catch (InterruptedException e) {
Log.info("Waiting for map renderer to stop is interrupted");
}
}
}
private void running() {
try {
while (Thread.currentThread() == thread) {
synchronized(lock) {
while(pendingcnt >= pendinglimit) {
try {
lock.wait(accelDequeueTime);
} catch (InterruptedException ix) {
if(Thread.currentThread() != thread)
return;
throw ix;
}
}
}
T t = pop();
if (t != null) {
synchronized(lock) {
pendingcnt++;
}
handler.handle(t);
}
if(set.size() >= accelDequeueThresh)
sleep(accelDequeueTime);
else
sleep(dequeueTime);
}
} catch (Exception ex) {
Log.severe("Exception on rendering-thread", ex);
}
}
private boolean sleep(int time) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
return false;
}
return true;
}
public void done(T t) {
synchronized (lock) {
if(pendingcnt > 0) pendingcnt--;
lock.notifyAll();
}
}
}

View file

@ -1,12 +0,0 @@
package org.dynmap;
public class ChatEvent {
public String source;
public String name;
public String message;
public ChatEvent(String source, String name, String message) {
this.source = source;
this.name = name;
this.message = message;
}
}

View file

@ -1,160 +0,0 @@
package org.dynmap;
import java.io.IOException;
import java.io.Writer;
import org.json.simple.JSONAware;
import org.json.simple.JSONStreamAware;
import org.dynmap.common.DynmapChatColor;
public class Client {
public static class Update implements JSONAware, JSONStreamAware {
public long timestamp = System.currentTimeMillis();
@Override
public String toJSONString() {
return org.dynmap.web.Json.stringifyJson(this);
}
@Override
public void writeJSONString(Writer w) throws IOException {
// TODO: This isn't the best...
w.write(toJSONString());
}
}
public static class ChatMessage extends Update {
public String type = "chat";
public String source;
public String playerName;
public String message;
public String account;
public String channel;
public ChatMessage(String source, String channel, String playerName, String message, String playeraccount) {
this.source = source;
this.playerName = Client.stripColor(playerName);
this.message = DynmapChatColor.stripColor(message);
this.account = playeraccount;
this.channel = channel;
}
@Override
public boolean equals(Object o) {
if(o instanceof ChatMessage) {
ChatMessage m = (ChatMessage)o;
return m.source.equals(source) && m.playerName.equals(playerName) && m.message.equals(message);
}
return false;
}
@Override
public int hashCode() {
return source.hashCode() ^ playerName.hashCode() ^ message.hashCode();
}
}
public static class PlayerJoinMessage extends Update {
public String type = "playerjoin";
public String playerName;
public String account;
public PlayerJoinMessage(String playerName, String playeraccount) {
this.playerName = Client.stripColor(playerName);
this.account = playeraccount;
}
@Override
public boolean equals(Object o) {
if(o instanceof PlayerJoinMessage) {
PlayerJoinMessage m = (PlayerJoinMessage)o;
return m.playerName.equals(playerName);
}
return false;
}
@Override
public int hashCode() {
return playerName.hashCode();
}
}
public static class PlayerQuitMessage extends Update {
public String type = "playerquit";
public String playerName;
public String account;
public PlayerQuitMessage(String playerName, String playeraccount) {
this.playerName = Client.stripColor(playerName);
this.account = playeraccount;
}
@Override
public boolean equals(Object o) {
if(o instanceof PlayerQuitMessage) {
PlayerQuitMessage m = (PlayerQuitMessage)o;
return m.playerName.equals(playerName);
}
return false;
}
@Override
public int hashCode() {
return playerName.hashCode();
}
}
public static class Tile extends Update {
public String type = "tile";
public String name;
public Tile(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
if(o instanceof Tile) {
Tile m = (Tile)o;
return m.name.equals(name);
}
return false;
}
@Override
public int hashCode() {
return name.hashCode();
}
}
public static class DayNight extends Update {
public String type = "daynight";
public boolean isday;
public DayNight(boolean isday) {
this.isday = isday;
}
@Override
public boolean equals(Object o) {
if(o instanceof DayNight) {
return true;
}
return false;
}
@Override
public int hashCode() {
return 12345;
}
}
public static class ComponentMessage extends Update {
public String type = "component";
/* Each subclass must provide 'ctype' string for component 'type' */
}
public static String stripColor(String s) {
s = DynmapChatColor.stripColor(s); /* Strip standard color encoding */
/* Handle Essentials nickname encoding too */
int idx = 0;
while((idx = s.indexOf('&', idx)) >= 0) {
char c = s.charAt(idx+1); /* Get next character */
if(c == '&') { /* Another ampersand */
s = s.substring(0, idx) + s.substring(idx+1);
}
else {
s = s.substring(0, idx) + s.substring(idx+2);
}
idx++;
}
return s;
}
}

View file

@ -1,67 +0,0 @@
package org.dynmap;
import static org.dynmap.JSONUtils.a;
import static org.dynmap.JSONUtils.s;
import java.util.List;
import java.util.Map;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
public class ClientComponent extends Component {
private boolean disabled;
public ClientComponent(final DynmapCore plugin, final ConfigurationNode configuration) {
super(plugin, configuration);
plugin.events.addListener("buildclientconfiguration", new Event.Listener<JSONObject>() {
@Override
public void triggered(JSONObject root) {
if(!disabled)
buildClientConfiguration(root);
}
});
}
protected void disableComponent() {
disabled = true;
}
protected void buildClientConfiguration(JSONObject root) {
JSONObject o = createClientConfiguration();
a(root, "components", o);
}
protected JSONObject createClientConfiguration() {
JSONObject o = convertMap(configuration);
o.remove("class");
return o;
}
protected static final JSONObject convertMap(Map<String, ?> m) {
JSONObject o = new JSONObject();
for(Map.Entry<String, ?> entry : m.entrySet()) {
s(o, entry.getKey(), convert(entry.getValue()));
}
return o;
}
@SuppressWarnings("unchecked")
protected static final JSONArray convertList(List<?> l) {
JSONArray o = new JSONArray();
for(Object entry : l) {
o.add(convert(entry));
}
return o;
}
@SuppressWarnings("unchecked")
protected static final Object convert(Object o) {
if (o instanceof Map<?, ?>) {
return convertMap((Map<String, ?>)o);
} else if (o instanceof List<?>) {
return convertList((List<?>)o);
}
return o;
}
}

View file

@ -1,67 +0,0 @@
package org.dynmap;
import static org.dynmap.JSONUtils.a;
import static org.dynmap.JSONUtils.s;
import org.dynmap.Event.Listener;
import org.json.simple.JSONObject;
public class ClientConfigurationComponent extends Component {
public ClientConfigurationComponent(final DynmapCore core, ConfigurationNode configuration) {
super(core, configuration);
core.events.<JSONObject>addListener("buildclientconfiguration", new Listener<JSONObject>() {
@Override
public void triggered(JSONObject t) {
ConfigurationNode c = core.configuration;
s(t, "confighash", core.getConfigHashcode());
s(t, "updaterate", c.getFloat("updaterate", 1.0f));
s(t, "showplayerfacesinmenu", c.getBoolean("showplayerfacesinmenu", true));
s(t, "joinmessage", c.getString("joinmessage", "%playername% joined"));
s(t, "quitmessage", c.getString("quitmessage", "%playername% quit"));
s(t, "spammessage", c.getString("spammessage", "You may only chat once every %interval% seconds."));
s(t, "webprefix", unescapeString(c.getString("webprefix", "[WEB] ")));
s(t, "defaultzoom", c.getInteger("defaultzoom", 0));
s(t, "sidebaropened", c.getString("sidebaropened", "false"));
s(t, "dynmapversion", core.getDynmapCoreVersion());
s(t, "cyrillic", c.getBoolean("cyrillic-support", false));
s(t, "showlayercontrol", c.getString("showlayercontrol", "true"));
s(t, "grayplayerswhenhidden", c.getBoolean("grayplayerswhenhidden", true));
String sn = core.getServer().getServerName();
if(sn.equals("Unknown Server"))
sn = "Minecraft Dynamic Map";
s(t, "title", c.getString("webpage-title", sn));
s(t, "msg-maptypes", c.getString("msg/maptypes", "Map Types"));
s(t, "msg-players", c.getString("msg/players", "Players"));
DynmapWorld defaultWorld = null;
String defmap = null;
for(DynmapWorld world : core.mapManager.getWorlds()) {
if (defaultWorld == null) defaultWorld = world;
ConfigurationNode wn = world.configuration;
JSONObject wo = new JSONObject();
s(wo, "name", wn.getString("name"));
s(wo, "title", wn.getString("title"));
DynmapLocation spawn = world.getSpawnLocation();
s(wo, "center/x", wn.getDouble("center/x", spawn.x));
s(wo, "center/y", wn.getDouble("center/y", spawn.y));
s(wo, "center/z", wn.getDouble("center/z", spawn.z));
s(wo, "bigworld", world.bigworld);
s(wo, "extrazoomout", world.getExtraZoomOutLevels());
a(t, "worlds", wo);
for(MapType mt : world.maps) {
mt.buildClientConfiguration(wo, world);
if(defmap == null) defmap = mt.getName();
}
}
s(t, "defaultworld", c.getString("defaultworld", defaultWorld == null ? "world" : defaultWorld.getName()));
s(t, "defaultmap", c.getString("defaultmap", defmap == null ? "surface" : defmap));
if(c.getString("followmap", null) != null)
s(t, "followmap", c.getString("followmap"));
if(c.getInteger("followzoom",-1) >= 0)
s(t, "followzoom", c.getInteger("followzoom", 0));
}
});
}
}

View file

@ -1,118 +0,0 @@
package org.dynmap;
import static org.dynmap.JSONUtils.a;
import static org.dynmap.JSONUtils.s;
import java.util.List;
import org.dynmap.common.DynmapPlayer;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
public class ClientUpdateComponent extends Component {
public ClientUpdateComponent(final DynmapCore plugin, ConfigurationNode configuration) {
super(plugin, configuration);
plugin.events.addListener("buildclientupdate", new Event.Listener<ClientUpdateEvent>() {
@Override
public void triggered(ClientUpdateEvent e) {
buildClientUpdate(e);
}
});
}
protected void buildClientUpdate(ClientUpdateEvent e) {
DynmapWorld world = e.world;
JSONObject u = e.update;
long since = e.timestamp;
String worldName = world.getName();
int hideifshadow = configuration.getInteger("hideifshadow", 15);
int hideifunder = configuration.getInteger("hideifundercover", 15);
boolean hideifsneaking = configuration.getBoolean("hideifsneaking", false);
s(u, "confighash", core.getConfigHashcode());
s(u, "servertime", world.getTime() % 24000);
s(u, "hasStorm", world.hasStorm());
s(u, "isThundering", world.isThundering());
s(u, "players", new JSONArray());
List<DynmapPlayer> players = core.playerList.getVisiblePlayers();
for(DynmapPlayer p : players) {
DynmapLocation pl = p.getLocation();
DynmapWorld pw = core.getWorld(pl.world);
if(pw == null)
continue;
JSONObject jp = new JSONObject();
boolean hide = false;
s(jp, "type", "player");
s(jp, "name", Client.stripColor(p.getDisplayName()));
s(jp, "account", p.getName());
if(hideifshadow < 15) {
if(pw.getLightLevel((int)pl.x, (int)pl.y, (int)pl.z) <= hideifshadow)
hide = true;
}
if(hideifunder < 15) {
if(pw.canGetSkyLightLevel()) { /* If we can get real sky level */
if(pw.getSkyLightLevel((int)pl.x, (int)pl.y, (int)pl.z) <= hideifunder)
hide = true;
}
else {
if(pw.getHighestBlockYAt((int)pl.x, (int)pl.z) > pl.y)
hide = true;
}
}
if(hideifsneaking && p.isSneaking())
hide = true;
/* Don't leak player location for world not visible on maps, or if sendposition disbaled */
DynmapWorld pworld = MapManager.mapman.worldsLookup.get(pl.world);
/* Fix typo on 'sendpositon' to 'sendposition', keep bad one in case someone used it */
if(configuration.getBoolean("sendposition", true) && configuration.getBoolean("sendpositon", true) &&
(pworld != null) && pworld.sendposition && (!hide)) {
s(jp, "world", pl.world);
s(jp, "x", pl.x);
s(jp, "y", pl.y);
s(jp, "z", pl.z);
}
else {
s(jp, "world", "-some-other-bogus-world-");
s(jp, "x", 0.0);
s(jp, "y", 64.0);
s(jp, "z", 0.0);
}
/* Only send health if enabled AND we're on visible world */
if (configuration.getBoolean("sendhealth", false) && (pworld != null) && pworld.sendhealth && (!hide)) {
s(jp, "health", p.getHealth());
s(jp, "armor", p.getArmorPoints());
}
else {
s(jp, "health", 0);
s(jp, "armor", 0);
}
a(u, "players", jp);
}
if(configuration.getBoolean("includehiddenplayers", false)) {
List<DynmapPlayer> hidden = core.playerList.getHiddenPlayers();
for(DynmapPlayer p : hidden) {
JSONObject jp = new JSONObject();
s(jp, "type", "player");
s(jp, "name", Client.stripColor(p.getDisplayName()));
s(jp, "account", p.getName());
s(jp, "world", "-hidden-player-");
s(jp, "x", 0.0);
s(jp, "y", 64.0);
s(jp, "z", 0.0);
s(jp, "health", 0);
s(jp, "armor", 0);
a(u, "players", jp);
}
}
s(u, "updates", new JSONArray());
for(Object update : core.mapManager.getWorldUpdates(worldName, since)) {
a(u, "updates", (Client.Update)update);
}
}
}

View file

@ -1,15 +0,0 @@
package org.dynmap;
import org.json.simple.JSONObject;
public class ClientUpdateEvent {
public long timestamp;
public DynmapWorld world;
public JSONObject update;
public ClientUpdateEvent(long timestamp, DynmapWorld world, JSONObject update) {
this.timestamp = timestamp;
this.world = world;
this.update = update;
}
}

View file

@ -1,74 +0,0 @@
package org.dynmap;
/**
* Simple replacement for java.awt.Color for dynmap - it's not an invariant, so we don't make millions
* of them during rendering
*/
public class Color {
/* ARGB value */
private int val;
public static final int TRANSPARENT = 0;
public Color(int red, int green, int blue, int alpha) {
setRGBA(red, green, blue, alpha);
}
public Color(int red, int green, int blue) {
setRGBA(red, green, blue, 0xFF);
}
public Color() {
setTransparent();
}
public final int getRed() {
return (val >> 16) & 0xFF;
}
public final int getGreen() {
return (val >> 8) & 0xFF;
}
public final int getBlue() {
return val & 0xFF;
}
public final int getAlpha() {
return ((val >> 24) & 0xFF);
}
public final boolean isTransparent() {
return ((val & 0xFF000000) == TRANSPARENT);
}
public final void setTransparent() {
val = TRANSPARENT;
}
public final void setColor(Color c) {
val = c.val;
}
public final void setRGBA(int red, int green, int blue, int alpha) {
val = ((alpha & 0xFF) << 24) | ((red & 0xFF) << 16) | ((green & 0xFF) << 8) | (blue & 0xFF);
}
public final int getARGB() {
return val;
}
public final void setARGB(int c) {
val = c;
}
public final int getComponent(int idx) {
return 0xFF & (val >> ((3-idx)*8));
}
public final void setAlpha(int v) {
val = (val & 0x00FFFFFF) | (v << 24);
}
/**
* Scale each color component, based on the corresponding component
*/
public final void blendColor(Color c) {
blendColor(c.val);
}
/**
* Scale each color component, based on the corresponding component
*/
public final void blendColor(int argb) {
int nval = (((((val >> 24) & 0xFF) * ((argb >> 24) & 0xFF)) / 255) << 24);
nval = nval | (((((val >> 16) & 0xFF) * ((argb >> 16) & 0xFF)) / 255) << 16);
nval = nval | (((((val >> 8) & 0xFF) * ((argb >> 8) & 0xFF)) / 255) << 8);
nval = nval | (((val & 0xFF) * (argb & 0xFF)) / 255);
val = nval;
}
}

View file

@ -1,250 +0,0 @@
package org.dynmap;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Scanner;
import org.dynmap.common.BiomeMap;
import org.dynmap.debug.Debug;
public class ColorScheme {
private static final HashMap<String, ColorScheme> cache = new HashMap<String, ColorScheme>();
public String name;
/* Switch to arrays - faster than map */
public final Color[][] colors; /* [blk-type][step] */
public final Color[][][] datacolors; /* [bkt-type][blk-dat][step] */
public final Color[][] biomecolors; /* [Biome.ordinal][step] */
public final Color[][] raincolors; /* [rain * 63][step] */
public final Color[][] tempcolors; /* [temp * 63][step] */
public ColorScheme(String name, Color[][] colors, Color[][][] datacolors, Color[][] biomecolors, Color[][] raincolors, Color[][] tempcolors) {
this.name = name;
this.colors = colors;
this.datacolors = datacolors;
this.biomecolors = biomecolors;
this.raincolors = raincolors;
this.tempcolors = tempcolors;
if(MapManager.mapman.getHideOres()) {
for(int i = 0; i < colors.length; i++) {
int id = MapManager.mapman.getBlockIDAlias(i);
if(id != i) {
this.colors[i] = this.colors[id];
this.datacolors[i] = this.datacolors[id];
}
}
}
}
private static File getColorSchemeDirectory(DynmapCore core) {
return new File(core.getDataFolder(), "colorschemes");
}
public static ColorScheme getScheme(DynmapCore core, String name) {
if (name == null)
name = "default";
ColorScheme scheme = cache.get(name);
if (scheme == null) {
scheme = loadScheme(core, name);
cache.put(name, scheme);
}
return scheme;
}
public static ColorScheme loadScheme(DynmapCore core, String name) {
File colorSchemeFile = new File(getColorSchemeDirectory(core), name + ".txt");
Color[][] colors = new Color[256][];
Color[][][] datacolors = new Color[256][][];
Color[][] biomecolors = new Color[BiomeMap.values().length][];
Color[][] raincolors = new Color[64][];
Color[][] tempcolors = new Color[64][];
InputStream stream;
try {
Debug.debug("Loading colors from '" + colorSchemeFile + "'...");
stream = new FileInputStream(colorSchemeFile);
Scanner scanner = new Scanner(stream);
int nc = 0;
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
if (line.startsWith("#") || line.equals("")) {
continue;
}
/* Make parser less pedantic - tabs or spaces should be fine */
String[] split = line.split("[\t ]");
int cnt = 0;
for(String s: split) { if(s.length() > 0) cnt++; }
String[] nsplit = new String[cnt];
cnt = 0;
for(String s: split) { if(s.length() > 0) { nsplit[cnt] = s; cnt++; } }
split = nsplit;
if (split.length < 17) {
continue;
}
Integer id;
Integer dat = null;
boolean isbiome = false;
boolean istemp = false;
boolean israin = false;
int idx = split[0].indexOf(':');
if(idx > 0) { /* ID:data - data color */
id = new Integer(split[0].substring(0, idx));
dat = new Integer(split[0].substring(idx+1));
}
else if(split[0].charAt(0) == '[') { /* Biome color data */
String bio = split[0].substring(1);
idx = bio.indexOf(']');
if(idx >= 0) bio = bio.substring(0, idx);
isbiome = true;
id = -1;
for(BiomeMap b : BiomeMap.values()) {
if(b.toString().equalsIgnoreCase(bio)) {
id = b.ordinal();
break;
}
}
if(id < 0) { /* Not biome - check for rain or temp */
if(bio.startsWith("RAINFALL-")) {
try {
double v = Double.parseDouble(bio.substring(9));
if((v >= 0) && (v <= 1.00)) {
id = (int)(v * 63.0);
israin = true;
}
} catch (NumberFormatException nfx) {
}
}
else if(bio.startsWith("TEMPERATURE-")) {
try {
double v = Double.parseDouble(bio.substring(12));
if((v >= 0) && (v <= 1.00)) {
id = (int)(v * 63.0);
istemp = true;
}
} catch (NumberFormatException nfx) {
}
}
}
}
else {
id = new Integer(split[0]);
}
Color[] c = new Color[5];
/* store colors by raycast sequence number */
c[0] = new Color(Integer.parseInt(split[1]), Integer.parseInt(split[2]), Integer.parseInt(split[3]), Integer.parseInt(split[4]));
c[3] = new Color(Integer.parseInt(split[5]), Integer.parseInt(split[6]), Integer.parseInt(split[7]), Integer.parseInt(split[8]));
c[1] = new Color(Integer.parseInt(split[9]), Integer.parseInt(split[10]), Integer.parseInt(split[11]), Integer.parseInt(split[12]));
c[2] = new Color(Integer.parseInt(split[13]), Integer.parseInt(split[14]), Integer.parseInt(split[15]), Integer.parseInt(split[16]));
/* Blended color - for 'smooth' option on flat map */
c[4] = new Color((c[1].getRed()+c[3].getRed())/2, (c[1].getGreen()+c[3].getGreen())/2, (c[1].getBlue()+c[3].getBlue())/2, (c[1].getAlpha()+c[3].getAlpha())/2);
if(isbiome) {
if(istemp) {
tempcolors[id] = c;
}
else if(israin) {
raincolors[id] = c;
}
else if((id >= 0) && (id < biomecolors.length))
biomecolors[id] = c;
}
else if(dat != null) {
Color[][] dcolor = datacolors[id]; /* Existing list? */
if(dcolor == null) {
dcolor = new Color[16][]; /* Make 16 index long list */
datacolors[id] = dcolor;
}
if((dat >= 0) && (dat < 16)) { /* Add color to list */
dcolor[dat] = c;
}
if(dat == 0) { /* Index zero is base color too */
colors[id] = c;
}
}
else {
colors[id] = c;
}
nc += 1;
}
scanner.close();
/* Last, push base color into any open slots in data colors list */
for(int k = 0; k < 256; k++) {
Color[][] dc = datacolors[k]; /* see if data colors too */
if(dc != null) {
Color[] c = colors[k];
for(int i = 0; i < 16; i++) {
if(dc[i] == null)
dc[i] = c;
}
}
}
/* And interpolate any missing rain and temperature colors */
interpolateColorTable(tempcolors);
interpolateColorTable(raincolors);
} catch (RuntimeException e) {
Log.severe("Could not load colors '" + name + "' ('" + colorSchemeFile + "').", e);
return null;
} catch (FileNotFoundException e) {
Log.severe("Could not load colors '" + name + "' ('" + colorSchemeFile + "'): File not found.", e);
}
return new ColorScheme(name, colors, datacolors, biomecolors, raincolors, tempcolors);
}
public static void interpolateColorTable(Color[][] c) {
int idx = -1;
for(int k = 0; k < c.length; k++) {
if(c[k] == null) { /* Missing? */
if((idx >= 0) && (k == (c.length-1))) { /* We're last - so fill forward from last color */
for(int kk = idx+1; kk <= k; kk++) {
c[kk] = c[idx];
}
}
/* Skip - will backfill when we find next color */
}
else if(idx == -1) { /* No previous color, just backfill this color */
for(int kk = 0; kk < k; kk++) {
c[kk] = c[k];
}
idx = k; /* This is now last defined color */
}
else { /* Else, interpolate between last idx and this one */
int cnt = c[k].length;
for(int kk = idx+1; kk < k; kk++) {
double interp = (double)(kk-idx)/(double)(k-idx);
Color[] cc = new Color[cnt];
for(int jj = 0; jj < cnt; jj++) {
cc[jj] = new Color(
(int)((1.0-interp)*c[idx][jj].getRed() + interp*c[k][jj].getRed()),
(int)((1.0-interp)*c[idx][jj].getGreen() + interp*c[k][jj].getGreen()),
(int)((1.0-interp)*c[idx][jj].getBlue() + interp*c[k][jj].getBlue()),
(int)((1.0-interp)*c[idx][jj].getAlpha() + interp*c[k][jj].getAlpha()));
}
c[kk] = cc;
}
idx = k;
}
}
}
public Color[] getRainColor(double rain) {
int idx = (int)(rain * 63.0);
if((idx >= 0) && (idx < raincolors.length))
return raincolors[idx];
else
return null;
}
public Color[] getTempColor(double temp) {
int idx = (int)(temp * 63.0);
if((idx >= 0) && (idx < tempcolors.length))
return tempcolors[idx];
else
return null;
}
public static void reset() {
cache.clear();
}
}

View file

@ -1,21 +0,0 @@
package org.dynmap;
public abstract class Component {
protected DynmapCore core;
protected ConfigurationNode configuration;
public Component(DynmapCore core, ConfigurationNode configuration) {
this.core = core;
this.configuration = configuration;
}
public void dispose() {
}
/* Substitute proper values for escape sequences */
public static String unescapeString(String v) {
/* Replace color code &color; */
v = v.replace("&color;", "\u00A7");
return v;
}
}

View file

@ -1,47 +0,0 @@
package org.dynmap;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class ComponentManager {
public Set<Component> components = new HashSet<Component>();
public Map<String, List<Component>> componentLookup = new HashMap<String, List<Component>>();
public void add(Component c) {
if (components.add(c)) {
String key = c.getClass().toString();
List<Component> clist = componentLookup.get(key);
if (clist == null) {
clist = new ArrayList<Component>();
componentLookup.put(key, clist);
}
clist.add(c);
}
}
public void remove(Component c) {
if (components.remove(c)) {
String key = c.getClass().toString();
List<Component> clist = componentLookup.get(key);
if (clist != null) {
clist.remove(c);
}
}
}
public void clear() {
componentLookup.clear();
components.clear();
}
public Iterable<Component> getComponents(Class<Component> c) {
List<Component> list = componentLookup.get(c.toString());
if (list == null)
return new ArrayList<Component>();
return list;
}
}

View file

@ -1,426 +0,0 @@
package org.dynmap;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;
import org.yaml.snakeyaml.introspector.Property;
import org.yaml.snakeyaml.nodes.CollectionNode;
import org.yaml.snakeyaml.nodes.MappingNode;
import org.yaml.snakeyaml.nodes.Node;
import org.yaml.snakeyaml.nodes.NodeTuple;
import org.yaml.snakeyaml.nodes.SequenceNode;
import org.yaml.snakeyaml.nodes.Tag;
import org.yaml.snakeyaml.reader.UnicodeReader;
import org.yaml.snakeyaml.representer.Represent;
import org.yaml.snakeyaml.representer.Representer;
public class ConfigurationNode implements Map<String, Object> {
public Map<String, Object> entries;
private File f;
private Yaml yaml;
public ConfigurationNode() {
entries = new HashMap<String, Object>();
}
private void initparse() {
if(yaml == null) {
DumperOptions options = new DumperOptions();
options.setIndent(4);
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
yaml = new Yaml(new SafeConstructor(), new EmptyNullRepresenter(), options);
}
}
public ConfigurationNode(File f) {
this.f = f;
entries = new HashMap<String, Object>();
}
public ConfigurationNode(Map<String, Object> map) {
if (map == null) {
throw new IllegalArgumentException();
}
entries = map;
}
public ConfigurationNode(InputStream in) {
load(in);
}
@SuppressWarnings("unchecked")
public boolean load(InputStream in) {
initparse();
Object o = yaml.load(new UnicodeReader(in));
if((o != null) && (o instanceof Map))
entries = (Map<String, Object>)o;
return (entries != null);
}
@SuppressWarnings("unchecked")
public boolean load() {
initparse();
FileInputStream fis = null;
try {
fis = new FileInputStream(f);
Object o = yaml.load(new UnicodeReader(fis));
if((o != null) && (o instanceof Map))
entries = (Map<String, Object>)o;
fis.close();
} catch(IOException iox) {
Log.severe("Error reading " + f.getPath());
return false;
} finally {
if(fis != null) {
try { fis.close(); } catch (IOException x) {}
}
}
return (entries != null);
}
public boolean save() {
return save(f);
}
public boolean save(File file) {
initparse();
FileOutputStream stream = null;
File parent = file.getParentFile();
if (parent != null) {
parent.mkdirs();
}
try {
stream = new FileOutputStream(file);
OutputStreamWriter writer = new OutputStreamWriter(stream, "UTF-8");
yaml.dump(entries, writer);
return true;
} catch (IOException e) {
} finally {
try {
if (stream != null) {
stream.close();
}
} catch (IOException e) {}
}
return false;
}
@SuppressWarnings("unchecked")
public Object getObject(String path) {
if (path.isEmpty())
return entries;
int separator = path.indexOf('/');
if (separator < 0)
return get(path);
String localKey = path.substring(0, separator);
Object subvalue = get(localKey);
if (subvalue == null)
return null;
if (!(subvalue instanceof Map<?, ?>))
return null;
Map<String, Object> submap;
try {
submap = (Map<String, Object>)subvalue;
} catch (ClassCastException e) {
return null;
}
String subpath = path.substring(separator + 1);
return new ConfigurationNode(submap).getObject(subpath);
}
public Object getObject(String path, Object def) {
Object o = getObject(path);
if (o == null)
return def;
return o;
}
@SuppressWarnings("unchecked")
public <T> T getGeneric(String path, T def) {
Object o = getObject(path, def);
try {
return (T)o;
} catch(ClassCastException e) {
return def;
}
}
public int getInteger(String path, int def) {
return Integer.parseInt(getObject(path, def).toString());
}
public double getLong(String path, long def) {
return Long.parseLong(getObject(path, def).toString());
}
public float getFloat(String path, float def) {
return Float.parseFloat(getObject(path, def).toString());
}
public double getDouble(String path, double def) {
return Double.parseDouble(getObject(path, def).toString());
}
public boolean getBoolean(String path, boolean def) {
return Boolean.parseBoolean(getObject(path, def).toString());
}
public String getString(String path) {
return getString(path, null);
}
public List<String> getStrings(String path, List<String> def) {
Object o = getObject(path);
if (!(o instanceof List<?>)) {
return def;
}
ArrayList<String> strings = new ArrayList<String>();
for(Object i : (List<?>)o) {
strings.add(i.toString());
}
return strings;
}
public String getString(String path, String def) {
Object o = getObject(path, def);
if (o == null)
return null;
return o.toString();
}
@SuppressWarnings("unchecked")
public <T> List<T> getList(String path) {
try {
List<T> list = (List<T>)getObject(path, null);
return list;
} catch (ClassCastException e) {
try {
T o = (T)getObject(path, null);
if (o == null) {
return new ArrayList<T>();
}
ArrayList<T> al = new ArrayList<T>();
al.add(o);
return al;
} catch (ClassCastException e2) {
return new ArrayList<T>();
}
}
}
public List<Map<String,Object>> getMapList(String path) {
return getList(path);
}
public ConfigurationNode getNode(String path) {
Map<String, Object> v = null;
v = getGeneric(path, v);
if (v == null)
return null;
return new ConfigurationNode(v);
}
@SuppressWarnings("unchecked")
public List<ConfigurationNode> getNodes(String path) {
List<Object> o = getList(path);
if(o == null)
return new ArrayList<ConfigurationNode>();
ArrayList<ConfigurationNode> nodes = new ArrayList<ConfigurationNode>();
for(Object i : (List<?>)o) {
if (i instanceof Map<?, ?>) {
Map<String, Object> map;
try {
map = (Map<String, Object>)i;
} catch(ClassCastException e) {
continue;
}
nodes.add(new ConfigurationNode(map));
}
}
return nodes;
}
public void extend(Map<String, Object> other) {
if (other != null)
extendMap(this, other);
}
@SuppressWarnings("unchecked")
private final static void extendMap(Map<String, Object> left, Map<String, Object> right) {
ConfigurationNode original = new ConfigurationNode(left);
for(Map.Entry<String, Object> entry : right.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
if (value instanceof Map<?, ?>) {
ConfigurationNode subnode = original.getNode(key);
if (subnode == null) {
original.put(key, subnode = new ConfigurationNode());
}
extendMap(subnode, (Map<String, Object>)value);
} else {
original.put(key, value);
}
}
}
public <T> T createInstance(Class<?>[] constructorParameters, Object[] constructorArguments) {
String typeName = getString("class");
try {
Class<?> mapTypeClass = Class.forName(typeName);
Class<?>[] constructorParameterWithConfiguration = new Class<?>[constructorParameters.length+1];
for(int i = 0; i < constructorParameters.length; i++) { constructorParameterWithConfiguration[i] = constructorParameters[i]; }
constructorParameterWithConfiguration[constructorParameterWithConfiguration.length-1] = ConfigurationNode.class;
Object[] constructorArgumentsWithConfiguration = new Object[constructorArguments.length+1];
for(int i = 0; i < constructorArguments.length; i++) { constructorArgumentsWithConfiguration[i] = constructorArguments[i]; }
constructorArgumentsWithConfiguration[constructorArgumentsWithConfiguration.length-1] = this;
Constructor<?> constructor = mapTypeClass.getConstructor(constructorParameterWithConfiguration);
@SuppressWarnings("unchecked")
T t = (T)constructor.newInstance(constructorArgumentsWithConfiguration);
return t;
} catch (Exception e) {
// TODO: Remove reference to MapManager.
Log.severe("Error loading maptype", e);
e.printStackTrace();
}
return null;
}
public <T> List<T> createInstances(String path, Class<?>[] constructorParameters, Object[] constructorArguments) {
List<ConfigurationNode> nodes = getNodes(path);
List<T> instances = new ArrayList<T>();
for(ConfigurationNode node : nodes) {
T instance = node.<T>createInstance(constructorParameters, constructorArguments);
if (instance != null) {
instances.add(instance);
}
}
return instances;
}
@Override
public int size() {
return entries.size();
}
@Override
public boolean isEmpty() {
return entries.isEmpty();
}
@Override
public boolean containsKey(Object key) {
return entries.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return entries.containsValue(value);
}
@Override
public Object get(Object key) {
return entries.get(key);
}
@Override
public Object put(String key, Object value) {
return entries.put(key, value);
}
@Override
public Object remove(Object key) {
return entries.remove(key);
}
@Override
public void putAll(Map<? extends String, ? extends Object> m) {
entries.putAll(m);
}
@Override
public void clear() {
entries.clear();
}
@Override
public Set<String> keySet() {
return entries.keySet();
}
@Override
public Collection<Object> values() {
return entries.values();
}
@Override
public Set<java.util.Map.Entry<String, Object>> entrySet() {
return entries.entrySet();
}
private class EmptyNullRepresenter extends Representer {
public EmptyNullRepresenter() {
super();
this.nullRepresenter = new EmptyRepresentNull();
}
protected class EmptyRepresentNull implements Represent {
public Node representData(Object data) {
return representScalar(Tag.NULL, ""); // Changed "null" to "" so as to avoid writing nulls
}
}
// Code borrowed from snakeyaml (http://code.google.com/p/snakeyaml/source/browse/src/test/java/org/yaml/snakeyaml/issues/issue60/SkipBeanTest.java)
@Override
protected NodeTuple representJavaBeanProperty(Object javaBean, Property property, Object propertyValue, Tag customTag) {
NodeTuple tuple = super.representJavaBeanProperty(javaBean, property, propertyValue, customTag);
Node valueNode = tuple.getValueNode();
if (valueNode instanceof CollectionNode) {
// Removed null check
if (Tag.SEQ.equals(valueNode.getTag())) {
SequenceNode seq = (SequenceNode) valueNode;
if (seq.getValue().isEmpty()) {
return null; // skip empty lists
}
}
if (Tag.MAP.equals(valueNode.getTag())) {
MappingNode seq = (MappingNode) valueNode;
if (seq.getValue().isEmpty()) {
return null; // skip empty maps
}
}
}
return tuple;
}
// End of borrowed code
}
}

View file

@ -1,10 +0,0 @@
package org.dynmap;
public class DynmapChunk {
public int x, z;
public DynmapChunk(int x, int z) {
this.x = x;
this.z = z;
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,16 +0,0 @@
package org.dynmap;
/**
* Generic block location
*/
public class DynmapLocation {
public double x, y, z;
public String world;
public DynmapLocation() {}
public DynmapLocation(String w, double x, double y, double z) {
world = w;
this.x = x; this.y = y; this.z = z;
}
}

View file

@ -1,525 +0,0 @@
package org.dynmap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.dynmap.debug.Debug;
import org.dynmap.utils.DynmapBufferedImage;
import org.dynmap.utils.FileLockManager;
import org.dynmap.utils.MapChunkCache;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import javax.imageio.ImageIO;
public abstract class DynmapWorld {
public enum AutoGenerateOption {
NONE,
FORMAPONLY,
PERMANENT
}
public List<MapType> maps = new ArrayList<MapType>();
public UpdateQueue updates = new UpdateQueue();
public ConfigurationNode configuration;
public List<DynmapLocation> seedloc;
public List<MapChunkCache.VisibilityLimit> visibility_limits;
public List<MapChunkCache.VisibilityLimit> hidden_limits;
public AutoGenerateOption do_autogenerate;
public MapChunkCache.HiddenChunkStyle hiddenchunkstyle;
public int servertime;
public boolean sendposition;
public boolean sendhealth;
public boolean bigworld; /* If true, deeper directory hierarchy */
private int extrazoomoutlevels; /* Number of additional zoom out levels to generate */
public File worldtilepath;
private Object lock = new Object();
@SuppressWarnings("unchecked")
private HashSet<String> zoomoutupdates[] = new HashSet[0];
private boolean checkts = true; /* Check timestamps on first run with new configuration */
private boolean cancelled;
private String wname;
protected DynmapWorld(String wname) {
this.wname = wname;
}
@SuppressWarnings("unchecked")
public void setExtraZoomOutLevels(int lvl) {
extrazoomoutlevels = lvl;
zoomoutupdates = new HashSet[lvl];
for(int i = 0; i < lvl; i++)
zoomoutupdates[i] = new HashSet<String>();
checkts = true;
}
public int getExtraZoomOutLevels() { return extrazoomoutlevels; }
public void enqueueZoomOutUpdate(File f) {
enqueueZoomOutUpdate(f, 0);
}
private void enqueueZoomOutUpdate(File f, int level) {
synchronized(lock) {
if(level >= zoomoutupdates.length) {
@SuppressWarnings("unchecked")
HashSet<String> new_zoomout[] = new HashSet[level+1];
System.arraycopy(zoomoutupdates, 0, new_zoomout, 0, zoomoutupdates.length);
for(int i = 0; i < new_zoomout.length; i++) {
if(i < zoomoutupdates.length)
new_zoomout[i] = zoomoutupdates[i];
else
new_zoomout[i] = new HashSet<String>();
}
zoomoutupdates = new_zoomout;
}
zoomoutupdates[level].add(f.getPath());
}
}
private boolean popQueuedUpdate(File f, int level) {
if(level >= zoomoutupdates.length)
return false;
synchronized(lock) {
return zoomoutupdates[level].remove(f.getPath());
}
}
private String[] peekQueuedUpdates(int level) {
if(level >= zoomoutupdates.length)
return new String[0];
synchronized(lock) {
return zoomoutupdates[level].toArray(new String[zoomoutupdates[level].size()]);
}
}
private static class DirFilter implements FilenameFilter {
public boolean accept(File f, String n) {
if(!n.equals("..") && !n.equals(".")) {
File fn = new File(f, n);
return fn.isDirectory();
}
return false;
}
}
private static final String COORDSTART = "-0123456789";
private static class PNGFileFilter implements FilenameFilter {
String prefix;
String suffix;
public PNGFileFilter(String pre, MapType.ImageFormat fmt) {
if((pre != null) && (pre.length() > 0))
prefix = pre;
suffix = "." + fmt.getFileExt();
}
public boolean accept(File f, String n) {
if(n.endsWith(suffix)) {
if((prefix != null) && (!n.startsWith(prefix)))
return false;
if((prefix == null) && (COORDSTART.indexOf(n.charAt(0)) < 0))
return false;
File fn = new File(f, n);
return fn.isFile();
}
return false;
}
}
public void freshenZoomOutFiles() {
boolean done = false;
int last_done = 0;
for(int i = 0; (!cancelled) && (!done); i++) {
done = freshenZoomOutFilesByLevel(i);
last_done = i;
}
/* Purge updates for levels above what any map needs */
for(int i = last_done; i < zoomoutupdates.length; i++) {
zoomoutupdates[i].clear();
}
checkts = false; /* Just handle queued updates after first scan */
}
public void cancelZoomOutFreshen() {
cancelled = true;
}
private static class PrefixData {
int stepsize;
int[] stepseq;
boolean neg_step_x;
boolean neg_step_y;
String baseprefix;
int zoomlevel;
int background;
String zoomprefix;
String fnprefix;
String zfnprefix;
int bigworldshift;
boolean isbigmap;
MapType.ImageFormat fmt;
}
public boolean freshenZoomOutFilesByLevel(int zoomlevel) {
int cnt = 0;
Debug.debug("freshenZoomOutFiles(" + wname + "," + zoomlevel + ")");
if(worldtilepath.exists() == false) /* Quit if not found */
return true;
HashMap<String, PrefixData> maptab = buildPrefixData(zoomlevel);
if(checkts) { /* If doing timestamp based scan (initial) */
DirFilter df = new DirFilter();
for(String pfx : maptab.keySet()) { /* Walk through prefixes */
if(cancelled) return true;
PrefixData pd = maptab.get(pfx);
if(pd.isbigmap) { /* If big world, next directories are map name specific */
File dname = new File(worldtilepath, pfx);
/* Now, go through subdirectories under this one, and process them */
String[] subdir = dname.list(df);
if(subdir == null) continue;
for(String s : subdir) {
if(cancelled) return true;
File sdname = new File(dname, s);
cnt += processZoomDirectory(sdname, pd);
}
}
else { /* Else, classic file layout */
cnt += processZoomDirectory(worldtilepath, maptab.get(pfx));
}
}
Debug.debug("freshenZoomOutFiles(" + wname + "," + zoomlevel + ") - done (" + cnt + " updated files)");
}
else { /* Else, only process updates */
String[] paths = peekQueuedUpdates(zoomlevel); /* Get pending updates */
HashMap<String, ProcessTileRec> toprocess = new HashMap<String, ProcessTileRec>();
/* Accumulate zoomed tiles to be processed (combine triggering subtiles) */
for(String p : paths) {
if(cancelled) return true;
File f = new File(p); /* Make file */
/* Find matching prefix */
for(PrefixData pd : maptab.values()) { /* Walk through prefixes */
if(cancelled) return true;
ProcessTileRec tr = null;
/* If big map and matches name pattern */
if(pd.isbigmap && f.getName().startsWith(pd.fnprefix) &&
f.getParentFile().getParentFile().getName().equals(pd.baseprefix)) {
tr = processZoomFile(f, pd);
}
/* If not big map and matches name pattern */
else if((!pd.isbigmap) && f.getName().startsWith(pd.fnprefix)) {
tr = processZoomFile(f, pd);
}
if(tr != null) {
String zfpath = tr.zf.getPath();
if(!toprocess.containsKey(zfpath)) {
toprocess.put(zfpath, tr);
}
}
}
}
/* Do processing */
for(ProcessTileRec s : toprocess.values()) {
if(cancelled) return true;
processZoomTile(s.pd, s.zf, s.zfname, s.x, s.y);
}
}
/* Return true when we have none left at the level */
return (maptab.size() == 0);
}
private HashMap<String, PrefixData> buildPrefixData(int zoomlevel) {
HashMap<String, PrefixData> maptab = new HashMap<String, PrefixData>();
/* Build table of file prefixes and step sizes */
for(MapType mt : maps) {
/* If level is above top needed for this map, skip */
if(zoomlevel > (this.extrazoomoutlevels + mt.getMapZoomOutLevels()))
continue;
List<MapType.ZoomInfo> pfx = mt.baseZoomFileInfo();
int stepsize = mt.baseZoomFileStepSize();
int bigworldshift = mt.getBigWorldShift();
boolean neg_step_x = false;
boolean neg_step_y = false;
switch(mt.zoomFileMapStep()) {
case X_PLUS_Y_PLUS:
break;
case X_MINUS_Y_PLUS:
neg_step_x = true;
break;
case X_PLUS_Y_MINUS:
neg_step_y = true;
break;
case X_MINUS_Y_MINUS:
neg_step_x = neg_step_y = true;
break;
}
int[] stepseq = mt.zoomFileStepSequence();
for(MapType.ZoomInfo p : pfx) {
PrefixData pd = new PrefixData();
pd.stepsize = stepsize;
pd.neg_step_x = neg_step_x;
pd.neg_step_y = neg_step_y;
pd.stepseq = stepseq;
pd.baseprefix = p.prefix;
pd.background = p.background_argb;
pd.zoomlevel = zoomlevel;
pd.zoomprefix = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz".substring(0, zoomlevel);
pd.bigworldshift = bigworldshift;
pd.isbigmap = mt.isBigWorldMap(this);
pd.fmt = mt.getImageFormat();
if(pd.isbigmap) {
if(zoomlevel > 0) {
pd.zoomprefix += "_";
pd.zfnprefix = "z" + pd.zoomprefix;
}
else {
pd.zfnprefix = "z_";
}
pd.fnprefix = pd.zoomprefix;
}
else {
pd.fnprefix = pd.zoomprefix + pd.baseprefix;
pd.zfnprefix = "z" + pd.fnprefix;
}
maptab.put(p.prefix, pd);
}
}
return maptab;
}
private static class ProcessTileRec {
File zf;
String zfname;
int x, y;
PrefixData pd;
}
private String makeFilePath(PrefixData pd, int x, int y, boolean zoomed) {
if(pd.isbigmap)
return pd.baseprefix + "/" + (x >> pd.bigworldshift) + "_" + (y >> pd.bigworldshift) + "/" + (zoomed?pd.zfnprefix:pd.fnprefix) + x + "_" + y + "." + pd.fmt.getFileExt();
else
return (zoomed?pd.zfnprefix:pd.fnprefix) + "_" + x + "_" + y + "." + pd.fmt.getFileExt();
}
private int processZoomDirectory(File dir, PrefixData pd) {
Debug.debug("processZoomDirectory(" + dir.getPath() + "," + pd.baseprefix + ")");
HashMap<String, ProcessTileRec> toprocess = new HashMap<String, ProcessTileRec>();
String[] files = dir.list(new PNGFileFilter(pd.fnprefix, pd.fmt));
if(files == null)
return 0;
for(String fn : files) {
ProcessTileRec tr = processZoomFile(new File(dir, fn), pd);
if(tr != null) {
String zfpath = tr.zf.getPath();
if(!toprocess.containsKey(zfpath)) {
toprocess.put(zfpath, tr);
}
}
}
int cnt = 0;
/* Do processing */
for(ProcessTileRec s : toprocess.values()) {
processZoomTile(s.pd, s.zf, s.zfname, s.x, s.y);
cnt++;
}
Debug.debug("processZoomDirectory(" + dir.getPath() + "," + pd.baseprefix + ") - done (" + cnt + " files)");
return cnt;
}
private ProcessTileRec processZoomFile(File f, PrefixData pd) {
/* If not checking timstamp, we're out if nothing queued for this file */
if(!checkts) {
if(!popQueuedUpdate(f, pd.zoomlevel))
return null;
}
int step = pd.stepsize << pd.zoomlevel;
String fn = f.getName();
/* Parse filename to predict zoomed out file */
fn = fn.substring(0, fn.lastIndexOf('.')); /* Strip off extension */
String[] tok = fn.split("_"); /* Split by underscores */
int x = 0;
int y = 0;
boolean parsed = false;
if(tok.length >= 2) {
try {
x = Integer.parseInt(tok[tok.length-2]);
y = Integer.parseInt(tok[tok.length-1]);
parsed = true;
} catch (NumberFormatException nfx) {
}
}
if(!parsed)
return null;
if(pd.neg_step_x) x = -x;
if(x >= 0)
x = x - (x % (2*step));
else
x = x + (x % (2*step));
if(pd.neg_step_x) x = -x;
if(pd.neg_step_y) y = -y;
if(y >= 0)
y = y - (y % (2*step));
else
y = y + (y % (2*step));
if(pd.neg_step_y) y = -y;
/* Make name of corresponding zoomed tile */
String zfname = makeFilePath(pd, x, y, true);
File zf = new File(worldtilepath, zfname);
if(checkts) { /* If checking timestamp, see if we need update based on enqueued update OR old file time */
/* If we're not updated, and zoom file exists and is older than our file, nothing to do */
if((!popQueuedUpdate(f, pd.zoomlevel)) && zf.exists() && (zf.lastModified() >= f.lastModified())) {
return null;
}
}
ProcessTileRec rec = new ProcessTileRec();
rec.zf = zf;
rec.x = x;
rec.y = y;
rec.zfname = zfname;
rec.pd = pd;
Debug.debug("Process " + zf.getPath() + " due to " + f.getPath());
return rec;
}
private void processZoomTile(PrefixData pd, File zf, String zfname, int tx, int ty) {
Debug.debug("processZoomFile(" + pd.baseprefix + "," + zf.getPath() + "," + tx + "," + ty + ")");
int width = 128, height = 128;
BufferedImage zIm = null;
DynmapBufferedImage kzIm = null;
boolean blank = true;
int[] argb = new int[width*height];
int step = pd.stepsize << pd.zoomlevel;
int ztx = tx;
int zty = ty;
tx = tx - (pd.neg_step_x?step:0); /* Adjust for negative step */
ty = ty - (pd.neg_step_y?step:0); /* Adjust for negative step */
/* create image buffer */
kzIm = DynmapBufferedImage.allocateBufferedImage(width, height);
zIm = kzIm.buf_img;
for(int i = 0; i < 4; i++) {
File f = new File(worldtilepath, makeFilePath(pd, (tx + step*(1&pd.stepseq[i])), (ty + step*(pd.stepseq[i]>>1)), false));
if(f.exists()) {
BufferedImage im = null;
FileLockManager.getReadLock(f);
popQueuedUpdate(f, pd.zoomlevel);
try {
im = ImageIO.read(f);
} catch (IOException e) {
} catch (IndexOutOfBoundsException e) {
} finally {
FileLockManager.releaseReadLock(f);
}
if(im != null) {
im.getRGB(0, 0, width, height, argb, 0, width); /* Read data */
im.flush();
blank = false;
/* Do binlinear scale to 64x64 */
int off = 0;
for(int y = 0; y < height; y += 2) {
off = y*width;
for(int x = 0; x < width; x += 2, off += 2) {
int p0 = argb[off];
int p1 = argb[off+1];
int p2 = argb[off+width];
int p3 = argb[off+width+1];
int alpha = ((p0 >> 24) & 0xFF) + ((p1 >> 24) & 0xFF) + ((p2 >> 24) & 0xFF) + ((p3 >> 24) & 0xFF);
int red = ((p0 >> 16) & 0xFF) + ((p1 >> 16) & 0xFF) + ((p2 >> 16) & 0xFF) + ((p3 >> 16) & 0xFF);
int green = ((p0 >> 8) & 0xFF) + ((p1 >> 8) & 0xFF) + ((p2 >> 8) & 0xFF) + ((p3 >> 8) & 0xFF);
int blue = (p0 & 0xFF) + (p1 & 0xFF) + (p2 & 0xFF) + (p3 & 0xFF);
argb[off>>1] = (((alpha>>2)&0xFF)<<24) | (((red>>2)&0xFF)<<16) | (((green>>2)&0xFF)<<8) | ((blue>>2)&0xFF);
}
}
/* blit scaled rendered tile onto zoom-out tile */
zIm.setRGB(((i>>1) != 0)?0:width/2, (i & 1) * height/2, width/2, height/2, argb, 0, width);
}
else {
Arrays.fill(argb, pd.background);
}
}
else {
Arrays.fill(argb, pd.background);
}
/* blit scaled rendered tile onto zoom-out tile */
zIm.setRGB(((i>>1) != 0)?0:width/2, (i & 1) * height/2, width/2, height/2, argb, 0, width);
}
FileLockManager.getWriteLock(zf);
try {
MapManager mm = MapManager.mapman;
if(mm == null)
return;
TileHashManager hashman = mm.hashman;
long crc = hashman.calculateTileHash(kzIm.argb_buf); /* Get hash of tile */
int tilex = ztx/step/2;
int tiley = zty/step/2;
String key = wname+".z"+pd.zoomprefix+pd.baseprefix;
if(blank) {
if(zf.exists()) {
zf.delete();
hashman.updateHashCode(key, null, tilex, tiley, -1);
MapManager.mapman.pushUpdate(this, new Client.Tile(zfname));
enqueueZoomOutUpdate(zf, pd.zoomlevel+1);
}
}
else if((!zf.exists()) || (crc != mm.hashman.getImageHashCode(key, null, tilex, tiley))) {
try {
if(!zf.getParentFile().exists())
zf.getParentFile().mkdirs();
FileLockManager.imageIOWrite(zIm, pd.fmt, zf);
Debug.debug("Saved zoom-out tile at " + zf.getPath());
} catch (IOException e) {
Debug.error("Failed to save zoom-out tile: " + zf.getName(), e);
} catch (java.lang.NullPointerException e) {
Debug.error("Failed to save zoom-out tile (NullPointerException): " + zf.getName(), e);
}
hashman.updateHashCode(key, null, tilex, tiley, crc);
MapManager.mapman.pushUpdate(this, new Client.Tile(zfname));
enqueueZoomOutUpdate(zf, pd.zoomlevel+1);
}
} finally {
FileLockManager.releaseWriteLock(zf);
DynmapBufferedImage.freeBufferedImage(kzIm);
}
}
/* Get world name */
public String getName() {
return wname;
}
/* Test if world is nether */
public abstract boolean isNether();
/* Get world spawn location */
public abstract DynmapLocation getSpawnLocation();
public int hashCode() {
return wname.hashCode();
}
/* Get world time */
public abstract long getTime();
/* World is storming */
public abstract boolean hasStorm();
/* World is thundering */
public abstract boolean isThundering();
/* World is loaded */
public abstract boolean isLoaded();
/* Get light level of block */
public abstract int getLightLevel(int x, int y, int z);
/* Get highest Y coord of given location */
public abstract int getHighestBlockYAt(int x, int z);
/* Test if sky light level is requestable */
public abstract boolean canGetSkyLightLevel();
/* Return sky light level */
public abstract int getSkyLightLevel(int x, int y, int z);
/**
* Get world environment ID (lower case - normal, the_end, nether)
*/
public abstract String getEnvironment();
/**
* Get map chunk cache for world
*/
public abstract MapChunkCache getChunkCache(List<DynmapChunk> chunks);
}

View file

@ -1,36 +0,0 @@
package org.dynmap;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class Event<T> {
private List<Listener<T>> listeners = new LinkedList<Listener<T>>();
private Object lock = new Object();
public void addListener(Listener<T> l) {
synchronized(lock) {
listeners.add(l);
}
}
public void removeListener(Listener<T> l) {
synchronized(lock) {
listeners.remove(l);
}
}
public void trigger(T t) {
ArrayList<Listener<T>> iterlist;
synchronized(lock) {
iterlist = new ArrayList<Listener<T>>(listeners);
}
for (Listener<T> l : iterlist) {
l.triggered(t);
}
}
public interface Listener<T> {
void triggered(T t);
}
}

View file

@ -1,37 +0,0 @@
package org.dynmap;
import java.util.HashMap;
import java.util.Map;
public class Events {
public Map<String, Event<?>> events = new HashMap<String, Event<?>>();
@SuppressWarnings("unchecked")
public <T> void addListener(String eventName, Event.Listener<T> listener) {
Event<?> genericEvent = events.get(eventName);
Event<T> event = null;
if (genericEvent != null) {
event = (Event<T>)genericEvent;
} else {
events.put(eventName, event = new Event<T>());
}
event.addListener(listener);
}
@SuppressWarnings("unchecked")
public <T> void removeListener(String eventName, Event.Listener<T> listener) {
Event<?> genericEvent = events.get(eventName);
Event<T> event = null;
if (genericEvent != null) {
event = (Event<T>)genericEvent;
event.removeListener(listener);
}
}
@SuppressWarnings("unchecked")
public <T> void trigger(String eventName, T argument) {
Event<?> genericEvent = events.get(eventName);
if (genericEvent == null)
return;
((Event<T>)genericEvent).trigger(argument);
}
}

View file

@ -1,5 +0,0 @@
package org.dynmap;
public interface Handler<T> {
void handle(T t);
}

View file

@ -1,63 +0,0 @@
package org.dynmap;
import org.dynmap.servlet.ClientUpdateServlet;
import org.dynmap.servlet.SendMessageServlet;
import org.json.simple.JSONObject;
import static org.dynmap.JSONUtils.*;
public class InternalClientUpdateComponent extends ClientUpdateComponent {
public InternalClientUpdateComponent(final DynmapCore dcore, final ConfigurationNode configuration) {
super(dcore, configuration);
dcore.addServlet("/up/world/*", new ClientUpdateServlet(dcore));
final Boolean allowwebchat = configuration.getBoolean("allowwebchat", false);
final Boolean hidewebchatip = configuration.getBoolean("hidewebchatip", false);
final Boolean trust_client_name = configuration.getBoolean("trustclientname", false);
final float webchatInterval = configuration.getFloat("webchat-interval", 1);
final String spammessage = dcore.configuration.getString("spammessage", "You may only chat once every %interval% seconds.");
final Boolean use_player_ip = configuration.getBoolean("use-player-login-ip", true);
final Boolean req_player_ip = configuration.getBoolean("require-player-login-ip", false);
final Boolean block_banned_player_chat = configuration.getBoolean("block-banned-player-chat", false);
dcore.events.addListener("buildclientconfiguration", new Event.Listener<JSONObject>() {
@Override
public void triggered(JSONObject t) {
s(t, "allowwebchat", allowwebchat);
s(t, "webchat-interval", webchatInterval);
}
});
if (allowwebchat) {
@SuppressWarnings("serial")
SendMessageServlet messageHandler = new SendMessageServlet() {{
maximumMessageInterval = (int)(webchatInterval * 1000);
spamMessage = "\""+spammessage+"\"";
hideip = hidewebchatip;
this.trustclientname = trust_client_name;
this.use_player_login_ip = use_player_ip;
this.require_player_login_ip = req_player_ip;
this.check_user_ban = block_banned_player_chat;
this.core = dcore;
onMessageReceived.addListener(new Event.Listener<Message> () {
@Override
public void triggered(Message t) {
webChat(t.name, t.message);
}
});
}};
dcore.addServlet("/up/sendmessage", messageHandler);
}
}
protected void webChat(String name, String message) {
if(core.mapManager == null)
return;
// TODO: Change null to something meaningful.
core.mapManager.pushUpdate(new Client.ChatMessage("web", null, name, message, null));
Log.info(unescapeString(core.configuration.getString("webprefix", "\u00A72[WEB] ")) + name + ": " + unescapeString(core.configuration.getString("websuffix", "\u00A7f")) + message);
ChatEvent event = new ChatEvent("web", name, message);
core.events.trigger("webchat", event);
}
}

View file

@ -1,71 +0,0 @@
package org.dynmap;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
public class JSONUtils {
// Gets a value at the specified path.
public static Object g(JSONObject o, String path) {
int index = path.indexOf('/');
if (index == -1) {
return o.get(path);
} else {
String key = path.substring(0, index);
String subpath = path.substring(index+1);
Object oo = o.get(key);
JSONObject subobject;
if (oo == null) {
return null;
} else /*if (oo instanceof JSONObject)*/ {
subobject = (JSONObject)o;
}
return g(subobject, subpath);
}
}
// Sets a value on the specified path. If JSONObjects inside the path are missing, they'll be created.
@SuppressWarnings("unchecked")
public static void s(JSONObject o, String path, Object value) {
int index = path.indexOf('/');
if (index == -1) {
o.put(path, value);
} else {
String key = path.substring(0, index);
String subpath = path.substring(index+1);
Object oo = o.get(key);
JSONObject subobject;
if (oo == null) {
subobject = new JSONObject();
o.put(key, subobject);
} else /*if (oo instanceof JSONObject)*/ {
subobject = (JSONObject)oo;
}
s(subobject, subpath, value);
}
}
// Adds a value to the list at the specified path. If the list does not exist, it will be created.
@SuppressWarnings("unchecked")
public static void a(JSONObject o, String path, Object value) {
Object oo = g(o, path);
JSONArray array;
if (oo == null) {
array =new JSONArray();
s(o, path, array);
} else {
array = (JSONArray)oo;
}
array.add(value);
}
// Simply creates a JSONArray.
@SuppressWarnings("unchecked")
public static JSONArray l(Object... items) {
JSONArray arr = new JSONArray();
for(Object item : items) {
arr.add(item);
}
return arr;
}
}

View file

@ -1,271 +0,0 @@
package org.dynmap;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.FileInputStream;
import java.io.Reader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import org.dynmap.web.Json;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import static org.dynmap.JSONUtils.*;
import java.nio.charset.Charset;
public class JsonFileClientUpdateComponent extends ClientUpdateComponent {
protected long jsonInterval;
protected long currentTimestamp = 0;
protected long lastTimestamp = 0;
protected JSONParser parser = new JSONParser();
private boolean hidewebchatip;
private boolean useplayerloginip;
private boolean requireplayerloginip;
private boolean trust_client_name;
private boolean checkuserban;
private HashMap<String,String> useralias = new HashMap<String,String>();
private int aliasindex = 1;
private long last_confighash;
private Charset cs_utf8 = Charset.forName("UTF-8");
public JsonFileClientUpdateComponent(final DynmapCore plugin, final ConfigurationNode configuration) {
super(plugin, configuration);
final boolean allowwebchat = configuration.getBoolean("allowwebchat", false);
jsonInterval = (long)(configuration.getFloat("writeinterval", 1) * 1000);
hidewebchatip = configuration.getBoolean("hidewebchatip", false);
useplayerloginip = configuration.getBoolean("use-player-login-ip", true);
requireplayerloginip = configuration.getBoolean("require-player-login-ip", false);
trust_client_name = configuration.getBoolean("trustclientname", false);
checkuserban = configuration.getBoolean("block-banned-player-chat", true);
MapManager.scheduleDelayedJob(new Runnable() {
@Override
public void run() {
currentTimestamp = System.currentTimeMillis();
if(last_confighash != plugin.getConfigHashcode())
writeConfiguration();
writeUpdates();
if (allowwebchat) {
handleWebChat();
}
lastTimestamp = currentTimestamp;
MapManager.scheduleDelayedJob(this, jsonInterval);
}}, jsonInterval);
plugin.events.addListener("buildclientconfiguration", new Event.Listener<JSONObject>() {
@Override
public void triggered(JSONObject t) {
s(t, "jsonfile", true);
s(t, "allowwebchat", allowwebchat);
// For 'sendmessage.php'
s(t, "webchat-interval", configuration.getFloat("webchat-interval", 5.0f));
}
});
plugin.events.addListener("initialized", new Event.Listener<Object>() {
@Override
public void triggered(Object t) {
writeConfiguration();
}
});
plugin.events.addListener("worldactivated", new Event.Listener<DynmapWorld>() {
@Override
public void triggered(DynmapWorld t) {
writeConfiguration();
}
});
}
protected File getStandaloneFile(String filename) {
File webpath = new File(core.configuration.getString("webpath", "web"), "standalone/" + filename);
if (webpath.isAbsolute())
return webpath;
else
return new File(core.getDataFolder(), webpath.toString());
}
private static final int RETRY_LIMIT = 5;
protected void writeConfiguration() {
File outputFile;
File outputTempFile;
JSONObject clientConfiguration = new JSONObject();
core.events.trigger("buildclientconfiguration", clientConfiguration);
outputFile = getStandaloneFile("dynmap_config.json");
outputTempFile = getStandaloneFile("dynmap_config.json.new");
last_confighash = core.getConfigHashcode();
int retrycnt = 0;
boolean done = false;
while(!done) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(outputTempFile);
fos.write(clientConfiguration.toJSONString().getBytes("UTF-8"));
fos.close();
fos = null;
outputFile.delete();
outputTempFile.renameTo(outputFile);
done = true;
} catch (IOException ioe) {
if(retrycnt < RETRY_LIMIT) {
try { Thread.sleep(20 * (1 << retrycnt)); } catch (InterruptedException ix) {}
retrycnt++;
}
else {
Log.severe("Exception while writing JSON-configuration-file.", ioe);
done = true;
}
} finally {
if(fos != null) {
try {
fos.close();
} catch (IOException iox) {
}
fos = null;
}
}
}
}
@SuppressWarnings("unchecked")
protected void writeUpdates() {
File outputFile;
File outputTempFile;
if(core.mapManager == null) return;
//Handles Updates
for (DynmapWorld dynmapWorld : core.mapManager.getWorlds()) {
JSONObject update = new JSONObject();
update.put("timestamp", currentTimestamp);
ClientUpdateEvent clientUpdate = new ClientUpdateEvent(currentTimestamp - 30000, dynmapWorld, update);
core.events.trigger("buildclientupdate", clientUpdate);
outputFile = getStandaloneFile("dynmap_" + dynmapWorld.getName() + ".json");
outputTempFile = getStandaloneFile("dynmap_" + dynmapWorld.getName() + ".json.new");
int retrycnt = 0;
boolean done = false;
while(!done) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(outputTempFile);
fos.write(Json.stringifyJson(update).getBytes("UTF-8"));
fos.close();
fos = null;
outputFile.delete();
outputTempFile.renameTo(outputFile);
done = true;
} catch (IOException ioe) {
if(retrycnt < RETRY_LIMIT) {
try { Thread.sleep(20 * (1 << retrycnt)); } catch (InterruptedException ix) {}
retrycnt++;
}
else {
Log.severe("Exception while writing JSON-file.", ioe);
done = true;
}
} finally {
if(fos != null) {
try {
fos.close();
} catch (IOException iox) {
}
fos = null;
}
}
}
core.events.<ClientUpdateEvent>trigger("clientupdatewritten", clientUpdate);
}
core.events.<Object>trigger("clientupdateswritten", null);
}
protected void handleWebChat() {
File webchatFile = getStandaloneFile("dynmap_webchat.json");
if (webchatFile.exists() && lastTimestamp != 0) {
JSONArray jsonMsgs = null;
Reader inputFileReader = null;
try {
inputFileReader = new InputStreamReader(new FileInputStream(webchatFile), cs_utf8);
jsonMsgs = (JSONArray) parser.parse(inputFileReader);
} catch (IOException ex) {
Log.severe("Exception while reading JSON-file.", ex);
} catch (ParseException ex) {
Log.severe("Exception while parsing JSON-file.", ex);
} finally {
if(inputFileReader != null) {
try {
inputFileReader.close();
} catch (IOException iox) {
}
inputFileReader = null;
}
}
if (jsonMsgs != null) {
Iterator<?> iter = jsonMsgs.iterator();
while (iter.hasNext()) {
JSONObject o = (JSONObject) iter.next();
String ts = String.valueOf(o.get("timestamp"));
if(ts.equals("null")) ts = "0";
if (Long.parseLong(ts) >= (lastTimestamp)) {
String name = String.valueOf(o.get("name"));
String ip = String.valueOf(o.get("ip"));
boolean isip = true;
if((!trust_client_name) || (name == null) || (name.equals(""))) {
if(ip != null)
name = ip;
}
if(useplayerloginip) { /* Try to match using IPs of player logins */
List<String> ids = core.getIDsForIP(name);
if(ids != null) {
name = ids.get(0);
isip = false;
if(checkuserban) {
if(core.getServer().isPlayerBanned(name)) {
Log.info("Ignore message from '" + ip + "' - banned player (" + name + ")");
return;
}
}
}
else if(requireplayerloginip) {
Log.info("Ignore message from '" + name + "' - no matching player login recorded");
return;
}
}
if(hidewebchatip && isip) {
String n = useralias.get(name);
if(n == null) { /* Make ID */
n = String.format("web-%03d", aliasindex);
aliasindex++;
useralias.put(name, n);
}
name = n;
}
String message = String.valueOf(o.get("message"));
webChat(name, message);
}
}
}
}
}
protected void webChat(String name, String message) {
if(core.mapManager == null) return;
// TODO: Change null to something meaningful.
core.mapManager.pushUpdate(new Client.ChatMessage("web", null, name, message, null));
Log.info(unescapeString(core.configuration.getString("webprefix", "\u00A2[WEB] ")) + name + ": " + unescapeString(core.configuration.getString("websuffix", "\u00A7f")) + message);
ChatEvent event = new ChatEvent("web", name, message);
core.events.trigger("webchat", event);
}
@Override
public void dispose() {
super.dispose();
}
}

View file

@ -1,32 +0,0 @@
package org.dynmap;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Log {
protected static final Logger log = Logger.getLogger("Minecraft");
protected static final String LOG_PREFIX = "[dynmap] ";
public static boolean verbose = false;
public static void info(String msg) {
log.log(Level.INFO, LOG_PREFIX + msg);
}
public static void verboseinfo(String msg) {
if(verbose)
log.log(Level.INFO, LOG_PREFIX + msg);
}
public static void severe(Exception e) {
log.log(Level.SEVERE, LOG_PREFIX + "Exception occured: ", e);
}
public static void severe(String msg) {
log.log(Level.SEVERE, LOG_PREFIX + msg);
}
public static void severe(String msg, Exception e) {
log.log(Level.SEVERE, LOG_PREFIX + msg, e);
}
public static void warning(String msg) {
log.log(Level.WARNING, LOG_PREFIX + msg);
}
public static void warning(String msg, Exception e) {
log.log(Level.WARNING, LOG_PREFIX + msg, e);
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,71 +0,0 @@
package org.dynmap;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import org.dynmap.utils.MapChunkCache;
public abstract class MapTile {
protected DynmapWorld world;
public abstract boolean render(MapChunkCache cache, String mapname);
public abstract List<DynmapChunk> getRequiredChunks();
public abstract MapTile[] getAdjecentTiles();
public DynmapWorld getDynmapWorld() {
return world;
}
public abstract String getFilename();
public abstract String getDayFilename();
public MapTile(DynmapWorld world) {
this.world = world;
}
@Override
public int hashCode() {
return getFilename().hashCode() ^ world.hashCode();
}
@Override
public abstract boolean equals(Object obj);
public abstract String getKey(String prefix);
public abstract boolean isBiomeDataNeeded();
public abstract boolean isHightestBlockYDataNeeded();
public abstract boolean isRawBiomeDataNeeded();
public abstract boolean isBlockTypeDataNeeded();
public abstract int tileOrdinalX();
public abstract int tileOrdinalY();
public ConfigurationNode saveTile() {
ConfigurationNode cn = new ConfigurationNode();
cn.put("class", this.getClass().getName());
cn.put("data", saveTileData());
return cn;
}
protected abstract String saveTileData();
public static MapTile restoreTile(DynmapWorld w, ConfigurationNode node) {
String cn = node.getString("class");
String dat = node.getString("data");
if((cn == null) || (dat == null)) return null;
try {
Class<?> cls = Class.forName(cn);
Constructor<?> con = cls.getConstructor(DynmapWorld.class, String.class);
return (MapTile)con.newInstance(w, dat);
} catch (ClassNotFoundException cnfx) {
} catch (NoSuchMethodException nsmx) {
} catch (InvocationTargetException itx) {
} catch (IllegalAccessException iax) {
} catch (InstantiationException ix) {
}
return null;
}
}

View file

@ -1,112 +0,0 @@
package org.dynmap;
import java.io.File;
import java.util.LinkedList;
import java.util.List;
import org.dynmap.utils.TileFlags;
import org.json.simple.JSONObject;
public abstract class MapType {
public enum ImageFormat {
FORMAT_PNG("png", "png", 0.0f),
FORMAT_JPG75("jpg-q75", "jpg", 0.75f),
FORMAT_JPG80("jpg-q80", "jpg", 0.80f),
FORMAT_JPG85("jpg-q85", "jpg", 0.85f),
FORMAT_JPG("jpg", "jpg", 0.85f),
FORMAT_JPG90("jpg-q90", "jpg", 0.90f),
FORMAT_JPG95("jpg-q95", "jpg", 0.95f),
FORMAT_JPG100("jpg-q100", "jpg", 1.00f);
String id;
String ext;
float qual;
ImageFormat(String id, String ext, float quality) {
this.id = id;
this.ext = ext;
this.qual = quality;
}
public String getID() { return id; }
public String getFileExt() { return ext; }
public float getQuality() { return qual; }
};
public static class ZoomInfo {
public String prefix;
public int background_argb;
public ZoomInfo(String pre, int bg) { prefix = pre; background_argb = bg; }
}
public abstract MapTile[] getTiles(DynmapWorld w, int x, int y, int z);
public abstract MapTile[] getTiles(DynmapWorld w, int minx, int miny, int minz, int maxx, int maxy, int maxz);
public abstract MapTile[] getAdjecentTiles(MapTile tile);
public abstract List<DynmapChunk> getRequiredChunks(MapTile tile);
public void buildClientConfiguration(JSONObject worldObject, DynmapWorld w) {
}
public abstract String getName();
/* Get maps rendered concurrently with this map in this world */
public abstract List<MapType> getMapsSharingRender(DynmapWorld w);
/* Get names of maps rendered concurrently with this map type in this world */
public abstract List<String> getMapNamesSharingRender(DynmapWorld w);
public enum MapStep {
X_PLUS_Y_PLUS,
X_PLUS_Y_MINUS,
X_MINUS_Y_PLUS,
X_MINUS_Y_MINUS
}
public abstract MapStep zoomFileMapStep();
public abstract List<ZoomInfo> baseZoomFileInfo();
public abstract int baseZoomFileStepSize();
/* How many bits of coordinate are shifted off to make big world directory name */
public abstract int getBigWorldShift();
/* Returns true if big world file structure is in effect for this map */
public abstract boolean isBigWorldMap(DynmapWorld w);
/* Return number of zoom levels needed by this map (before extra levels from extrazoomout) */
public int getMapZoomOutLevels() { return 0; }
public ImageFormat getImageFormat() { return ImageFormat.FORMAT_PNG; }
public int getBackgroundARGBNight() { return 0; }
public int getBackgroundARGBDay() { return 0; }
/**
* Step sequence for creating zoomed file: first index is top-left, second top-right, third bottom-left, forth bottom-right
* Values correspond to tile X,Y (0), X+step,Y (1), X,Y+step (2), X+step,Y+step (3)
*/
public abstract int[] zoomFileStepSequence();
public void purgeOldTiles(DynmapWorld world, TileFlags rendered) { }
public interface FileCallback {
public void fileFound(File f, File parent, boolean day);
}
protected void walkMapTree(File root, FileCallback cb, boolean day) {
LinkedList<File> dirs = new LinkedList<File>();
String ext = "." + getImageFormat().getFileExt();
dirs.add(root);
while(dirs.isEmpty() == false) {
File dir = dirs.pop();
String[] lst = dir.list();
for(String fn : lst) {
if(fn.equals(".") || fn.equals(".."))
continue;
File f = new File(dir, fn);
if(f.isDirectory()) { /* If directory, add to list to process */
dirs.add(f);
}
else if(fn.endsWith(ext)) { /* Else, if matches suffix */
cb.fileFound(f, dir, day);
}
}
}
}
}

View file

@ -1,207 +0,0 @@
package org.dynmap;
import org.dynmap.common.DynmapListenerManager.EventType;
import org.dynmap.common.DynmapListenerManager.WorldEventListener;
import org.dynmap.common.DynmapListenerManager.PlayerEventListener;
import org.dynmap.common.DynmapPlayer;
import org.dynmap.markers.Marker;
import org.dynmap.markers.MarkerIcon;
import org.dynmap.markers.MarkerSet;
import org.dynmap.markers.impl.MarkerAPIImpl;
import org.dynmap.markers.impl.MarkerSignManager;
/**
* Markers component - ties in the component system, both on the server and client
*/
public class MarkersComponent extends ClientComponent {
private MarkerAPIImpl api;
private MarkerSignManager signmgr;
private MarkerIcon spawnicon;
private String spawnlbl;
private MarkerSet offlineset;
private MarkerIcon offlineicon;
private MarkerSet spawnbedset;
private MarkerIcon spawnbedicon;
private String spawnbedformat;
private static final String OFFLINE_PLAYERS_SETID = "offline_players";
private static final String PLAYER_SPAWN_BED_SETID = "spawn_beds";
public MarkersComponent(final DynmapCore core, ConfigurationNode configuration) {
super(core, configuration);
/* Register API with plugin, if needed */
if(core.markerAPIInitialized()) {
api = (MarkerAPIImpl)core.getMarkerAPI();
}
else {
api = MarkerAPIImpl.initializeMarkerAPI(core);
core.registerMarkerAPI(api);
}
/* If configuration has enabled sign support, prime it too */
if(configuration.getBoolean("enablesigns", false)) {
signmgr = MarkerSignManager.initializeSignManager(core);
}
/* If we're posting spawn point markers, initialize and add world listener */
if(configuration.getBoolean("showspawn", false)) {
String ico = configuration.getString("spawnicon", MarkerIcon.WORLD);
spawnlbl = configuration.getString("spawnlabel", "Spawn");
spawnicon = api.getMarkerIcon(ico); /* Load it */
if(spawnicon == null) {
spawnicon = api.getMarkerIcon(MarkerIcon.WORLD);
}
/* Add listener for world loads */
WorldEventListener wel = new WorldEventListener() {
@Override
public void worldEvent(DynmapWorld w) {
DynmapLocation loc = w.getSpawnLocation(); /* Get location of spawn */
if(loc != null)
addUpdateWorld(w, loc);
}
};
core.listenerManager.addListener(EventType.WORLD_LOAD, wel);
/* Add listener for spawn changes */
core.listenerManager.addListener(EventType.WORLD_SPAWN_CHANGE, wel);
/* Initialize already loaded worlds */
for(DynmapWorld w : core.getMapManager().getWorlds()) {
DynmapLocation loc = w.getSpawnLocation();
if(loc != null)
addUpdateWorld(w, loc);
}
}
/* If showing offline players as markers */
if(configuration.getBoolean("showofflineplayers", false)) {
/* Make set, if needed */
offlineset = api.getMarkerSet(OFFLINE_PLAYERS_SETID);
if(offlineset == null) {
offlineset = api.createMarkerSet(OFFLINE_PLAYERS_SETID, configuration.getString("offlinelabel", "Offline"), null, true);
}
offlineset.setHideByDefault(configuration.getBoolean("offlinehidebydefault", true));
offlineset.setMinZoom(configuration.getInteger("offlineminzoom", 0));
offlineicon = api.getMarkerIcon(configuration.getString("offlineicon", "offlineuser"));
/* Add listener for players coming and going */
core.listenerManager.addListener(EventType.PLAYER_JOIN, new PlayerEventListener() {
@Override
public void playerEvent(DynmapPlayer p) {
Marker m = offlineset.findMarker(p.getName());
if(m != null) {
m.deleteMarker();
}
}
});
core.listenerManager.addListener(EventType.PLAYER_QUIT, new PlayerEventListener() {
@Override
public void playerEvent(DynmapPlayer p) {
String pname = p.getName();
Marker m = offlineset.findMarker(pname);
if(m != null) {
m.deleteMarker();
}
if(core.playerList.isVisiblePlayer(pname)) {
DynmapLocation loc = p.getLocation();
m = offlineset.createMarker(p.getName(), core.getServer().stripChatColor(p.getDisplayName()), false,
loc.world, loc.x, loc.y, loc.z, offlineicon, true);
}
}
});
}
else {
/* Make set, if needed */
offlineset = api.getMarkerSet(OFFLINE_PLAYERS_SETID);
if(offlineset != null) {
offlineset.deleteMarkerSet();
}
}
/* If showing player spawn bed locations as markers */
if(configuration.getBoolean("showspawnbeds", false)) {
/* Make set, if needed */
spawnbedset = api.getMarkerSet(PLAYER_SPAWN_BED_SETID);
if(spawnbedset == null) {
spawnbedset = api.createMarkerSet(PLAYER_SPAWN_BED_SETID, configuration.getString("spawnbedlabel", "Spawn Beds"), null, true);
}
spawnbedset.setHideByDefault(configuration.getBoolean("spawnbedhidebydefault", true));
spawnbedset.setMinZoom(configuration.getInteger("spawnbedminzoom", 0));
spawnbedicon = api.getMarkerIcon(configuration.getString("spawnbedicon", "bed"));
spawnbedformat = configuration.getString("spawnbedformat", "%name%'s bed");
/* Add listener for players coming and going */
core.listenerManager.addListener(EventType.PLAYER_JOIN, new PlayerEventListener() {
@Override
public void playerEvent(DynmapPlayer p) {
updatePlayer(p);
}
});
core.listenerManager.addListener(EventType.PLAYER_QUIT, new PlayerEventListener() {
@Override
public void playerEvent(DynmapPlayer p) {
Marker m = spawnbedset.findMarker(p.getName()+"_bed");
if(m != null) {
m.deleteMarker();
}
}
});
core.listenerManager.addListener(EventType.PLAYER_BED_LEAVE, new PlayerEventListener() {
@Override
public void playerEvent(final DynmapPlayer p) {
core.getServer().scheduleServerTask(new Runnable() {
public void run() {
updatePlayer(p);
}
}, 0);
}
});
}
else {
/* Make set, if needed */
spawnbedset = api.getMarkerSet(PLAYER_SPAWN_BED_SETID);
if(spawnbedset != null) {
spawnbedset.deleteMarkerSet();
}
}
}
private void updatePlayer(DynmapPlayer p) {
DynmapLocation bl = p.getBedSpawnLocation();
Marker m = spawnbedset.findMarker(p.getName()+"_bed");
if(bl == null) { /* No bed location */
if(m != null) {
m.deleteMarker();
}
}
else {
if(m != null)
m.setLocation(bl.world, bl.x, bl.y, bl.z);
else
m = spawnbedset.createMarker(p.getName()+"_bed", spawnbedformat.replace("%name%", core.getServer().stripChatColor(p.getDisplayName())), false,
bl.world, bl.x, bl.y, bl.z,
spawnbedicon, true);
}
}
private void addUpdateWorld(DynmapWorld w, DynmapLocation loc) {
MarkerSet ms = api.getMarkerSet(MarkerSet.DEFAULT);
if(ms != null) {
String spawnid = "_spawn_" + w.getName();
Marker m = ms.findMarker(spawnid); /* See if defined */
if(m == null) { /* Not defined yet, add it */
ms.createMarker(spawnid, spawnlbl, w.getName(), loc.x, loc.y, loc.z,
spawnicon, false);
}
else {
m.setLocation(w.getName(), loc.z, loc.y, loc.z);
}
}
}
@Override
public void dispose() {
if(signmgr != null) {
MarkerSignManager.terminateSignManager(this.core);
signmgr = null;
}
/* Don't unregister API - other plugins might be using it, and we want to keep non-persistent markers */
}
}

View file

@ -1,160 +0,0 @@
package org.dynmap;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import javax.imageio.ImageIO;
import org.dynmap.MapType.ImageFormat;
import org.dynmap.common.DynmapListenerManager.EventType;
import org.dynmap.common.DynmapListenerManager.PlayerEventListener;
import org.dynmap.common.DynmapPlayer;
import org.dynmap.debug.Debug;
import org.dynmap.utils.DynmapBufferedImage;
import org.dynmap.utils.FileLockManager;
/**
* Listen for player logins, and process player faces by fetching skins *
*/
public class PlayerFaces {
private File facesdir;
private File faces8x8dir;
private File faces16x16dir;
private File faces32x32dir;
private boolean fetchskins;
private boolean refreshskins;
private class LoadPlayerImages implements Runnable {
public String playername;
public LoadPlayerImages(String playername) {
this.playername = playername;
}
public void run() {
File img_8x8 = new File(faces8x8dir, playername + ".png");
File img_16x16 = new File(faces16x16dir, playername + ".png");
File img_32x32 = new File(faces32x32dir, playername + ".png");
boolean has_8x8 = img_8x8.exists();
boolean has_16x16 = img_16x16.exists();
boolean has_32x32 = img_32x32.exists();
boolean missing_any = !(has_8x8 && has_16x16 && has_32x32);
BufferedImage img = null;
try {
if(fetchskins && (refreshskins || missing_any)) {
URL url = new URL("http://s3.amazonaws.com/MinecraftSkins/" + playername + ".png");
img = ImageIO.read(url); /* Load skin for player */
}
} catch (IOException iox) {
Debug.debug("Error loading skin for '" + playername + "' - " + iox);
}
if(img == null) {
try {
InputStream in = getClass().getResourceAsStream("/char.png");
img = ImageIO.read(in); /* Load generic skin for player */
in.close();
} catch (IOException iox) {
Debug.debug("Error loading default skin for '" + playername + "' - " + iox);
}
}
if(img == null) { /* No image to process? Quit */
return;
}
int[] faceaccessory = new int[64]; /* 8x8 of face accessory */
/* Get buffered image for face at 8x8 */
DynmapBufferedImage face8x8 = DynmapBufferedImage.allocateBufferedImage(8, 8);
img.getRGB(8, 8, 8, 8, face8x8.argb_buf, 0, 8); /* Read face from image */
img.getRGB(40, 8, 8, 8, faceaccessory, 0, 8); /* Read face accessory from image */
/* Apply accessory to face: see if anything is transparent (if so, apply accessory */
boolean transp = false;
for(int i = 0; i < 64; i++) {
if((faceaccessory[i] & 0xFF000000) == 0) {
transp = true;
break;
}
}
if(transp) {
for(int i = 0; i < 64; i++) {
if((faceaccessory[i] & 0xFF000000) != 0)
face8x8.argb_buf[i] = faceaccessory[i];
}
}
/* Write 8x8 file */
if(refreshskins || (!has_8x8)) {
FileLockManager.getWriteLock(img_8x8);
try {
FileLockManager.imageIOWrite(face8x8.buf_img, ImageFormat.FORMAT_PNG, img_8x8);
} catch (IOException iox) {
Log.severe("Cannot write player icon " + img_8x8.getPath());
}
FileLockManager.releaseWriteLock(img_8x8);
}
/* Write 16x16 file */
if(refreshskins || (!has_16x16)) {
/* Make 16x16 version */
DynmapBufferedImage face16x16 = DynmapBufferedImage.allocateBufferedImage(16, 16);
for(int i = 0; i < 16; i++) {
for(int j = 0; j < 16; j++) {
face16x16.argb_buf[i*16+j] = face8x8.argb_buf[(i/2)*8 + (j/2)];
}
}
FileLockManager.getWriteLock(img_16x16);
try {
FileLockManager.imageIOWrite(face16x16.buf_img, ImageFormat.FORMAT_PNG, img_16x16);
} catch (IOException iox) {
Log.severe("Cannot write player icon " + img_16x16.getPath());
}
FileLockManager.releaseWriteLock(img_16x16);
DynmapBufferedImage.freeBufferedImage(face16x16);
}
/* Write 32x32 file */
if(refreshskins || (!has_32x32)) {
/* Make 32x32 version */
DynmapBufferedImage face32x32 = DynmapBufferedImage.allocateBufferedImage(32, 32);
for(int i = 0; i < 32; i++) {
for(int j = 0; j < 32; j++) {
face32x32.argb_buf[i*32+j] = face8x8.argb_buf[(i/4)*8 + (j/4)];
}
}
FileLockManager.getWriteLock(img_32x32);
try {
FileLockManager.imageIOWrite(face32x32.buf_img, ImageFormat.FORMAT_PNG, img_32x32);
} catch (IOException iox) {
Log.severe("Cannot write player icon " + img_32x32.getPath());
}
FileLockManager.releaseWriteLock(img_32x32);
DynmapBufferedImage.freeBufferedImage(face32x32);
}
DynmapBufferedImage.freeBufferedImage(face8x8);
/* TODO: signal update for player icon to client */
}
}
public PlayerFaces(DynmapCore core) {
fetchskins = core.configuration.getBoolean("fetchskins", true); /* Control whether to fetch skins */
refreshskins = core.configuration.getBoolean("refreshskins", true); /* Control whether to update existing fetched skins or faces */
core.listenerManager.addListener(EventType.PLAYER_JOIN, new PlayerEventListener() {
@Override
public void playerEvent(DynmapPlayer p) {
Runnable job = new LoadPlayerImages(p.getName());
if(fetchskins)
MapManager.scheduleDelayedJob(job, 0);
else
job.run();
}
});
facesdir = new File(core.getTilesFolder(), "faces");
facesdir.mkdirs(); /* Make sure directory exists */
faces8x8dir = new File(facesdir, "8x8");
faces8x8dir.mkdirs();
faces16x16dir = new File(facesdir, "16x16");
faces16x16dir.mkdirs();
faces32x32dir = new File(facesdir, "32x32");
faces32x32dir.mkdirs();
}
}

View file

@ -1,130 +0,0 @@
package org.dynmap;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Scanner;
import org.dynmap.common.DynmapPlayer;
import org.dynmap.common.DynmapServerInterface;
public class PlayerList {
private DynmapServerInterface server;
private HashSet<String> hiddenPlayerNames = new HashSet<String>();
private File hiddenPlayersFile;
private ConfigurationNode configuration;
private DynmapPlayer[] online;
public PlayerList(DynmapServerInterface server, File hiddenPlayersFile, ConfigurationNode configuration) {
this.server = server;
this.hiddenPlayersFile = hiddenPlayersFile;
this.configuration = configuration;
updateOnlinePlayers(null);
}
public void save() {
OutputStream stream;
try {
stream = new FileOutputStream(hiddenPlayersFile);
OutputStreamWriter writer = new OutputStreamWriter(stream);
for (String player : hiddenPlayerNames) {
writer.write(player);
writer.write("\n");
}
writer.close();
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void load() {
try {
Scanner scanner = new Scanner(hiddenPlayersFile);
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
hiddenPlayerNames.add(line);
}
scanner.close();
} catch (FileNotFoundException e) {
return;
}
}
public void hide(String playerName) {
hiddenPlayerNames.add(playerName.toLowerCase());
save();
}
public void show(String playerName) {
hiddenPlayerNames.remove(playerName.toLowerCase());
save();
}
public void setVisible(String playerName, boolean visible) {
if (visible ^ configuration.getBoolean("display-whitelist", false))
show(playerName);
else
hide(playerName);
}
public List<DynmapPlayer> getVisiblePlayers(String worldName) {
ArrayList<DynmapPlayer> visiblePlayers = new ArrayList<DynmapPlayer>();
DynmapPlayer[] onlinePlayers = online; /* Use copied list - we don't call from server thread */
boolean useWhitelist = configuration.getBoolean("display-whitelist", false);
for (int i = 0; i < onlinePlayers.length; i++) {
DynmapPlayer p = onlinePlayers[i];
if(p == null) continue;
if((worldName != null) && (p.getWorld().equals(worldName) == false)) continue;
if (!(useWhitelist ^ hiddenPlayerNames.contains(p.getName().toLowerCase()))) {
visiblePlayers.add(p);
}
}
return visiblePlayers;
}
public List<DynmapPlayer> getVisiblePlayers() {
return getVisiblePlayers(null);
}
public List<DynmapPlayer> getHiddenPlayers() {
ArrayList<DynmapPlayer> hidden = new ArrayList<DynmapPlayer>();
DynmapPlayer[] onlinePlayers = online; /* Use copied list - we don't call from server thread */
boolean useWhitelist = configuration.getBoolean("display-whitelist", false);
for (int i = 0; i < onlinePlayers.length; i++) {
DynmapPlayer p = onlinePlayers[i];
if(p == null) continue;
if (useWhitelist ^ hiddenPlayerNames.contains(p.getName().toLowerCase())) {
hidden.add(p);
}
}
return hidden;
}
public boolean isVisiblePlayer(String p) {
boolean useWhitelist = configuration.getBoolean("display-whitelist", false);
return (!(useWhitelist ^ hiddenPlayerNames.contains(p.toLowerCase())));
}
/**
* Call this from server thread to update player list safely
*/
void updateOnlinePlayers(String skipone) {
DynmapPlayer[] players = server.getOnlinePlayers();
DynmapPlayer[] pl = new DynmapPlayer[players.length];
System.arraycopy(players, 0, pl, 0, pl.length);
if(skipone != null) {
for(int i = 0; i < pl.length; i++)
if(pl[i].getName().equals(skipone))
pl[i] = null;
}
online = pl;
}
}

View file

@ -1,66 +0,0 @@
package org.dynmap;
import static org.dynmap.JSONUtils.s;
import org.dynmap.common.DynmapListenerManager;
import org.dynmap.common.DynmapListenerManager.ChatEventListener;
import org.dynmap.common.DynmapListenerManager.EventType;
import org.dynmap.common.DynmapPlayer;
import org.json.simple.JSONObject;
public class SimpleWebChatComponent extends Component {
public SimpleWebChatComponent(final DynmapCore plugin, final ConfigurationNode configuration) {
super(plugin, configuration);
plugin.events.addListener("webchat", new Event.Listener<ChatEvent>() {
@Override
public void triggered(ChatEvent t) {
if(plugin.getServer().sendWebChatEvent(t.source, t.name, t.message)) {
String msg;
String msgfmt = plugin.configuration.getString("webmsgformat", null);
if(msgfmt != null) {
msgfmt = unescapeString(msgfmt);
msg = msgfmt.replace("%playername%", t.name).replace("%message%", t.message);
}
else {
msg = unescapeString(plugin.configuration.getString("webprefix", "\u00A72[WEB] ")) + t.name + ": " + unescapeString(plugin.configuration.getString("websuffix", "\u00A7f")) + t.message;
}
plugin.getServer().broadcastMessage(msg);
}
}
});
plugin.events.addListener("buildclientconfiguration", new Event.Listener<JSONObject>() {
@Override
public void triggered(JSONObject t) {
s(t, "allowchat", configuration.getBoolean("allowchat", false));
}
});
if (configuration.getBoolean("allowchat", false)) {
plugin.listenerManager.addListener(EventType.PLAYER_CHAT, new ChatEventListener() {
@Override
public void chatEvent(DynmapPlayer p, String msg) {
if(core.mapManager != null)
core.mapManager.pushUpdate(new Client.ChatMessage("player", "", p.getDisplayName(), msg, p.getName()));
}
});
plugin.listenerManager.addListener(EventType.PLAYER_JOIN, new DynmapListenerManager.PlayerEventListener() {
@Override
public void playerEvent(DynmapPlayer p) {
if((core.mapManager != null) && (core.playerList != null) && (core.playerList.isVisiblePlayer(p.getName()))) {
core.mapManager.pushUpdate(new Client.PlayerJoinMessage(p.getDisplayName(), p.getName()));
}
}
});
plugin.listenerManager.addListener(EventType.PLAYER_QUIT, new DynmapListenerManager.PlayerEventListener() {
@Override
public void playerEvent(DynmapPlayer p) {
if((core.mapManager != null) && (core.playerList != null) && (core.playerList.isVisiblePlayer(p.getName()))) {
core.mapManager.pushUpdate(new Client.PlayerQuitMessage(p.getDisplayName(), p.getName()));
}
}
});
}
}
}

View file

@ -1,10 +0,0 @@
package org.dynmap;
public class TestComponent extends Component {
public TestComponent(DynmapCore plugin, ConfigurationNode configuration) {
super(plugin, configuration);
Log.info("Hello! I'm a component that does stuff! Like saying what is in my configuration: " + configuration.getString("stuff"));
}
}

View file

@ -1,195 +0,0 @@
package org.dynmap;
import java.io.File;
import java.io.RandomAccessFile;
import java.util.Arrays;
import java.util.LinkedList;
import java.io.IOException;
import java.util.zip.CRC32;
import org.dynmap.utils.LRULinkedHashMap;
/**
* Image hash code manager - used to reduce compression and notification of updated tiles that do not actually yield new content
*
*/
public class TileHashManager {
private File tiledir; /* Base tile directory */
private boolean enabled;
/**
* Each tile hash file is a 32x32 tile grid, with each file having a CRC32 hash code generated from its pre-compression frame buffer
*/
private static class TileHashFile {
final String key;
final String subtype;
final int x; /* minimum tile coordinate / 32 */
final int y; /* minimum tile coordinate / 32 */
private File hf;
TileHashFile(String key, String subtype, int x, int y) {
this.key = key;
if(subtype != null)
this.subtype = subtype;
else
this.subtype = "";
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object o) {
if(!(o instanceof TileHashFile))
return false;
TileHashFile fo = (TileHashFile)o;
return (x == fo.x) && (y == fo.y) && key.equals(fo.key) && (subtype.equals(fo.subtype));
}
@Override
public int hashCode() {
return key.hashCode() ^ subtype.hashCode() ^ (x << 16) ^ y;
}
public File getHashFile(File tiledir) {
if(hf == null) {
String k;
int idx = key.lastIndexOf('.'); /* Find last '.' - world name split (allows dots in world name) */
if(idx > 0)
k = key.substring(0, idx) + File.separatorChar + key.substring(idx+1);
else
k = key;
hf = new File(tiledir, k + (subtype.equals("")?"":("." + subtype)) + "_" + x + "_" + y + ".hash");
}
return hf;
}
/* Write to file */
public void writeToFile(File tiledir, byte[] crcbuf) {
RandomAccessFile fd = null;
try {
fd = new RandomAccessFile(getHashFile(tiledir), "rw");
fd.seek(0);
fd.write(crcbuf);
} catch (IOException iox) {
Log.severe("Error writing hash file - " + getHashFile(tiledir).getPath());
} finally {
if(fd != null) {
try { fd.close(); } catch (IOException iox) {}
}
}
}
/* Read from file */
public void readFromFile(File tiledir, byte[] crcbuf) {
RandomAccessFile fd = null;
try {
fd = new RandomAccessFile(getHashFile(tiledir), "r");
fd.seek(0);
fd.read(crcbuf);
} catch (IOException iox) {
Arrays.fill(crcbuf, (byte)0xFF);
writeToFile(tiledir, crcbuf);
} finally {
if(fd != null) {
try { fd.close(); } catch (IOException iox) {}
}
}
}
/* Read CRC */
public long getCRC(int tx, int ty, byte[] crcbuf) {
int off = (128 * (ty & 0x1F)) + (4 * (tx & 0x1F));
long crc = 0;
for(int i = 0; i < 4; i++)
crc = (crc << 8) + (0xFF & (int)crcbuf[off+i]);
return crc;
}
/* Set CRC */
public void setCRC(int tx, int ty, byte[] crcbuf, long crc) {
int off = (128 * (ty & 0x1F)) + (4 * (tx & 0x1F));
for(int i = 0; i < 4; i++)
crcbuf[off+i] = (byte)((crc >> ((3-i)*8)) & 0xFF);
}
}
private static final int MAX_CACHED_TILEHASHFILES = 25;
private Object lock = new Object();
private LRULinkedHashMap<TileHashFile, byte[]> tilehash = new LRULinkedHashMap<TileHashFile, byte[]>(MAX_CACHED_TILEHASHFILES);
private LinkedList<byte[]> crcworkbufs = new LinkedList<byte[]>();
private LinkedList<CRC32> crcs = new LinkedList<CRC32>();
public TileHashManager(File tileroot, boolean enabled) {
tiledir = tileroot;
this.enabled = enabled;
}
/* Read cached hashcode for given tile */
public long getImageHashCode(String key, String subtype, int tx, int ty) {
if(!enabled) {
return -1; /* Return value that never matches */
}
TileHashFile thf = new TileHashFile(key, subtype, tx >> 5, ty >> 5);
synchronized(lock) {
byte[] crcbuf = tilehash.get(thf); /* See if we have it cached */
if(crcbuf == null) { /* If not in cache, load it */
crcbuf = new byte[32*32*4]; /* Get our space */
Arrays.fill(crcbuf, (byte)0xFF); /* Fill with -1 */
tilehash.put(thf, crcbuf); /* Add to cache */
thf.readFromFile(tiledir, crcbuf);
}
return thf.getCRC(tx & 0x1F, ty & 0x1F, crcbuf);
}
}
/* Calculate hash code for given buffer */
public long calculateTileHash(int[] newbuf) {
if(!enabled) {
return 0; /* Return value that doesn't match */
}
CRC32 crc32;
byte[] crcworkbuf;
synchronized(lock) {
if(crcworkbufs.isEmpty()) {
crcworkbuf = new byte[4*newbuf.length];
}
else {
crcworkbuf = crcworkbufs.removeFirst();
}
if(crcs.isEmpty()) {
crc32 = new CRC32();
}
else {
crc32 = crcs.removeFirst();
crc32.reset();
}
}
if(crcworkbuf.length < (4*newbuf.length)){
crcworkbuf = new byte[4*newbuf.length];
}
for(int i = 0, off = 0; i < newbuf.length; i++) {
int v = newbuf[i];
crcworkbuf[off++] = (byte)v;
crcworkbuf[off++] = (byte)(v>>8);
crcworkbuf[off++] = (byte)(v>>16);
crcworkbuf[off++] = (byte)(v>>24);
}
/* Calculate CRC-32 for buffer */
crc32.update(crcworkbuf, 0, 4*newbuf.length);
long v = crc32.getValue();
synchronized(lock) {
crcworkbufs.addFirst(crcworkbuf);
crcs.addFirst(crc32);
}
return v;
}
/* Update hashcode for given tile */
public void updateHashCode(String key, String subtype, int tx, int ty, long newcrc) {
if(!enabled)
return;
synchronized(lock) {
/* Now, find and check existing value */
TileHashFile thf = new TileHashFile(key, subtype, tx >> 5, ty >> 5);
byte[] crcbuf = tilehash.get(thf); /* See if we have it cached */
if(crcbuf == null) { /* If not in cache, load it */
crcbuf = new byte[32*32*4]; /* Get our space */
tilehash.put(thf, crcbuf); /* Add to cache */
thf.readFromFile(tiledir, crcbuf);
}
thf.setCRC(tx & 0x1F, ty & 0x1F, crcbuf, newcrc); /* Update field */
thf.writeToFile(tiledir, crcbuf); /* And write it out */
}
}
}

View file

@ -1,120 +0,0 @@
package org.dynmap;
import java.util.ArrayList;
import java.util.HashMap;
public class UpdateQueue {
public Object lock = new Object();
private HashMap<UpdateRec,UpdateRec> updateSet = new HashMap<UpdateRec,UpdateRec>();
private UpdateRec orderedlist = null; /* Oldest to youngest */
private static final long maxUpdateAge = 120000;
private static final long ageOutPeriod = 5000;
private long lastageout = 0;
private static class UpdateRec {
Client.Update u;
UpdateRec next;
UpdateRec prev;
@Override
public boolean equals(Object o) {
if(o instanceof UpdateRec)
return u.equals(((UpdateRec)o).u);
return false;
}
@Override
public int hashCode() {
return u.hashCode();
}
}
private void doAgeOut(long now) {
/* If we're due */
if((now < lastageout) || (now > (lastageout + ageOutPeriod))) {
lastageout = now;
long deadline = now - maxUpdateAge;
while((orderedlist != null) && (orderedlist.u.timestamp < deadline)) {
UpdateRec r = orderedlist;
updateSet.remove(r); /* Remove record from set */
if(r.next == r) {
orderedlist = null;
}
else {
orderedlist = r.next;
r.next.prev = r.prev;
r.prev.next = r.next;
}
r.next = r.prev = null;
}
}
}
public void pushUpdate(Client.Update obj) {
synchronized (lock) {
/* Do inside lock - prevent delay between time and actual work */
long now = System.currentTimeMillis();
doAgeOut(now); /* Consider age out */
UpdateRec r = new UpdateRec();
r.u = obj;
UpdateRec oldr = updateSet.remove(r); /* Try to remove redundant event */
if(oldr != null) { /* If found, remove from ordered list too */
if(oldr.next == oldr) { /* Only one? */
orderedlist = null;
}
else {
if(orderedlist == oldr) { /* We're oldest? */
orderedlist = oldr.next;
}
oldr.next.prev = oldr.prev;
oldr.prev.next = oldr.next;
}
oldr.next = oldr.prev = null;
}
updateSet.put(r, r);
/* Add to end of ordered list */
if(orderedlist == null) {
orderedlist = r;
r.next = r.prev = r;
}
else {
r.next = orderedlist;
r.prev = orderedlist.prev;
r.next.prev = r.prev.next = r;
}
}
}
private ArrayList<Client.Update> tmpupdates = new ArrayList<Client.Update>();
public Client.Update[] getUpdatedObjects(long since) {
Client.Update[] updates;
synchronized (lock) {
long now = System.currentTimeMillis();
doAgeOut(now); /* Consider age out */
tmpupdates.clear();
if(orderedlist != null) {
UpdateRec r = orderedlist.prev; /* Get newest */
while(r != null) {
if(r.u.timestamp >= since) {
tmpupdates.add(r.u);
if(r == orderedlist)
r = null;
else
r = r.prev;
}
else {
r = null;
}
}
}
// Reverse output.
updates = new Client.Update[tmpupdates.size()];
for (int i = 0; i < updates.length; i++) {
updates[i] = tmpupdates.get(updates.length-1-i);
}
}
return updates;
}
}

View file

@ -73,6 +73,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
private PermissionProvider permissions;
private String version;
public BukkitEventProcessor bep;
public SnapshotCache sscache;
private MapManager mapManager;
public static DynmapPlugin plugin;
@ -227,7 +228,14 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
bname[i] = b[i].toString();
return bname;
}
@Override
public double getCacheHitRate() {
return sscache.getHitRate();
}
@Override
public void resetCacheStats() {
sscache.resetStats();
}
}
/**
* Player access abstraction class
@ -365,6 +373,8 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
this.setEnabled(false);
return;
}
sscache = new SnapshotCache(core.getSnapShotCacheSize());
/* Get map manager from core */
mapManager = core.getMapManager();
/* Initialized the currently loaded worlds */
@ -384,7 +394,13 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
bep.cleanup();
/* Disable core */
core.disableCore();
if(sscache != null) {
sscache.cleanup();
sscache = null;
}
}
@Override
public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
DynmapCommandSender dsender;
@ -548,7 +564,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
return;
Location loc = event.getBlock().getLocation();
String wn = loc.getWorld().getName();
mapManager.sscache.invalidateSnapshot(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
sscache.invalidateSnapshot(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
if(onplace) {
mapManager.touch(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), "blockplace");
}
@ -560,7 +576,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
return;
Location loc = event.getBlock().getLocation();
String wn = loc.getWorld().getName();
mapManager.sscache.invalidateSnapshot(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
sscache.invalidateSnapshot(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
if(onbreak) {
mapManager.touch(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), "blockbreak");
}
@ -572,7 +588,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
return;
Location loc = event.getBlock().getLocation();
String wn = loc.getWorld().getName();
mapManager.sscache.invalidateSnapshot(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
sscache.invalidateSnapshot(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
if(onleaves) {
mapManager.touch(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), "leavesdecay");
}
@ -584,7 +600,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
return;
Location loc = event.getBlock().getLocation();
String wn = loc.getWorld().getName();
mapManager.sscache.invalidateSnapshot(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
sscache.invalidateSnapshot(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
if(onburn) {
mapManager.touch(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), "blockburn");
}
@ -596,7 +612,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
return;
Location loc = event.getBlock().getLocation();
String wn = loc.getWorld().getName();
mapManager.sscache.invalidateSnapshot(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
sscache.invalidateSnapshot(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
if(onblockform) {
mapManager.touch(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), "blockform");
}
@ -608,7 +624,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
return;
Location loc = event.getBlock().getLocation();
String wn = loc.getWorld().getName();
mapManager.sscache.invalidateSnapshot(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
sscache.invalidateSnapshot(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
if(onblockfade) {
mapManager.touch(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), "blockfade");
}
@ -620,7 +636,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
return;
Location loc = event.getBlock().getLocation();
String wn = loc.getWorld().getName();
mapManager.sscache.invalidateSnapshot(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
sscache.invalidateSnapshot(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
if(onblockspread) {
mapManager.touch(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), "blockspread");
}
@ -632,12 +648,12 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
return;
Location loc = event.getToBlock().getLocation();
String wn = loc.getWorld().getName();
mapManager.sscache.invalidateSnapshot(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
sscache.invalidateSnapshot(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
if(onblockfromto)
mapManager.touch(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), "blockfromto");
loc = event.getBlock().getLocation();
wn = loc.getWorld().getName();
mapManager.sscache.invalidateSnapshot(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
sscache.invalidateSnapshot(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
if(onblockfromto)
mapManager.touch(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), "blockfromto");
}
@ -648,7 +664,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
return;
Location loc = event.getBlock().getLocation();
String wn = loc.getWorld().getName();
mapManager.sscache.invalidateSnapshot(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
sscache.invalidateSnapshot(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
if(onblockphysics) {
mapManager.touch(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), "blockphysics");
}
@ -668,14 +684,14 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
}
String wn = loc.getWorld().getName();
int x = loc.getBlockX(), y = loc.getBlockY(), z = loc.getBlockZ();
mapManager.sscache.invalidateSnapshot(wn, x, y, z);
sscache.invalidateSnapshot(wn, x, y, z);
if(onpiston)
mapManager.touch(wn, x, y, z, "pistonretract");
for(int i = 0; i < 2; i++) {
x += dir.getModX();
y += dir.getModY();
z += dir.getModZ();
mapManager.sscache.invalidateSnapshot(wn, x, y, z);
sscache.invalidateSnapshot(wn, x, y, z);
if(onpiston)
mapManager.touch(wn, x, y, z, "pistonretract");
}
@ -694,14 +710,14 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
}
String wn = loc.getWorld().getName();
int x = loc.getBlockX(), y = loc.getBlockY(), z = loc.getBlockZ();
mapManager.sscache.invalidateSnapshot(wn, x, y, z);
sscache.invalidateSnapshot(wn, x, y, z);
if(onpiston)
mapManager.touch(wn, x, y, z, "pistonretract");
for(int i = 0; i < 1+event.getLength(); i++) {
x += dir.getModX();
y += dir.getModY();
z += dir.getModZ();
mapManager.sscache.invalidateSnapshot(wn, x, y, z);
sscache.invalidateSnapshot(wn, x, y, z);
if(onpiston)
mapManager.touch(wn, x, y, z, "pistonretract");
}
@ -794,7 +810,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
if(z < minz) minz = z;
if(z > maxz) maxz = z;
}
mapManager.sscache.invalidateSnapshot(wname, minx, miny, minz, maxx, maxy, maxz);
sscache.invalidateSnapshot(wname, minx, miny, minz, maxx, maxy, maxz);
if(onexplosion) {
mapManager.touchVolume(wname, minx, miny, minz, maxx, maxy, maxz, "entityexplode");
}

View file

@ -481,7 +481,7 @@ public class NewMapChunkCache implements MapChunkCache {
}
}
/* Check if cached chunk snapshot found */
ChunkSnapshot ss = MapManager.mapman.sscache.getSnapshot(w.getName(), chunk.x, chunk.z, blockdata, biome, biomeraw, highesty);
ChunkSnapshot ss = DynmapPlugin.plugin.sscache.getSnapshot(w.getName(), chunk.x, chunk.z, blockdata, biome, biomeraw, highesty);
if(ss != null) {
if(!vis) {
if(hidestyle == HiddenChunkStyle.FILL_STONE_PLAIN)
@ -518,7 +518,7 @@ public class NewMapChunkCache implements MapChunkCache {
else
ss = w.getEmptyChunkSnapshot(chunk.x, chunk.z, biome, biomeraw);
if(ss != null) {
MapManager.mapman.sscache.putSnapshot(w.getName(), chunk.x, chunk.z, ss, blockdata, biome, biomeraw, highesty);
DynmapPlugin.plugin.sscache.putSnapshot(w.getName(), chunk.x, chunk.z, ss, blockdata, biome, biomeraw, highesty);
}
}
snaparray[(chunk.x-x_min) + (chunk.z - z_min)*x_dim] = ss;

View file

@ -1,33 +0,0 @@
package org.dynmap.common;
/* Generic biome mapping */
public enum BiomeMap {
NULL,
RAINFOREST,
SWAMPLAND,
SEASONAL_FOREST,
FOREST,
SAVANNA,
SHRUBLAND,
TAIGA,
DESERT,
PLAINS,
ICE_DESERT,
TUNDRA,
HELL,
SKY,
OCEAN,
RIVER,
EXTREME_HILLS,
FROZEN_OCEAN,
FROZEN_RIVER,
ICE_PLAINS,
ICE_MOUNTAINS,
MUSHROOM_ISLAND,
MUSHROOM_SHORE,
BEACH,
DESERT_HILLS,
FOREST_HILLS,
TAIGA_HILLS,
SMALL_MOUNTAINS
}

View file

@ -1,37 +0,0 @@
package org.dynmap.common;
public enum DynmapChatColor {
BLACK(0x0),
DARK_BLUE(0x1),
DARK_GREEN(0x2),
DARK_AQUA(0x3),
DARK_RED(0x4),
DARK_PURPLE(0x5),
GOLD(0x6),
GRAY(0x7),
DARK_GRAY(0x8),
BLUE(0x9),
GREEN(0xA),
AQUA(0xB),
RED(0xC),
LIGHT_PURPLE(0xD),
YELLOW(0xE),
WHITE(0xF);
private final String str;
private DynmapChatColor(final int code) {
this.str = String.format("\u00A7%x", code);
}
@Override
public String toString() {
return str;
}
public static String stripColor(final String input) {
if (input == null) {
return null;
}
return input.replaceAll("(?i)\u00A7[0-9A-F]", "");
}
}

View file

@ -1,24 +0,0 @@
package org.dynmap.common;
public interface DynmapCommandSender {
/**
* Does command sender have given security privilege
* @param privid - privilege ID
* @return true if it does, false if it doesn't
*/
public boolean hasPrivilege(String privid);
/**
* Send given message to command sender
* @param msg - message to be sent (with color codes marked &0 to &F)
*/
public void sendMessage(String msg);
/**
* Test if command sender is still connected/online
* @return true if connected, false if not
*/
public boolean isConnected();
/**
* Is operator privilege
*/
public boolean isOp();
}

View file

@ -1,123 +0,0 @@
package org.dynmap.common;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.Map;
import org.dynmap.DynmapCore;
import org.dynmap.DynmapWorld;
/**
* Simple handler for managing event listeners and dispatch in a neutral fashion
*
*/
public class DynmapListenerManager {
private DynmapCore core;
public DynmapListenerManager(DynmapCore core) {
this.core = core;
}
public interface EventListener {
}
public interface WorldEventListener extends EventListener {
public void worldEvent(DynmapWorld w);
}
public interface PlayerEventListener extends EventListener {
public void playerEvent(DynmapPlayer p);
}
public interface ChatEventListener extends EventListener {
public void chatEvent(DynmapPlayer p, String msg);
}
public interface BlockEventListener extends EventListener {
public void blockEvent(int blkid, String w, int x, int y, int z);
}
public interface SignChangeEventListener extends EventListener {
public void signChangeEvent(int blkid, String w, int x, int y, int z, String[] lines, DynmapPlayer p);
}
public enum EventType {
WORLD_LOAD,
WORLD_UNLOAD,
WORLD_SPAWN_CHANGE,
PLAYER_JOIN,
PLAYER_QUIT,
PLAYER_BED_LEAVE,
PLAYER_CHAT,
BLOCK_BREAK,
SIGN_CHANGE
}
private Map<EventType, ArrayList<EventListener>> listeners = new EnumMap<EventType, ArrayList<EventListener>>(EventType.class);
public void addListener(EventType type, EventListener listener) {
ArrayList<EventListener> lst = listeners.get(type);
if(lst == null) {
lst = new ArrayList<EventListener>();
listeners.put(type, lst);
core.getServer().requestEventNotification(type);
}
lst.add(listener);
}
public void processWorldEvent(EventType type, DynmapWorld w) {
ArrayList<EventListener> lst = listeners.get(type);
if(lst == null) return;
int sz = lst.size();
for(int i = 0; i < sz; i++) {
EventListener el = lst.get(i);
if(el instanceof WorldEventListener) {
((WorldEventListener)el).worldEvent(w);
}
}
}
public void processPlayerEvent(EventType type, DynmapPlayer p) {
ArrayList<EventListener> lst = listeners.get(type);
if(lst == null) return;
int sz = lst.size();
for(int i = 0; i < sz; i++) {
EventListener el = lst.get(i);
if(el instanceof PlayerEventListener) {
((PlayerEventListener)el).playerEvent(p);
}
}
}
public void processChatEvent(EventType type, DynmapPlayer p, String msg) {
ArrayList<EventListener> lst = listeners.get(type);
if(lst == null) return;
int sz = lst.size();
for(int i = 0; i < sz; i++) {
EventListener el = lst.get(i);
if(el instanceof ChatEventListener) {
((ChatEventListener)el).chatEvent(p, msg);
}
}
}
public void processBlockEvent(EventType type, int blkid, String world, int x, int y, int z)
{
ArrayList<EventListener> lst = listeners.get(type);
if(lst == null) return;
int sz = lst.size();
for(int i = 0; i < sz; i++) {
EventListener el = lst.get(i);
if(el instanceof BlockEventListener) {
((BlockEventListener)el).blockEvent(blkid, world, x, y, z);
}
}
}
public void processSignChangeEvent(EventType type, int blkid, String world, int x, int y, int z, String[] lines, DynmapPlayer p)
{
ArrayList<EventListener> lst = listeners.get(type);
if(lst == null) return;
int sz = lst.size();
for(int i = 0; i < sz; i++) {
EventListener el = lst.get(i);
if(el instanceof SignChangeEventListener) {
((SignChangeEventListener)el).signChangeEvent(blkid, world, x, y, z, lines, p);
}
}
}
/* Clean up registered listeners */
public void cleanup() {
for(ArrayList<EventListener> l : listeners.values())
l.clear();
listeners.clear();
}
}

View file

@ -1,56 +0,0 @@
package org.dynmap.common;
import java.net.InetSocketAddress;
import org.dynmap.DynmapLocation;
/**
* Player (server neutral) - represents online or offline player
*/
public interface DynmapPlayer extends DynmapCommandSender {
/**
* Get player ID
* @return ID (case insensitive)
*/
public String getName();
/**
* Get player display name
* @return display name
*/
public String getDisplayName();
/**
* Is player online?
* @return true if online
*/
public boolean isOnline();
/**
* Get current location of player
* @return location
*/
public DynmapLocation getLocation();
/**
* Get world ID of player
* @return id
*/
public String getWorld();
/**
* Get connected address for player
*/
public InetSocketAddress getAddress();
/**
* Check if player is sneaking
*/
public boolean isSneaking();
/**
* Get health
*/
public int getHealth();
/**
* Get armor points
*/
public int getArmorPoints();
/**
* Get spawn bed location
*/
public DynmapLocation getBedSpawnLocation();
}

View file

@ -1,78 +0,0 @@
package org.dynmap.common;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import org.dynmap.common.DynmapListenerManager.EventType;
/**
* This interface defines a server-neutral interface for the DynmapCore and other neutral components to use to access server provided
* services. Platform-specific plugin must supply DynmapCore with an instance of an object implementing this interface.
*/
public interface DynmapServerInterface {
/**
* Schedule task to run on server-safe thread (one suitable for other server API calls)
* @param run - runnable method
* @param delay - delay in server ticks (50msec)
*/
public void scheduleServerTask(Runnable run, long delay);
/**
* Call method on server-safe thread
* @param call - Callable method
* @return future for completion of call
*/
public <T> Future<T> callSyncMethod(Callable<T> task);
/**
* Get list of online players
* @return list of online players
*/
public DynmapPlayer[] getOnlinePlayers();
/**
* Request reload of plugin
*/
public void reload();
/**
* Get active player
* @param name - player name
* @return player
*/
public DynmapPlayer getPlayer(String name);
/**
* Get banned IPs
*/
public Set<String> getIPBans();
/**
* Get server name
*/
public String getServerName();
/**
* Test if player ID is banned
*/
public boolean isPlayerBanned(String pid);
/**
* Strip out chat color
*/
public String stripChatColor(String s);
/**
* Request notificiation for given events (used by DynmapListenerManager)
*/
public boolean requestEventNotification(EventType type);
/**
* Send notification of web chat message
* @param source - source
* @param name - name
* @param msg - message text
* @return true if not cancelled
*/
public boolean sendWebChatEvent(String source, String name, String msg);
/**
* Broadcast message to players
* @param msg
*/
public void broadcastMessage(String msg);
/**
* Get Biome ID list
*/
public String[] getBiomeIDs();
}

View file

@ -1,31 +0,0 @@
package org.dynmap.debug;
import java.util.ArrayList;
public class Debug {
private static ArrayList<Debugger> debuggers = new ArrayList<Debugger>();
public synchronized static void addDebugger(Debugger d) {
debuggers.add(d);
}
public synchronized static void removeDebugger(Debugger d) {
debuggers.remove(d);
}
public synchronized static void clearDebuggers() {
debuggers.clear();
}
public synchronized static void debug(String message) {
for(int i = 0; i < debuggers.size(); i++) debuggers.get(i).debug(message);
}
public synchronized static void error(String message) {
for(int i = 0; i < debuggers.size(); i++) debuggers.get(i).error(message);
}
public synchronized static void error(String message, Throwable thrown) {
for(int i = 0; i < debuggers.size(); i++) debuggers.get(i).error(message, thrown);
}
}

View file

@ -1,9 +0,0 @@
package org.dynmap.debug;
public interface Debugger {
void debug(String message);
void error(String message);
void error(String message, Throwable thrown);
}

View file

@ -1,27 +0,0 @@
package org.dynmap.debug;
import org.dynmap.ConfigurationNode;
import org.dynmap.DynmapCore;
import org.dynmap.Log;
public class LogDebugger implements Debugger {
public LogDebugger(DynmapCore core, ConfigurationNode configuration) {
}
@Override
public void debug(String message) {
Log.info(message);
}
@Override
public void error(String message) {
Log.severe(message);
}
@Override
public void error(String message, Throwable thrown) {
Log.severe(message);
thrown.printStackTrace();
}
}

View file

@ -1,21 +0,0 @@
package org.dynmap.debug;
import org.dynmap.ConfigurationNode;
import org.dynmap.DynmapCore;
public class NullDebugger implements Debugger {
public static final NullDebugger instance = new NullDebugger(null, null);
public NullDebugger(DynmapCore core, ConfigurationNode configuration) {
}
public void debug(String message) {
}
public void error(String message) {
}
public void error(String message, Throwable thrown) {
}
}

View file

@ -1,592 +0,0 @@
package org.dynmap.flat;
import org.dynmap.DynmapWorld;
import static org.dynmap.JSONUtils.a;
import static org.dynmap.JSONUtils.s;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.dynmap.Client;
import org.dynmap.Color;
import org.dynmap.ColorScheme;
import org.dynmap.ConfigurationNode;
import org.dynmap.DynmapChunk;
import org.dynmap.DynmapCore;
import org.dynmap.DynmapCore.CompassMode;
import org.dynmap.MapManager;
import org.dynmap.TileHashManager;
import org.dynmap.MapTile;
import org.dynmap.MapType;
import org.dynmap.debug.Debug;
import org.dynmap.utils.DynmapBufferedImage;
import org.dynmap.utils.FileLockManager;
import org.dynmap.utils.MapChunkCache;
import org.dynmap.utils.MapIterator;
import org.dynmap.utils.MapIterator.BlockStep;
import org.json.simple.JSONObject;
public class FlatMap extends MapType {
private ConfigurationNode configuration;
private String prefix;
private String name;
private ColorScheme colorScheme;
private int maximumHeight = 127;
private int ambientlight = 15;;
private int shadowscale[] = null;
private boolean night_and_day; /* If true, render both day (prefix+'-day') and night (prefix) tiles */
protected boolean transparency;
private enum Texture { NONE, SMOOTH, DITHER };
private Texture textured = Texture.NONE;
private boolean isbigmap;
public FlatMap(DynmapCore core, ConfigurationNode configuration) {
this.configuration = configuration;
name = configuration.getString("name", null);
prefix = configuration.getString("prefix", name);
colorScheme = ColorScheme.getScheme(core, (String) configuration.get("colorscheme"));
Object o = configuration.get("maximumheight");
if (o != null) {
maximumHeight = Integer.parseInt(String.valueOf(o));
if (maximumHeight > 127)
maximumHeight = 127;
}
o = configuration.get("shadowstrength");
if(o != null) {
double shadowweight = Double.parseDouble(String.valueOf(o));
if(shadowweight > 0.0) {
shadowscale = new int[16];
shadowscale[15] = 256;
/* Normal brightness weight in MC is a 20% relative dropoff per step */
for(int i = 14; i >= 0; i--) {
double v = shadowscale[i+1] * (1.0 - (0.2 * shadowweight));
shadowscale[i] = (int)v;
if(shadowscale[i] > 256) shadowscale[i] = 256;
if(shadowscale[i] < 0) shadowscale[i] = 0;
}
}
}
o = configuration.get("ambientlight");
if(o != null) {
ambientlight = Integer.parseInt(String.valueOf(o));
}
night_and_day = configuration.getBoolean("night-and-day", false);
transparency = configuration.getBoolean("transparency", false); /* Default off */
String tex = configuration.getString("textured", "none");
if(tex.equals("none"))
textured = Texture.NONE;
else if(tex.equals("dither"))
textured = Texture.DITHER;
else
textured = Texture.SMOOTH;
isbigmap = configuration.getBoolean("isbigmap", false);
}
@Override
public MapTile[] getTiles(DynmapWorld w, int x, int y, int z) {
return new MapTile[] { new FlatMapTile(w, this, x>>7, z>>7, 128) };
}
@Override
public MapTile[] getTiles(DynmapWorld w, int xmin, int ymin, int zmin, int xmax, int ymax, int zmax) {
ArrayList<MapTile> rslt = new ArrayList<MapTile>();
for(int i = xmin; i <= xmax; i++) {
for(int j = zmin; j < zmax; j++) {
rslt.add(new FlatMapTile(w, this, i, j, 128));
}
}
return rslt.toArray(new MapTile[rslt.size()]);
}
@Override
public MapTile[] getAdjecentTiles(MapTile tile) {
FlatMapTile t = (FlatMapTile) tile;
DynmapWorld w = t.getDynmapWorld();
int x = t.x;
int y = t.y;
int s = t.size;
return new MapTile[] {
new FlatMapTile(w, this, x, y - 1, s),
new FlatMapTile(w, this, x + 1, y, s),
new FlatMapTile(w, this, x, y + 1, s),
new FlatMapTile(w, this, x - 1, y, s) };
}
@Override
public List<DynmapChunk> getRequiredChunks(MapTile tile) {
FlatMapTile t = (FlatMapTile) tile;
int chunksPerTile = t.size / 16;
int sx = t.x * chunksPerTile;
int sz = t.y * chunksPerTile;
ArrayList<DynmapChunk> result = new ArrayList<DynmapChunk>(chunksPerTile * chunksPerTile);
for (int x = 0; x < chunksPerTile; x++)
for (int z = 0; z < chunksPerTile; z++) {
result.add(new DynmapChunk(sx + x, sz + z));
}
return result;
}
public boolean render(MapChunkCache cache, MapTile tile, File outputFile) {
FlatMapTile t = (FlatMapTile) tile;
boolean isnether = t.getDynmapWorld().isNether() && (maximumHeight == 127);
boolean didwrite = false;
Color rslt = new Color();
int[] pixel = new int[4];
int[] pixel_day = null;
DynmapBufferedImage im = DynmapBufferedImage.allocateBufferedImage(t.size, t.size);
int[] argb_buf = im.argb_buf;
DynmapBufferedImage im_day = null;
int[] argb_buf_day = null;
if(night_and_day) {
im_day = DynmapBufferedImage.allocateBufferedImage(t.size, t.size);
argb_buf_day = im_day.argb_buf;
pixel_day = new int[4];
}
MapIterator mapiter = cache.getIterator(t.x * t.size, 127, t.y * t.size);
for (int x = 0; x < t.size; x++) {
mapiter.initialize(t.x * t.size + x, 127, t.y * t.size);
for (int y = 0; y < t.size; y++, mapiter.stepPosition(BlockStep.Z_PLUS)) {
int blockType;
mapiter.setY(127);
if(isnether) {
while((blockType = mapiter.getBlockTypeID()) != 0) {
mapiter.stepPosition(BlockStep.Y_MINUS);
if(mapiter.getY() < 0) { /* Solid - use top */
mapiter.setY(127);
blockType = mapiter.getBlockTypeID();
break;
}
}
if(blockType == 0) { /* Hit air - now find non-air */
while((blockType = mapiter.getBlockTypeID()) == 0) {
mapiter.stepPosition(BlockStep.Y_MINUS);
if(mapiter.getY() < 0) {
mapiter.setY(0);
break;
}
}
}
}
else {
int my = mapiter.getHighestBlockYAt();
if(my > maximumHeight) my = maximumHeight;
mapiter.setY(my);
blockType = mapiter.getBlockTypeID();
if(blockType == 0) { /* If air, go down one - fixes ice */
my--;
if(my < 0)
continue;
mapiter.setY(my);
blockType = mapiter.getBlockTypeID();
}
}
int data = 0;
Color[] colors = colorScheme.colors[blockType];
if(colorScheme.datacolors[blockType] != null) {
data = mapiter.getBlockData();
colors = colorScheme.datacolors[blockType][data];
}
if (colors == null)
continue;
Color c;
if(textured == Texture.SMOOTH)
c = colors[4];
else if((textured == Texture.DITHER) && (((x+y) & 0x01) == 1)) {
c = colors[2];
}
else {
c = colors[0];
}
if (c == null)
continue;
pixel[0] = c.getRed();
pixel[1] = c.getGreen();
pixel[2] = c.getBlue();
pixel[3] = c.getAlpha();
/* If transparency needed, process it */
if(transparency && (pixel[3] < 255)) {
process_transparent(pixel, pixel_day, mapiter);
}
/* If ambient light less than 15, do scaling */
else if((shadowscale != null) && (ambientlight < 15)) {
if(mapiter.getY() < 127)
mapiter.stepPosition(BlockStep.Y_PLUS);
if(night_and_day) { /* Use unscaled color for day (no shadows from above) */
pixel_day[0] = pixel[0];
pixel_day[1] = pixel[1];
pixel_day[2] = pixel[2];
pixel_day[3] = 255;
}
int light = Math.max(ambientlight, mapiter.getBlockEmittedLight());
pixel[0] = (pixel[0] * shadowscale[light]) >> 8;
pixel[1] = (pixel[1] * shadowscale[light]) >> 8;
pixel[2] = (pixel[2] * shadowscale[light]) >> 8;
pixel[3] = 255;
}
else { /* Only do height keying if we're not messing with ambient light */
boolean below = mapiter.getY() < 64;
// Make height range from 0 - 1 (1 - 0 for below and 0 - 1 above)
float height = (below ? 64 - mapiter.getY() : mapiter.getY() - 64) / 64.0f;
// Defines the 'step' in coloring.
float step = 10 / 128.0f;
// The step applied to height.
float scale = ((int)(height/step))*step;
// Make the smaller values change the color (slightly) more than the higher values.
scale = (float)Math.pow(scale, 1.1f);
// Don't let the color go fully white or fully black.
scale *= 0.8f;
if (below) {
pixel[0] -= pixel[0] * scale;
pixel[1] -= pixel[1] * scale;
pixel[2] -= pixel[2] * scale;
pixel[3] = 255;
} else {
pixel[0] += (255-pixel[0]) * scale;
pixel[1] += (255-pixel[1]) * scale;
pixel[2] += (255-pixel[2]) * scale;
pixel[3] = 255;
}
if(night_and_day) {
pixel_day[0] = pixel[0];
pixel_day[1] = pixel[1];
pixel_day[2] = pixel[2];
pixel_day[3] = 255;
}
}
rslt.setRGBA(pixel[0], pixel[1], pixel[2], pixel[3]);
argb_buf[(t.size-y-1) + (x*t.size)] = rslt.getARGB();
if(night_and_day) {
rslt.setRGBA(pixel_day[0], pixel_day[1], pixel_day[2], pixel[3]);
argb_buf_day[(t.size-y-1) + (x*t.size)] = rslt.getARGB();
}
}
}
/* Test to see if we're unchanged from older tile */
TileHashManager hashman = MapManager.mapman.hashman;
long crc = hashman.calculateTileHash(argb_buf);
boolean tile_update = false;
FileLockManager.getWriteLock(outputFile);
try {
if((!outputFile.exists()) || (crc != hashman.getImageHashCode(tile.getKey(prefix), null, t.x, t.y))) {
/* Wrap buffer as buffered image */
Debug.debug("saving image " + outputFile.getPath());
if(!outputFile.getParentFile().exists())
outputFile.getParentFile().mkdirs();
try {
FileLockManager.imageIOWrite(im.buf_img, ImageFormat.FORMAT_PNG, outputFile);
} catch (IOException e) {
Debug.error("Failed to save image: " + outputFile.getPath(), e);
} catch (java.lang.NullPointerException e) {
Debug.error("Failed to save image (NullPointerException): " + outputFile.getPath(), e);
}
MapManager.mapman.pushUpdate(tile.getDynmapWorld(), new Client.Tile(tile.getFilename()));
hashman.updateHashCode(tile.getKey(prefix), null, t.x, t.y, crc);
tile.getDynmapWorld().enqueueZoomOutUpdate(outputFile);
tile_update = true;
didwrite = true;
}
else {
Debug.debug("skipping image " + outputFile.getPath() + " - hash match");
}
} finally {
FileLockManager.releaseWriteLock(outputFile);
DynmapBufferedImage.freeBufferedImage(im);
}
MapManager.mapman.updateStatistics(tile, prefix, true, tile_update, true);
/* If day too, handle it */
if(night_and_day) {
File dayfile = new File(tile.getDynmapWorld().worldtilepath, tile.getDayFilename());
crc = hashman.calculateTileHash(argb_buf_day);
FileLockManager.getWriteLock(dayfile);
try {
if((!dayfile.exists()) || (crc != hashman.getImageHashCode(tile.getKey(prefix), "day", t.x, t.y))) {
Debug.debug("saving image " + dayfile.getPath());
if(!dayfile.getParentFile().exists())
dayfile.getParentFile().mkdirs();
try {
FileLockManager.imageIOWrite(im_day.buf_img, ImageFormat.FORMAT_PNG, dayfile);
} catch (IOException e) {
Debug.error("Failed to save image: " + dayfile.getPath(), e);
} catch (java.lang.NullPointerException e) {
Debug.error("Failed to save image (NullPointerException): " + dayfile.getPath(), e);
}
MapManager.mapman.pushUpdate(tile.getDynmapWorld(), new Client.Tile(tile.getDayFilename()));
hashman.updateHashCode(tile.getKey(prefix), "day", t.x, t.y, crc);
tile.getDynmapWorld().enqueueZoomOutUpdate(dayfile);
tile_update = true;
didwrite = true;
}
else {
Debug.debug("skipping image " + dayfile.getPath() + " - hash match");
tile_update = false;
}
} finally {
FileLockManager.releaseWriteLock(dayfile);
DynmapBufferedImage.freeBufferedImage(im_day);
}
MapManager.mapman.updateStatistics(tile, prefix+"_day", true, tile_update, true);
}
return didwrite;
}
private void process_transparent(int[] pixel, int[] pixel_day, MapIterator mapiter) {
int r = pixel[0], g = pixel[1], b = pixel[2], a = pixel[3];
int r_day = 0, g_day = 0, b_day = 0, a_day = 0;
if(pixel_day != null) {
r_day = pixel[0]; g_day = pixel[1]; b_day = pixel[2]; a_day = pixel[3];
}
/* Scale alpha to be proportional to iso view (where we go through 4 blocks to go sqrt(6) or 2.45 units of distance */
if(a < 255)
a = a_day = 255 - ((255-a)*(255-a) >> 8);
/* Handle lighting on cube */
if((shadowscale != null) && (ambientlight < 15)) {
boolean did_inc = false;
if(mapiter.getY() < 127) {
mapiter.stepPosition(BlockStep.Y_PLUS);
did_inc = true;
}
if(night_and_day) { /* Use unscaled color for day (no shadows from above) */
r_day = r; g_day = g; b_day = b; a_day = a;
}
int light = Math.max(ambientlight, mapiter.getBlockEmittedLight());
r = (r * shadowscale[light]) >> 8;
g = (g * shadowscale[light]) >> 8;
b = (b * shadowscale[light]) >> 8;
if(did_inc)
mapiter.stepPosition(BlockStep.Y_MINUS);
}
if(a < 255) { /* If not opaque */
pixel[0] = pixel[1] = pixel[2] = pixel[3] = 0;
if(pixel_day != null)
pixel_day[0] = pixel_day[1] = pixel_day[2] = pixel_day[3] = 0;
mapiter.stepPosition(BlockStep.Y_MINUS);
if(mapiter.getY() >= 0) {
int blockType = mapiter.getBlockTypeID();
int data = 0;
Color[] colors = colorScheme.colors[blockType];
if(colorScheme.datacolors[blockType] != null) {
data = mapiter.getBlockData();
colors = colorScheme.datacolors[blockType][data];
}
if (colors != null) {
Color c = colors[0];
if (c != null) {
pixel[0] = c.getRed();
pixel[1] = c.getGreen();
pixel[2] = c.getBlue();
pixel[3] = c.getAlpha();
}
}
/* Recurse to resolve color here */
process_transparent(pixel, pixel_day, mapiter);
}
}
/* Blend colors from behind block and block, based on alpha */
r *= a;
g *= a;
b *= a;
int na = 255 - a;
pixel[0] = (pixel[0] * na + r) >> 8;
pixel[1] = (pixel[1] * na + g) >> 8;
pixel[2] = (pixel[2] * na + b) >> 8;
pixel[3] = 255;
if(pixel_day != null) {
r_day *= a_day;
g_day *= a_day;
b_day *= a_day;
na = 255 - a_day;
pixel_day[0] = (pixel_day[0] * na + r_day) >> 8;
pixel_day[1] = (pixel_day[1] * na + g_day) >> 8;
pixel_day[2] = (pixel_day[2] * na + b_day) >> 8;
pixel_day[3] = 255;
}
}
public String getName() {
return name;
}
public String getPrefix() {
return prefix;
}
/* Get maps rendered concurrently with this map in this world */
public List<MapType> getMapsSharingRender(DynmapWorld w) {
return Collections.singletonList((MapType)this);
}
/* Get names of maps rendered concurrently with this map type in this world */
public List<String> getMapNamesSharingRender(DynmapWorld w) {
return Collections.singletonList(name);
}
public List<ZoomInfo> baseZoomFileInfo() {
ArrayList<ZoomInfo> s = new ArrayList<ZoomInfo>();
s.add(new ZoomInfo(getPrefix() + "_128", 0));
if(night_and_day)
s.add(new ZoomInfo(getPrefix()+"_day_128", 0));
return s;
}
public int baseZoomFileStepSize() { return 1; }
private static final int[] stepseq = { 1, 3, 0, 2 };
public MapStep zoomFileMapStep() { return MapStep.X_PLUS_Y_PLUS; }
public int[] zoomFileStepSequence() { return stepseq; }
/* How many bits of coordinate are shifted off to make big world directory name */
public int getBigWorldShift() { return 5; }
/* Returns true if big world file structure is in effect for this map */
@Override
public boolean isBigWorldMap(DynmapWorld w) {
return w.bigworld || isbigmap;
}
public static class FlatMapTile extends MapTile {
FlatMap map;
public int x;
public int y;
public int size;
private String fname;
private String fname_day;
public FlatMapTile(DynmapWorld world, FlatMap map, int x, int y, int size) {
super(world);
this.map = map;
this.x = x;
this.y = y;
this.size = size;
}
public FlatMapTile(DynmapWorld world, String parm) throws Exception {
super(world);
String[] parms = parm.split(",");
if(parms.length < 4) throw new Exception("wrong parameter count");
this.x = Integer.parseInt(parms[0]);
this.y = Integer.parseInt(parms[1]);
this.size = Integer.parseInt(parms[2]);
for(MapType t : world.maps) {
if(t.getName().equals(parms[3]) && (t instanceof FlatMap)) {
this.map = (FlatMap)t;
break;
}
}
if(this.map == null) throw new Exception("invalid map");
}
@Override
protected String saveTileData() {
return String.format("%d,%d,%d,%s", x, y, size, map.getName());
}
@Override
public String getFilename() {
if(fname == null) {
if(world.bigworld)
fname = map.prefix + "_" + size + "/" + ((-(y+1))>>5) + "_" + (x>>5) + "/" + -(y+1) + "_" + x + ".png";
else
fname = map.prefix + "_" + size + "_" + -(y+1) + "_" + x + ".png";
}
return fname;
}
@Override
public String getDayFilename() {
if(fname_day == null) {
if(world.bigworld)
fname_day = map.prefix + "_day_" + size + "/" + ((-(y+1))>>5) + "_" + (x>>5) + "/" + -(y+1) + "_" + x + ".png";
else
fname_day = map.prefix + "_day_" + size + "_" + -(y+1) + "_" + x + ".png";
}
return fname_day;
}
public String toString() {
return world.getName() + ":" + getFilename();
}
@Override
public boolean render(MapChunkCache cache, String mapname) {
return map.render(cache, this, MapManager.mapman.getTileFile(this));
}
@Override
public List<DynmapChunk> getRequiredChunks() {
return map.getRequiredChunks(this);
}
@Override
public MapTile[] getAdjecentTiles() {
return map.getAdjecentTiles(this);
}
@Override
public int hashCode() {
return x ^ y ^ size ^ map.getName().hashCode();
}
@Override
public boolean equals(Object x) {
if(x instanceof FlatMapTile) {
return equals((FlatMapTile)x);
}
return false;
}
public boolean equals(FlatMapTile o) {
return (o.x == x) && (o.y == y) && (o.map == map);
}
@Override
public String getKey(String prefix) {
return world.getName() + "." + map.getPrefix();
}
public boolean isHightestBlockYDataNeeded() { return true; }
public boolean isBiomeDataNeeded() { return false; }
public boolean isRawBiomeDataNeeded() { return false; }
public boolean isBlockTypeDataNeeded() { return true; }
public int tileOrdinalX() { return x; }
public int tileOrdinalY() { return y; }
}
@Override
public void buildClientConfiguration(JSONObject worldObject, DynmapWorld world) {
ConfigurationNode c = configuration;
JSONObject o = new JSONObject();
s(o, "type", "FlatMapType");
s(o, "name", c.getString("name"));
s(o, "title", c.getString("title"));
s(o, "icon", c.getString("icon"));
s(o, "prefix", c.getString("prefix"));
s(o, "background", c.getString("background"));
s(o, "nightandday", c.getBoolean("night-and-day",false));
s(o, "backgroundday", c.getString("backgroundday"));
s(o, "backgroundnight", c.getString("backgroundnight"));
s(o, "bigmap", this.isBigWorldMap(world));
s(o, "mapzoomin", c.getInteger("mapzoomin", 3));
s(o, "mapzoomout", world.getExtraZoomOutLevels());
if(MapManager.mapman.getCompassMode() != CompassMode.PRE19)
s(o, "compassview", "E"); /* Always from east */
else
s(o, "compassview", "S"); /* Always from south */
s(o, "image-format", ImageFormat.FORMAT_PNG.getFileExt());
a(worldObject, "maps", o);
}
}

View file

@ -1,191 +0,0 @@
package org.dynmap.hdmap;
import static org.dynmap.JSONUtils.s;
import org.dynmap.Color;
import org.dynmap.ConfigurationNode;
import org.dynmap.DynmapCore;
import org.dynmap.utils.MapChunkCache;
import org.dynmap.utils.MapIterator;
import org.json.simple.JSONObject;
public class CaveHDShader implements HDShader {
private String name;
private boolean iflit;
public CaveHDShader(DynmapCore core, ConfigurationNode configuration) {
name = (String) configuration.get("name");
iflit = configuration.getBoolean("onlyiflit", false);
}
@Override
public boolean isBiomeDataNeeded() {
return false;
}
@Override
public boolean isRawBiomeDataNeeded() {
return false;
}
@Override
public boolean isHightestBlockYDataNeeded() {
return false;
}
@Override
public boolean isBlockTypeDataNeeded() {
return true;
}
@Override
public boolean isSkyLightLevelNeeded() {
return false;
}
@Override
public boolean isEmittedLightLevelNeeded() {
return iflit;
}
@Override
public String getName() {
return name;
}
private class OurShaderState implements HDShaderState {
private Color color;
protected MapIterator mapiter;
protected HDMap map;
private boolean air;
private OurShaderState(MapIterator mapiter, HDMap map) {
this.mapiter = mapiter;
this.map = map;
this.color = new Color();
}
/**
* Get our shader
*/
public HDShader getShader() {
return CaveHDShader.this;
}
/**
* Get our map
*/
public HDMap getMap() {
return map;
}
/**
* Get our lighting
*/
public HDLighting getLighting() {
return map.getLighting();
}
/**
* Reset renderer state for new ray
*/
public void reset(HDPerspectiveState ps) {
color.setTransparent();
air = true;
}
/**
* Process next ray step - called for each block on route
* @return true if ray is done, false if ray needs to continue
*/
public boolean processBlock(HDPerspectiveState ps) {
int blocktype = ps.getBlockTypeID();
switch (blocktype) {
case 0:
case 17:
case 18:
case 20:
case 64:
case 71:
case 78:
case 79:
blocktype = 0;
break;
default:
air = false;
return false;
}
if ((blocktype == 0) && !air) {
if(iflit && (ps.getMapIterator().getBlockEmittedLight() == 0)) {
return false;
}
int cr, cg, cb;
int mult = 256;
if (mapiter.getY() < 64) {
cr = 0;
cg = 64 + mapiter.getY() * 3;
cb = 255 - mapiter.getY() * 4;
} else {
cr = (mapiter.getY() - 64) * 4;
cg = 255;
cb = 0;
}
/* Figure out which color to use */
switch(ps.getLastBlockStep()) {
case X_PLUS:
case X_MINUS:
mult = 224;
break;
case Z_PLUS:
case Z_MINUS:
mult = 256;
break;
default:
mult = 160;
break;
}
cr = cr * mult / 256;
cg = cg * mult / 256;
cb = cb * mult / 256;
color.setRGBA(cr, cg, cb, 255);
return true;
}
return false;
}
/**
* Ray ended - used to report that ray has exited map (called if renderer has not reported complete)
*/
public void rayFinished(HDPerspectiveState ps) {
}
/**
* Get result color - get resulting color for ray
* @param c - object to store color value in
* @param index - index of color to request (renderer specific - 0=default, 1=day for night/day renderer
*/
public void getRayColor(Color c, int index) {
c.setColor(color);
}
/**
* Clean up state object - called after last ray completed
*/
public void cleanup() {
}
}
/**
* Get renderer state object for use rendering a tile
* @param map - map being rendered
* @param cache - chunk cache containing data for tile to be rendered
* @param mapiter - iterator used when traversing rays in tile
* @return state object to use for all rays in tile
*/
public HDShaderState getStateInstance(HDMap map, MapChunkCache cache, MapIterator mapiter) {
return new OurShaderState(mapiter, map);
}
/* Add shader's contributions to JSON for map object */
public void addClientConfiguration(JSONObject mapObject) {
s(mapObject, "shader", name);
}
}

View file

@ -1,51 +0,0 @@
package org.dynmap.hdmap;
import org.dynmap.Color;
import org.dynmap.ConfigurationNode;
import org.dynmap.DynmapCore;
import org.json.simple.JSONObject;
import static org.dynmap.JSONUtils.s;
public class DefaultHDLighting implements HDLighting {
private String name;
public DefaultHDLighting(DynmapCore core, ConfigurationNode configuration) {
name = (String) configuration.get("name");
}
/* Get lighting name */
public String getName() { return name; }
/* Apply lighting to given pixel colors (1 outcolor if normal, 2 if night/day) */
public void applyLighting(HDPerspectiveState ps, HDShaderState ss, Color incolor, Color[] outcolor) {
for(int i = 0; i < outcolor.length; i++)
outcolor[i].setColor(incolor);
}
/* Test if Biome Data is needed for this renderer */
public boolean isBiomeDataNeeded() { return false; }
/* Test if raw biome temperature/rainfall data is needed */
public boolean isRawBiomeDataNeeded() { return false; }
/* Test if highest block Y data is needed */
public boolean isHightestBlockYDataNeeded() { return false; }
/* Tet if block type data needed */
public boolean isBlockTypeDataNeeded() { return false; }
/* Test if night/day is enabled for this renderer */
public boolean isNightAndDayEnabled() { return false; }
/* Test if sky light level needed */
public boolean isSkyLightLevelNeeded() { return false; }
/* Test if emitted light level needed */
public boolean isEmittedLightLevelNeeded() { return false; }
/* Add shader's contributions to JSON for map object */
public void addClientConfiguration(JSONObject mapObject) {
s(mapObject, "lighting", name);
s(mapObject, "nightandday", isNightAndDayEnabled());
}
}

View file

@ -1,277 +0,0 @@
package org.dynmap.hdmap;
import static org.dynmap.JSONUtils.s;
import org.dynmap.Color;
import org.dynmap.ColorScheme;
import org.dynmap.ConfigurationNode;
import org.dynmap.DynmapCore;
import org.dynmap.common.BiomeMap;
import org.dynmap.utils.MapChunkCache;
import org.dynmap.utils.MapIterator;
import org.json.simple.JSONObject;
public class DefaultHDShader implements HDShader {
private String name;
protected ColorScheme colorScheme;
protected boolean transparency; /* Is transparency support active? */
public enum BiomeColorOption {
NONE, BIOME, TEMPERATURE, RAINFALL
}
protected BiomeColorOption biomecolored = BiomeColorOption.NONE; /* Use biome for coloring */
public DefaultHDShader(DynmapCore core, ConfigurationNode configuration) {
name = (String) configuration.get("name");
colorScheme = ColorScheme.getScheme(core, configuration.getString("colorscheme", "default"));
transparency = configuration.getBoolean("transparency", true); /* Default on */
String biomeopt = configuration.getString("biomecolored", "none");
if(biomeopt.equals("biome")) {
biomecolored = BiomeColorOption.BIOME;
}
else if(biomeopt.equals("temperature")) {
biomecolored = BiomeColorOption.TEMPERATURE;
}
else if(biomeopt.equals("rainfall")) {
biomecolored = BiomeColorOption.RAINFALL;
}
else {
biomecolored = BiomeColorOption.NONE;
}
}
@Override
public boolean isBiomeDataNeeded() {
return biomecolored == BiomeColorOption.BIOME;
}
@Override
public boolean isRawBiomeDataNeeded() {
return (biomecolored == BiomeColorOption.RAINFALL) || (biomecolored == BiomeColorOption.TEMPERATURE);
}
@Override
public boolean isHightestBlockYDataNeeded() {
return false;
}
@Override
public boolean isBlockTypeDataNeeded() {
return true;
}
@Override
public boolean isSkyLightLevelNeeded() {
return false;
}
@Override
public boolean isEmittedLightLevelNeeded() {
return false;
}
@Override
public String getName() {
return name;
}
private class OurShaderState implements HDShaderState {
private Color color[];
protected MapIterator mapiter;
protected HDMap map;
private Color tmpcolor[];
private int pixelodd;
private HDLighting lighting;
private OurShaderState(MapIterator mapiter, HDMap map) {
this.mapiter = mapiter;
this.map = map;
this.lighting = map.getLighting();
if(lighting.isNightAndDayEnabled()) {
color = new Color[] { new Color(), new Color() };
tmpcolor = new Color[] { new Color(), new Color() };
}
else {
color = new Color[] { new Color() };
tmpcolor = new Color[] { new Color() };
}
}
/**
* Get our shader
*/
public HDShader getShader() {
return DefaultHDShader.this;
}
/**
* Get our map
*/
public HDMap getMap() {
return map;
}
/**
* Get our lighting
*/
public HDLighting getLighting() {
return lighting;
}
/**
* Reset renderer state for new ray
*/
public void reset(HDPerspectiveState ps) {
for(int i = 0; i < color.length; i++)
color[i].setTransparent();
pixelodd = (ps.getPixelX() & 0x3) + (ps.getPixelY()<<1);
}
protected Color[] getBlockColors(int blocktype, int blockdata) {
if((blockdata != 0) && (colorScheme.datacolors[blocktype] != null))
return colorScheme.datacolors[blocktype][blockdata];
else
return colorScheme.colors[blocktype];
}
/**
* Process next ray step - called for each block on route
* @return true if ray is done, false if ray needs to continue
*/
public boolean processBlock(HDPerspectiveState ps) {
int i;
int blocktype = ps.getBlockTypeID();
if(blocktype == 0)
return false;
Color[] colors = getBlockColors(blocktype, ps.getBlockData());
if (colors != null) {
int seq;
int subalpha = ps.getSubmodelAlpha();
/* Figure out which color to use */
switch(ps.getLastBlockStep()) {
case X_PLUS:
case X_MINUS:
seq = 2;
break;
case Z_PLUS:
case Z_MINUS:
seq = 0;
break;
default:
//if(subalpha >= 0) /* We hit a block in a model */
// seq = 4; /* Use smooth top */
//else
if(((pixelodd + mapiter.getY()) & 0x03) == 0)
seq = 3;
else
seq = 1;
break;
}
Color c = colors[seq];
if (c.getAlpha() > 0) {
/* Handle light level, if needed */
lighting.applyLighting(ps, this, c, tmpcolor);
/* If we got alpha from subblock model, use it instead */
if(subalpha >= 0) {
for(int j = 0; j < tmpcolor.length; j++)
tmpcolor[j].setAlpha(Math.max(subalpha,tmpcolor[j].getAlpha()));
}
/* Blend color with accumulated color (weighted by alpha) */
if(!transparency) { /* No transparency support */
for(i = 0; i < color.length; i++)
color[i].setARGB(tmpcolor[i].getARGB() | 0xFF000000);
return true; /* We're done */
}
/* If no previous color contribution, use new color */
else if(color[0].isTransparent()) {
for(i = 0; i < color.length; i++)
color[i].setColor(tmpcolor[i]);
return (color[0].getAlpha() == 255);
}
/* Else, blend and generate new alpha */
else {
int alpha = color[0].getAlpha();
int alpha2 = tmpcolor[0].getAlpha() * (255-alpha) / 255;
int talpha = alpha + alpha2;
for(i = 0; i < color.length; i++)
color[i].setRGBA((tmpcolor[i].getRed()*alpha2 + color[i].getRed()*alpha) / talpha,
(tmpcolor[i].getGreen()*alpha2 + color[i].getGreen()*alpha) / talpha,
(tmpcolor[i].getBlue()*alpha2 + color[i].getBlue()*alpha) / talpha, talpha);
return (talpha >= 254); /* If only one short, no meaningful contribution left */
}
}
}
return false;
}
/**
* Ray ended - used to report that ray has exited map (called if renderer has not reported complete)
*/
public void rayFinished(HDPerspectiveState ps) {
}
/**
* Get result color - get resulting color for ray
* @param c - object to store color value in
* @param index - index of color to request (renderer specific - 0=default, 1=day for night/day renderer
*/
public void getRayColor(Color c, int index) {
c.setColor(color[index]);
}
/**
* Clean up state object - called after last ray completed
*/
public void cleanup() {
}
}
private class OurBiomeShaderState extends OurShaderState {
private OurBiomeShaderState(MapIterator mapiter, HDMap map) {
super(mapiter, map);
}
protected Color[] getBlockColors(int blocktype, int blockdata) {
BiomeMap bio = mapiter.getBiome();
if(bio != null)
return colorScheme.biomecolors[bio.ordinal()];
return null;
}
}
private class OurBiomeRainfallShaderState extends OurShaderState {
private OurBiomeRainfallShaderState(MapIterator mapiter, HDMap map) {
super(mapiter, map);
}
protected Color[] getBlockColors(int blocktype, int blockdata) {
return colorScheme.getRainColor(mapiter.getRawBiomeRainfall());
}
}
private class OurBiomeTempShaderState extends OurShaderState {
private OurBiomeTempShaderState(MapIterator mapiter, HDMap map) {
super(mapiter, map);
}
protected Color[] getBlockColors(int blocktype, int blockdata) {
return colorScheme.getTempColor(mapiter.getRawBiomeTemperature());
}
}
/**
* Get renderer state object for use rendering a tile
* @param map - map being rendered
* @param cache - chunk cache containing data for tile to be rendered
* @param mapiter - iterator used when traversing rays in tile
* @return state object to use for all rays in tile
*/
public HDShaderState getStateInstance(HDMap map, MapChunkCache cache, MapIterator mapiter) {
switch(biomecolored) {
case NONE:
return new OurShaderState(mapiter, map);
case BIOME:
return new OurBiomeShaderState(mapiter, map);
case RAINFALL:
return new OurBiomeRainfallShaderState(mapiter, map);
case TEMPERATURE:
return new OurBiomeTempShaderState(mapiter, map);
}
return null;
}
/* Add shader's contributions to JSON for map object */
public void addClientConfiguration(JSONObject mapObject) {
s(mapObject, "shader", name);
}
}

View file

@ -1,518 +0,0 @@
package org.dynmap.hdmap;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.dynmap.ConfigurationNode;
import org.dynmap.Log;
/**
* Custom block models - used for non-cube blocks to represent the physical volume associated with the block
* Used by perspectives to determine if rays have intersected a block that doesn't occupy its whole block
*/
public class HDBlockModels {
private int blockid;
private int databits;
private long blockflags[];
private int nativeres;
private HashMap<Integer, short[]> scaledblocks;
private static int linkalg[] = new int[256];
private static int linkmap[][] = new int[256][];
private static HashMap<Integer, HDBlockModels> models_by_id_data = new HashMap<Integer, HDBlockModels>();
public static class HDScaledBlockModels {
private short[][][] modelvectors;
public final short[] getScaledModel(int blocktype, int blockdata, int blockrenderdata) {
if(modelvectors[blocktype] == null) {
return null;
}
return modelvectors[blocktype][(blockrenderdata>=0)?blockrenderdata:blockdata];
}
}
private static HashMap<Integer, HDScaledBlockModels> scaled_models_by_scale = new HashMap<Integer, HDScaledBlockModels>();
/**
* Block definition - positions correspond to Bukkit coordinates (+X is south, +Y is up, +Z is west)
* @param blockid - block ID
* @param databits - bitmap of block data bits matching this model (bit N is set if data=N would match)
* @param nativeres - native subblocks per edge of cube (up to 64)
* @param blockflags - array of native^2 long integers representing volume of block (bit X of element (nativeres*Y+Z) is set if that subblock is filled)
* if array is short, other elements area are assumed to be zero (fills from bottom of block up)
*/
public HDBlockModels(int blockid, int databits, int nativeres, long[] blockflags) {
this.blockid = blockid;
this.databits = databits;
this.nativeres = nativeres;
this.blockflags = new long[nativeres * nativeres];
System.arraycopy(blockflags, 0, this.blockflags, 0, blockflags.length);
for(int i = 0; i < 16; i++) {
if((databits & (1<<i)) != 0) {
models_by_id_data.put((blockid<<4)+i, this);
}
}
}
/**
* Test if given native block is filled
*/
public final boolean isSubblockSet(int x, int y, int z) {
return ((blockflags[nativeres*y+z] & (1 << x)) != 0);
}
/**
* Set subblock value
*/
public final void setSubblock(int x, int y, int z, boolean isset) {
if(isset)
blockflags[nativeres*y+z] |= (1 << x);
else
blockflags[nativeres*y+z] &= ~(1 << x);
}
/**
* Get link algorithm
* @param blkid - block ID
* @return 0=no link alg
*/
public static final int getLinkAlgID(int blkid) {
return linkalg[blkid];
}
/**
* Get link block IDs
* @param blkid - block ID
* @return array of block IDs to link with
*/
public static final int[] getLinkIDs(int blkid) {
return linkmap[blkid];
}
/**
* Get scaled map of block: will return array of alpha levels, corresponding to how much of the
* scaled subblocks are occupied by the original blocks (indexed by Y*res*res + Z*res + X)
* @param res - requested scale (res subblocks per edge of block)
* @return array of alpha values (0-255), corresponding to resXresXres subcubes of block
*/
public short[] getScaledMap(int res) {
if(scaledblocks == null) { scaledblocks = new HashMap<Integer, short[]>(); }
short[] map = scaledblocks.get(Integer.valueOf(res));
if(map == null) {
map = new short[res*res*res];
if(res == nativeres) {
for(int i = 0; i < blockflags.length; i++) {
for(int j = 0; j < nativeres; j++) {
if((blockflags[i] & (1 << j)) != 0)
map[res*i+j] = 255;
}
}
}
/* If scaling from smaller sub-blocks to larger, each subblock contributes to 1-2 blocks
* on each axis: need to calculate crossovers for each, and iterate through smaller
* blocks to accumulate contributions
*/
else if(res > nativeres) {
int weights[] = new int[res];
int offsets[] = new int[res];
/* LCM of resolutions is used as length of line (res * nativeres)
* Each native block is (res) long, each scaled block is (nativeres) long
* Each scaled block overlaps 1 or 2 native blocks: starting with native block 'offsets[]' with
* 'weights[]' of its (res) width in the first, and the rest in the second
*/
for(int v = 0, idx = 0; v < res*nativeres; v += nativeres, idx++) {
offsets[idx] = (v/res); /* Get index of the first native block we draw from */
if((v+nativeres-1)/res == offsets[idx]) { /* If scaled block ends in same native block */
weights[idx] = nativeres;
}
else { /* Else, see how much is in first one */
weights[idx] = (offsets[idx] + res) - v;
weights[idx] = (offsets[idx]*res + res) - v;
}
}
/* Now, use weights and indices to fill in scaled map */
for(int y = 0, off = 0; y < res; y++) {
int ind_y = offsets[y];
int wgt_y = weights[y];
for(int z = 0; z < res; z++) {
int ind_z = offsets[z];
int wgt_z = weights[z];
for(int x = 0; x < res; x++, off++) {
int ind_x = offsets[x];
int wgt_x = weights[x];
int raw_w = 0;
for(int xx = 0; xx < 2; xx++) {
int wx = (xx==0)?wgt_x:(nativeres-wgt_x);
if(wx == 0) continue;
for(int yy = 0; yy < 2; yy++) {
int wy = (yy==0)?wgt_y:(nativeres-wgt_y);
if(wy == 0) continue;
for(int zz = 0; zz < 2; zz++) {
int wz = (zz==0)?wgt_z:(nativeres-wgt_z);
if(wz == 0) continue;
if(isSubblockSet(ind_x+xx, ind_y+yy, ind_z+zz)) {
raw_w += wx*wy*wz;
}
}
}
}
map[off] = (short)((255*raw_w) / (nativeres*nativeres*nativeres));
if(map[off] > 255) map[off] = 255;
if(map[off] < 0) map[off] = 0;
}
}
}
}
else { /* nativeres > res */
int weights[] = new int[nativeres];
int offsets[] = new int[nativeres];
/* LCM of resolutions is used as length of line (res * nativeres)
* Each native block is (res) long, each scaled block is (nativeres) long
* Each native block overlaps 1 or 2 scaled blocks: starting with scaled block 'offsets[]' with
* 'weights[]' of its (res) width in the first, and the rest in the second
*/
for(int v = 0, idx = 0; v < res*nativeres; v += res, idx++) {
offsets[idx] = (v/nativeres); /* Get index of the first scaled block we draw to */
if((v+res-1)/nativeres == offsets[idx]) { /* If native block ends in same scaled block */
weights[idx] = res;
}
else { /* Else, see how much is in first one */
weights[idx] = (offsets[idx]*nativeres + nativeres) - v;
}
}
/* Now, use weights and indices to fill in scaled map */
long accum[] = new long[map.length];
for(int y = 0; y < nativeres; y++) {
int ind_y = offsets[y];
int wgt_y = weights[y];
for(int z = 0; z < nativeres; z++) {
int ind_z = offsets[z];
int wgt_z = weights[z];
for(int x = 0; x < nativeres; x++) {
if(isSubblockSet(x, y, z)) {
int ind_x = offsets[x];
int wgt_x = weights[x];
for(int xx = 0; xx < 2; xx++) {
int wx = (xx==0)?wgt_x:(res-wgt_x);
if(wx == 0) continue;
for(int yy = 0; yy < 2; yy++) {
int wy = (yy==0)?wgt_y:(res-wgt_y);
if(wy == 0) continue;
for(int zz = 0; zz < 2; zz++) {
int wz = (zz==0)?wgt_z:(res-wgt_z);
if(wz == 0) continue;
accum[(ind_y+yy)*res*res + (ind_z+zz)*res + (ind_x+xx)] +=
wx*wy*wz;
}
}
}
}
}
}
}
for(int i = 0; i < map.length; i++) {
map[i] = (short)(accum[i]*255/nativeres/nativeres/nativeres);
if(map[i] > 255) map[i] = 255;
if(map[i] < 0) map[i] = 0;
}
}
scaledblocks.put(Integer.valueOf(res), map);
}
return map;
}
/**
* Get scaled set of models for all modelled blocks
* @param scale
* @return
*/
public static HDScaledBlockModels getModelsForScale(int scale) {
HDScaledBlockModels model = scaled_models_by_scale.get(Integer.valueOf(scale));
if(model == null) {
model = new HDScaledBlockModels();
short[][][] blockmodels = new short[256][][];
for(HDBlockModels m : models_by_id_data.values()) {
short[][] row = blockmodels[m.blockid];
if(row == null) {
row = new short[16][];
blockmodels[m.blockid] = row;
}
short[] smod = m.getScaledMap(scale);
/* See if scaled model is full block : much faster to not use it if it is */
if(smod != null) {
boolean keep = false;
for(int i = 0; (!keep) && (i < smod.length); i++) {
if(smod[i] == 0) keep = true;
}
if(keep) {
for(int i = 0; i < 16; i++) {
if((m.databits & (1 << i)) != 0) {
row[i] = smod;
}
}
}
}
}
model.modelvectors = blockmodels;
scaled_models_by_scale.put(scale, model);
}
return model;
}
/**
* Load models
*/
public static void loadModels(File datadir, ConfigurationNode config) {
/* Reset models-by-ID-Data cache */
models_by_id_data.clear();
/* Reset scaled models by scale cache */
scaled_models_by_scale.clear();
/* Load block models */
InputStream in = TexturePack.class.getResourceAsStream("/models.txt");
if(in != null) {
loadModelFile(in, "models.txt", config);
try { in.close(); } catch (IOException iox) {} in = null;
}
File customdir = new File(datadir, "renderdata");
String[] files = customdir.list();
if(files != null) {
for(String fn : files) {
if(fn.endsWith("-models.txt") == false)
continue;
File custom = new File(customdir, fn);
if(custom.canRead()) {
try {
in = new FileInputStream(custom);
loadModelFile(in, custom.getPath(), config);
} catch (IOException iox) {
Log.severe("Error loading " + custom.getPath());
} finally {
if(in != null) {
try { in.close(); } catch (IOException iox) {}
in = null;
}
}
}
}
}
}
private static Integer getIntValue(Map<String,Integer> vars, String val) throws NumberFormatException {
if(Character.isLetter(val.charAt(0))) {
Integer v = vars.get(val);
if(v == null)
throw new NumberFormatException("invalid ID - " + val);
return v;
}
else {
return Integer.valueOf(val);
}
}
/**
* Load models from file
*/
private static void loadModelFile(InputStream in, String fname, ConfigurationNode config) {
LineNumberReader rdr = null;
int cnt = 0;
try {
String line;
ArrayList<HDBlockModels> modlist = new ArrayList<HDBlockModels>();
HashMap<String,Integer> varvals = new HashMap<String,Integer>();
int layerbits = 0;
int rownum = 0;
int scale = 0;
rdr = new LineNumberReader(new InputStreamReader(in));
while((line = rdr.readLine()) != null) {
if(line.startsWith("block:")) {
ArrayList<Integer> blkids = new ArrayList<Integer>();
int databits = 0;
scale = 0;
line = line.substring(6);
String[] args = line.split(",");
for(String a : args) {
String[] av = a.split("=");
if(av.length < 2) continue;
if(av[0].equals("id")) {
blkids.add(getIntValue(varvals,av[1]));
}
else if(av[0].equals("data")) {
if(av[1].equals("*"))
databits = 0xFFFF;
else
databits |= (1 << getIntValue(varvals,av[1]));
}
else if(av[0].equals("scale")) {
scale = Integer.parseInt(av[1]);
}
}
/* If we have everything, build block */
if((blkids.size() > 0) && (databits != 0) && (scale > 0)) {
modlist.clear();
for(Integer id : blkids) {
modlist.add(new HDBlockModels(id.intValue(), databits, scale, new long[0]));
cnt++;
}
}
else {
Log.severe("Block model missing required parameters = line " + rdr.getLineNumber() + " of " + fname);
}
layerbits = 0;
}
else if(line.startsWith("layer:")) {
line = line.substring(6);
String args[] = line.split(",");
layerbits = 0;
rownum = 0;
for(String a: args) {
layerbits |= (1 << Integer.parseInt(a));
}
}
else if(line.startsWith("rotate:")) {
line = line.substring(7);
String args[] = line.split(",");
int id = -1;
int data = -1;
int rot = -1;
for(String a : args) {
String[] av = a.split("=");
if(av.length < 2) continue;
if(av[0].equals("id")) { id = getIntValue(varvals,av[1]); }
if(av[0].equals("data")) { data = getIntValue(varvals,av[1]); }
if(av[0].equals("rot")) { rot = Integer.parseInt(av[1]); }
}
/* get old model to be rotated */
HDBlockModels mod = models_by_id_data.get((id<<4)+data);
if((mod != null) && ((rot%90) == 0)) {
for(int x = 0; x < scale; x++) {
for(int y = 0; y < scale; y++) {
for(int z = 0; z < scale; z++) {
if(mod.isSubblockSet(x, y, z) == false) continue;
switch(rot) {
case 0:
for(HDBlockModels bm : modlist)
bm.setSubblock(x, y, z, true);
break;
case 90:
for(HDBlockModels bm : modlist)
bm.setSubblock(scale-z-1, y, x, true);
break;
case 180:
for(HDBlockModels bm : modlist)
bm.setSubblock(scale-x-1, y, scale-z-1, true);
break;
case 270:
for(HDBlockModels bm : modlist)
bm.setSubblock(z, y, scale-x-1, true);
break;
}
}
}
}
}
}
else if(line.startsWith("linkmap:")) {
ArrayList<Integer> blkids = new ArrayList<Integer>();
line = line.substring(8);
String[] args = line.split(",");
List<Integer> map = new ArrayList<Integer>();
int linktype = 0;
for(String a : args) {
String[] av = a.split("=");
if(av.length < 2) continue;
if(av[0].equals("id")) {
blkids.add(getIntValue(varvals,av[1]));
}
else if(av[0].equals("linkalg")) {
linktype = Integer.parseInt(av[1]);
}
else if(av[0].equals("linkid")) {
map.add(getIntValue(varvals,av[1]));
}
}
if(linktype > 0) {
int[] mapids = new int[map.size()];
for(int i = 0; i < mapids.length; i++)
mapids[i] = map.get(i);
for(Integer bid : blkids) {
linkalg[bid] = linktype;
linkmap[bid] = mapids;
}
}
}
else if(line.startsWith("#") || line.startsWith(";")) {
}
else if(line.startsWith("enabled:")) { /* Test if texture file is enabled */
line = line.substring(8).trim();
if(line.startsWith("true")) { /* We're enabled? */
/* Nothing to do - keep processing */
}
else if(line.startsWith("false")) { /* Disabled */
return; /* Quit */
}
/* If setting is not defined or false, quit */
else if(config.getBoolean(line, false) == false) {
return;
}
else {
Log.info(line + " models enabled");
}
}
else if(line.startsWith("var:")) { /* Test if variable declaration */
line = line.substring(4).trim();
String args[] = line.split(",");
for(int i = 0; i < args.length; i++) {
String[] v = args[i].split("=");
if(v.length < 2) {
Log.severe("Format error - line " + rdr.getLineNumber() + " of " + fname);
return;
}
try {
int val = Integer.valueOf(v[1]); /* Parse default value */
int parmval = config.getInteger(v[0], val); /* Read value, with applied default */
varvals.put(v[0], parmval); /* And save value */
} catch (NumberFormatException nfx) {
Log.severe("Format error - line " + rdr.getLineNumber() + " of " + fname);
return;
}
}
}
else if(layerbits != 0) { /* If we're working pattern lines */
/* Layerbits determine Y, rows count from North to South (X=0 to X=N-1), columns Z are West to East (N-1 to 0) */
for(int i = 0; (i < scale) && (i < line.length()); i++) {
if(line.charAt(i) == '*') { /* If an asterix, set flag */
for(int y = 0; y < scale; y++) {
if((layerbits & (1<<y)) != 0) {
for(HDBlockModels mod : modlist) {
mod.setSubblock(rownum, y, scale-i-1, true);
}
}
}
}
}
/* See if we're done with layer */
rownum++;
if(rownum >= scale) {
rownum = 0;
layerbits = 0;
}
}
}
Log.verboseinfo("Loaded " + cnt + " block models from " + fname);
} catch (IOException iox) {
Log.severe("Error reading models.txt - " + iox.toString());
} catch (NumberFormatException nfx) {
Log.severe("Format error - line " + rdr.getLineNumber() + " of " + fname);
} finally {
if(rdr != null) {
try {
rdr.close();
rdr = null;
} catch (IOException e) {
}
}
}
}
}

View file

@ -1,27 +0,0 @@
package org.dynmap.hdmap;
import org.dynmap.Color;
import org.json.simple.JSONObject;
public interface HDLighting {
/* Get lighting name */
String getName();
/* Apply lighting to given pixel colors (1 outcolor if normal, 2 if night/day) */
void applyLighting(HDPerspectiveState ps, HDShaderState ss, Color incolor, Color[] outcolor);
/* Test if Biome Data is needed for this renderer */
boolean isBiomeDataNeeded();
/* Test if raw biome temperature/rainfall data is needed */
boolean isRawBiomeDataNeeded();
/* Test if highest block Y data is needed */
boolean isHightestBlockYDataNeeded();
/* Tet if block type data needed */
boolean isBlockTypeDataNeeded();
/* Test if night/day is enabled for this renderer */
boolean isNightAndDayEnabled();
/* Test if sky light level needed */
boolean isSkyLightLevelNeeded();
/* Test if emitted light level needed */
boolean isEmittedLightLevelNeeded();
/* Add shader's contributions to JSON for map object */
void addClientConfiguration(JSONObject mapObject);
}

View file

@ -1,335 +0,0 @@
package org.dynmap.hdmap;
import static org.dynmap.JSONUtils.a;
import static org.dynmap.JSONUtils.s;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.dynmap.Client;
import org.dynmap.ConfigurationNode;
import org.dynmap.DynmapChunk;
import org.dynmap.DynmapCore;
import org.dynmap.DynmapWorld;
import org.dynmap.Log;
import org.dynmap.MapManager;
import org.dynmap.MapTile;
import org.dynmap.MapType;
import org.dynmap.debug.Debug;
import org.dynmap.utils.TileFlags;
import org.json.simple.JSONObject;
public class HDMap extends MapType {
private String name;
private String prefix;
private HDPerspective perspective;
private HDShader shader;
private HDLighting lighting;
private ConfigurationNode configuration;
private int mapzoomout;
private MapType.ImageFormat imgformat;
private int bgcolornight;
private int bgcolorday;
public static final String IMGFORMAT_PNG = "png";
public static final String IMGFORMAT_JPG = "jpg";
public HDMap(DynmapCore core, ConfigurationNode configuration) {
name = configuration.getString("name", null);
if(name == null) {
Log.severe("HDMap missing required attribute 'name' - disabled");
return;
}
String perspectiveid = configuration.getString("perspective", "default");
perspective = MapManager.mapman.hdmapman.perspectives.get(perspectiveid);
if(perspective == null) {
/* Try to use default */
perspective = MapManager.mapman.hdmapman.perspectives.get("default");
if(perspective == null) {
Log.severe("HDMap '"+name+"' loaded invalid perspective '" + perspectiveid + "' - map disabled");
name = null;
return;
}
else {
Log.severe("HDMap '"+name+"' loaded invalid perspective '" + perspectiveid + "' - using 'default' perspective");
}
}
String shaderid = configuration.getString("shader", "default");
shader = MapManager.mapman.hdmapman.shaders.get(shaderid);
if(shader == null) {
shader = MapManager.mapman.hdmapman.shaders.get("default");
if(shader == null) {
Log.severe("HDMap '"+name+"' loading invalid shader '" + shaderid + "' - map disabled");
name = null;
return;
}
else {
Log.severe("HDMap '"+name+"' loading invalid shader '" + shaderid + "' - using 'default' shader");
}
}
String lightingid = configuration.getString("lighting", "default");
lighting = MapManager.mapman.hdmapman.lightings.get(lightingid);
if(lighting == null) {
lighting = MapManager.mapman.hdmapman.lightings.get("default");
if(lighting == null) {
Log.severe("HDMap '"+name+"' loading invalid lighting '" + lighting + "' - map disabled");
name = null;
return;
}
else {
Log.severe("HDMap '"+name+"' loading invalid lighting '" + lighting + "' - using 'default' lighting");
}
}
prefix = configuration.getString("prefix", name);
this.configuration = configuration;
/* Compute extra zoom outs needed for this map */
double scale = perspective.getScale();
mapzoomout = 0;
while(scale >= 1.0) {
mapzoomout++;
scale = scale / 2.0;
}
String fmt = configuration.getString("image-format", "png");
/* Only allow png or jpg */
for(ImageFormat f : ImageFormat.values()) {
if(fmt.equals(f.getID())) {
imgformat = f;
break;
}
}
if(imgformat == null) {
Log.severe("HDMap '"+name+"' set invalid image-format: " + fmt);
imgformat = ImageFormat.FORMAT_PNG;
}
/* Get color info */
String c = configuration.getString("background");
if(c != null) {
bgcolorday = bgcolornight = parseColor(c);
}
c = configuration.getString("backgroundday");
if(c != null) {
bgcolorday = parseColor(c);
}
c = configuration.getString("backgroundnight");
if(c != null) {
bgcolornight = parseColor(c);
}
if(imgformat != ImageFormat.FORMAT_PNG) { /* If JPG, set background color opacity */
bgcolorday |= 0xFF000000;
bgcolornight |= 0xFF000000;
}
}
public HDShader getShader() { return shader; }
public HDPerspective getPerspective() { return perspective; }
public HDLighting getLighting() { return lighting; }
@Override
public MapTile[] getTiles(DynmapWorld w, int x, int y, int z) {
return perspective.getTiles(w, x, y, z);
}
@Override
public MapTile[] getTiles(DynmapWorld w, int minx, int miny, int minz, int maxx, int maxy, int maxz) {
return perspective.getTiles(w, minx, miny, minz, maxx, maxy, maxz);
}
@Override
public MapTile[] getAdjecentTiles(MapTile tile) {
return perspective.getAdjecentTiles(tile);
}
@Override
public List<DynmapChunk> getRequiredChunks(MapTile tile) {
return perspective.getRequiredChunks(tile);
}
@Override
public List<ZoomInfo> baseZoomFileInfo() {
ArrayList<ZoomInfo> s = new ArrayList<ZoomInfo>();
s.add(new ZoomInfo(prefix, getBackgroundARGBNight()));
if(lighting.isNightAndDayEnabled())
s.add(new ZoomInfo(prefix + "_day", getBackgroundARGBDay()));
return s;
}
public int baseZoomFileStepSize() { return 1; }
private static final int[] stepseq = { 3, 1, 2, 0 };
public MapStep zoomFileMapStep() { return MapStep.X_PLUS_Y_MINUS; }
public int[] zoomFileStepSequence() { return stepseq; }
/* How many bits of coordinate are shifted off to make big world directory name */
public int getBigWorldShift() { return 5; }
/* Returns true if big world file structure is in effect for this map */
@Override
public boolean isBigWorldMap(DynmapWorld w) { return true; } /* We always use it on these maps */
/* Return number of zoom levels needed by this map (before extra levels from extrazoomout) */
public int getMapZoomOutLevels() {
return mapzoomout;
}
@Override
public String getName() {
return name;
}
public String getPrefix() {
return prefix;
}
/* Get maps rendered concurrently with this map in this world */
public List<MapType> getMapsSharingRender(DynmapWorld w) {
ArrayList<MapType> maps = new ArrayList<MapType>();
for(MapType mt : w.maps) {
if(mt instanceof HDMap) {
HDMap hdmt = (HDMap)mt;
if(hdmt.perspective == this.perspective) { /* Same perspective */
maps.add(hdmt);
}
}
}
return maps;
}
/* Get names of maps rendered concurrently with this map type in this world */
public List<String> getMapNamesSharingRender(DynmapWorld w) {
ArrayList<String> lst = new ArrayList<String>();
for(MapType mt : w.maps) {
if(mt instanceof HDMap) {
HDMap hdmt = (HDMap)mt;
if(hdmt.perspective == this.perspective) { /* Same perspective */
if(hdmt.lighting.isNightAndDayEnabled())
lst.add(hdmt.getName() + "(night/day)");
else
lst.add(hdmt.getName());
}
}
}
return lst;
}
@Override
public ImageFormat getImageFormat() { return imgformat; }
@Override
public void buildClientConfiguration(JSONObject worldObject, DynmapWorld world) {
ConfigurationNode c = configuration;
JSONObject o = new JSONObject();
s(o, "type", "HDMapType");
s(o, "name", name);
s(o, "title", c.getString("title"));
s(o, "icon", c.getString("icon"));
s(o, "prefix", prefix);
s(o, "background", c.getString("background"));
s(o, "backgroundday", c.getString("backgroundday"));
s(o, "backgroundnight", c.getString("backgroundnight"));
s(o, "bigmap", true);
s(o, "mapzoomout", (world.getExtraZoomOutLevels()+mapzoomout));
s(o, "mapzoomin", c.getInteger("mapzoomin", 2));
s(o, "image-format", imgformat.getFileExt());
perspective.addClientConfiguration(o);
shader.addClientConfiguration(o);
lighting.addClientConfiguration(o);
a(worldObject, "maps", o);
}
private static int parseColor(String c) {
int v = 0;
if(c.startsWith("#")) {
c = c.substring(1);
if(c.length() == 3) { /* #rgb */
try {
v = Integer.valueOf(c, 16);
} catch (NumberFormatException nfx) {
return 0;
}
v = 0xFF000000 | ((v & 0xF00) << 12) | ((v & 0x0F0) << 8) | ((v & 0x00F) << 4);
}
else if(c.length() == 6) { /* #rrggbb */
try {
v = Integer.valueOf(c, 16);
} catch (NumberFormatException nfx) {
return 0;
}
v = 0xFF000000 | (v & 0xFFFFFF);
}
}
return v;
}
public int getBackgroundARGBDay() {
return bgcolorday;
}
public int getBackgroundARGBNight() {
return bgcolornight;
}
private HDMapTile fileToTile(DynmapWorld world, File f) {
String n = f.getName();
n = n.substring(0, n.lastIndexOf('.'));
if(n == null) return null;
String[] nt = n.split("_");
if(nt.length != 2) return null;
int xx, zz;
try {
xx = Integer.parseInt(nt[0]);
zz = Integer.parseInt(nt[1]);
} catch (NumberFormatException nfx) {
return null;
}
return new HDMapTile(world, perspective, xx, zz);
}
public void purgeOldTiles(final DynmapWorld world, final TileFlags rendered) {
File basedir = new File(world.worldtilepath, prefix); /* Get base directory for map */
FileCallback cb = new FileCallback() {
public void fileFound(File f, File parent, boolean day) {
String n = f.getName();
if(n.startsWith("z")) { /* If zoom file */
if(n.startsWith("z_")) { /* First tier of zoom? */
File ff = new File(parent, n.substring(2)); /* Make file for render tier, and drive update */
HDMapTile tile = fileToTile(world, ff); /* Parse it */
if(tile == null) return;
if(rendered.getFlag(tile.tx, tile.ty) || rendered.getFlag(tile.tx+1, tile.ty) ||
rendered.getFlag(tile.tx, tile.ty-1) || rendered.getFlag(tile.tx+1, tile.ty-1))
return;
world.enqueueZoomOutUpdate(ff);
}
return;
}
HDMapTile tile = fileToTile(world, f);
if(tile == null) return;
if(rendered.getFlag(tile.tx, tile.ty)) { /* If we rendered this tile, its good */
return;
}
Debug.debug("clean up " + f.getPath());
/* Otherwise, delete tile */
f.delete();
/* Push updates, clear hash code, and signal zoom tile update */
MapManager.mapman.pushUpdate(world,
new Client.Tile(day?tile.getDayFilename(prefix, getImageFormat()):tile.getFilename(prefix, getImageFormat())));
MapManager.mapman.hashman.updateHashCode(tile.getKey(prefix), day?"day":null, tile.tx, tile.ty, -1);
world.enqueueZoomOutUpdate(f);
}
};
walkMapTree(basedir, cb, false);
if(lighting.isNightAndDayEnabled()) {
basedir = new File(world.worldtilepath, prefix+"_day");
walkMapTree(basedir, cb, true);
}
}
}

View file

@ -1,181 +0,0 @@
package org.dynmap.hdmap;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import org.dynmap.ConfigurationNode;
import org.dynmap.DynmapCore;
import org.dynmap.DynmapWorld;
import org.dynmap.Log;
import org.dynmap.MapManager;
import org.dynmap.MapType;
import org.dynmap.utils.MapChunkCache;
import org.dynmap.utils.MapIterator;
public class HDMapManager {
public HashMap<String, HDShader> shaders = new HashMap<String, HDShader>();
public HashMap<String, HDPerspective> perspectives = new HashMap<String, HDPerspective>();
public HashMap<String, HDLighting> lightings = new HashMap<String, HDLighting>();
public HashSet<HDMap> maps = new HashSet<HDMap>();
public HashMap<String, ArrayList<HDMap>> maps_by_world_perspective = new HashMap<String, ArrayList<HDMap>>();
public static boolean usegeneratedtextures;
public static boolean waterlightingfix;
public static boolean biomeshadingfix;
public void loadHDShaders(DynmapCore core) {
Log.verboseinfo("Loading shaders...");
File f = new File(core.getDataFolder(), "shaders.txt");
if(!core.updateUsingDefaultResource("/shaders.txt", f, "shaders")) {
return;
}
ConfigurationNode shadercfg = new ConfigurationNode(f);
shadercfg.load();
for(HDShader shader : shadercfg.<HDShader>createInstances("shaders", new Class<?>[] { DynmapCore.class }, new Object[] { core })) {
if(shader.getName() == null) continue;
shaders.put(shader.getName(), shader);
}
/* Load custom shaders, if file is defined - or create empty one if not */
f = new File(core.getDataFolder(), "custom-shaders.txt");
core.createDefaultFileFromResource("/custom-shaders.txt", f);
if(f.exists()) {
ConfigurationNode customshadercfg = new ConfigurationNode(f);
customshadercfg.load();
for(HDShader shader : customshadercfg.<HDShader>createInstances("shaders", new Class<?>[] { DynmapCore.class }, new Object[] { core })) {
if(shader.getName() == null) continue;
shaders.put(shader.getName(), shader);
}
}
Log.info("Loaded " + shaders.size() + " shaders.");
/* Update ore mappings, if needed */
TexturePack.handleHideOres();
}
public void loadHDPerspectives(DynmapCore core) {
Log.verboseinfo("Loading perspectives...");
File f = new File(core.getDataFolder(), "perspectives.txt");
if(!core.updateUsingDefaultResource("/perspectives.txt", f, "perspectives")) {
return;
}
ConfigurationNode perspectivecfg = new ConfigurationNode(f);
perspectivecfg.load();
for(HDPerspective perspective : perspectivecfg.<HDPerspective>createInstances("perspectives", new Class<?>[] { DynmapCore.class }, new Object[] { core })) {
if(perspective.getName() == null) continue;
perspectives.put(perspective.getName(), perspective);
}
/* Load custom perspectives, if file is defined - or create empty one if not */
f = new File(core.getDataFolder(), "custom-perspectives.txt");
core.createDefaultFileFromResource("/custom-perspectives.txt", f);
if(f.exists()) {
perspectivecfg = new ConfigurationNode(f);
perspectivecfg.load();
for(HDPerspective perspective : perspectivecfg.<HDPerspective>createInstances("perspectives", new Class<?>[] { DynmapCore.class }, new Object[] { core })) {
if(perspective.getName() == null) continue;
perspectives.put(perspective.getName(), perspective);
}
}
Log.info("Loaded " + perspectives.size() + " perspectives.");
}
public void loadHDLightings(DynmapCore core) {
Log.verboseinfo("Loading lightings...");
File f = new File(core.getDataFolder(), "lightings.txt");
if(!core.updateUsingDefaultResource("/lightings.txt", f, "lightings")) {
return;
}
ConfigurationNode lightingcfg = new ConfigurationNode(f);
lightingcfg.load();
for(HDLighting lighting : lightingcfg.<HDLighting>createInstances("lightings", new Class<?>[] { DynmapCore.class }, new Object[] { core })) {
if(lighting.getName() == null) continue;
lightings.put(lighting.getName(), lighting);
}
/* Load custom lightings, if file is defined - or create empty one if not */
f = new File(core.getDataFolder(), "custom-lightings.txt");
core.createDefaultFileFromResource("/custom-lightings.txt", f);
if(f.exists()) {
lightingcfg = new ConfigurationNode(f);
lightingcfg.load();
for(HDLighting lighting : lightingcfg.<HDLighting>createInstances("lightings", new Class<?>[] { DynmapCore.class }, new Object[] { core })) {
if(lighting.getName() == null) continue;
lightings.put(lighting.getName(), lighting);
}
}
Log.info("Loaded " + lightings.size() + " lightings.");
}
/**
* Initialize shader states for all shaders for given tile
*/
public HDShaderState[] getShaderStateForTile(HDMapTile tile, MapChunkCache cache, MapIterator mapiter, String mapname) {
DynmapWorld w = MapManager.mapman.worldsLookup.get(tile.getDynmapWorld().getName());
if(w == null) return new HDShaderState[0];
ArrayList<HDShaderState> shaders = new ArrayList<HDShaderState>();
for(MapType map : w.maps) {
if(map instanceof HDMap) {
HDMap hdmap = (HDMap)map;
if(hdmap.getPerspective() == tile.perspective) {
/* If limited to one map, and this isn't it, skip */
if((mapname != null) && (!hdmap.getName().equals(mapname)))
continue;
shaders.add(hdmap.getShader().getStateInstance(hdmap, cache, mapiter));
}
}
}
return shaders.toArray(new HDShaderState[shaders.size()]);
}
private static final int BIOMEDATAFLAG = 0;
private static final int HIGHESTZFLAG = 1;
private static final int RAWBIOMEFLAG = 2;
private static final int BLOCKTYPEFLAG = 3;
public boolean isBiomeDataNeeded(HDMapTile t) {
return getCachedFlags(t)[BIOMEDATAFLAG];
}
public boolean isHightestBlockYDataNeeded(HDMapTile t) {
return getCachedFlags(t)[HIGHESTZFLAG];
}
public boolean isRawBiomeDataNeeded(HDMapTile t) {
return getCachedFlags(t)[RAWBIOMEFLAG];
}
public boolean isBlockTypeDataNeeded(HDMapTile t) {
return getCachedFlags(t)[BLOCKTYPEFLAG];
}
private HashMap<String, boolean[]> cached_data_flags_by_world_perspective = new HashMap<String, boolean[]>();
private boolean[] getCachedFlags(HDMapTile t) {
String w = t.getDynmapWorld().getName();
String k = w + "/" + t.perspective.getName();
boolean[] flags = cached_data_flags_by_world_perspective.get(k);
if(flags != null)
return flags;
flags = new boolean[4];
cached_data_flags_by_world_perspective.put(k, flags);
DynmapWorld dw = MapManager.mapman.worldsLookup.get(w);
if(dw == null) return flags;
for(MapType map : dw.maps) {
if(map instanceof HDMap) {
HDMap hdmap = (HDMap)map;
if(hdmap.getPerspective() == t.perspective) {
HDShader sh = hdmap.getShader();
HDLighting lt = hdmap.getLighting();
flags[BIOMEDATAFLAG] |= sh.isBiomeDataNeeded() | lt.isBiomeDataNeeded();
flags[HIGHESTZFLAG] |= sh.isHightestBlockYDataNeeded() | lt.isHightestBlockYDataNeeded();
flags[RAWBIOMEFLAG] |= sh.isRawBiomeDataNeeded() | lt.isRawBiomeDataNeeded();
flags[BLOCKTYPEFLAG] |= sh.isBlockTypeDataNeeded() | lt.isBlockTypeDataNeeded();
}
}
}
return flags;
}
}

View file

@ -1,110 +0,0 @@
package org.dynmap.hdmap;
import org.dynmap.DynmapChunk;
import org.dynmap.DynmapWorld;
import org.dynmap.MapManager;
import org.dynmap.MapType;
import java.util.List;
import org.dynmap.MapTile;
import org.dynmap.utils.MapChunkCache;
public class HDMapTile extends MapTile {
public HDPerspective perspective;
public int tx, ty; /* Tile X and Tile Y are in tile coordinates (pixels/tile-size) */
public HDMapTile(DynmapWorld world, HDPerspective perspective, int tx, int ty) {
super(world);
this.perspective = perspective;
this.tx = tx;
this.ty = ty;
}
public HDMapTile(DynmapWorld world, String parm) throws Exception {
super(world);
String[] parms = parm.split(",");
if(parms.length < 3) throw new Exception("wrong parameter count");
this.tx = Integer.parseInt(parms[0]);
this.ty = Integer.parseInt(parms[1]);
this.perspective = MapManager.mapman.hdmapman.perspectives.get(parms[2]);
if(this.perspective == null) throw new Exception("invalid perspective");
}
@Override
protected String saveTileData() {
return String.format("%d,%d,%s", tx, ty, perspective.getName());
}
@Override
public String getFilename() {
return getFilename("hdmap", MapType.ImageFormat.FORMAT_PNG);
}
public String getFilename(String prefix, MapType.ImageFormat format) {
return prefix + "/" + (tx >> 5) + '_' + (ty >> 5) + '/' + tx + "_" + ty + "." + format.getFileExt();
}
@Override
public String getDayFilename() {
return getDayFilename("hdmap", MapType.ImageFormat.FORMAT_PNG);
}
public String getDayFilename(String prefix, MapType.ImageFormat format) {
return prefix + "_day/" + (tx >> 5) + '_' + (ty >> 5) + '/' + tx + "_" + ty + "." + format.getFileExt();
}
@Override
public int hashCode() {
return tx ^ ty ^ perspective.getName().hashCode() ^ world.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof HDMapTile) {
return equals((HDMapTile) obj);
}
return false;
}
public boolean equals(HDMapTile o) {
return o.tx == tx && o.ty == ty && (perspective == o.perspective) && (o.world == world);
}
public String getKey(String prefix) {
return world.getName() + "." + prefix;
}
@Override
public String toString() {
return world.getName() + ":" + getFilename();
}
@Override
public boolean isBiomeDataNeeded() { return MapManager.mapman.hdmapman.isBiomeDataNeeded(this); }
@Override
public boolean isHightestBlockYDataNeeded() { return MapManager.mapman.hdmapman.isHightestBlockYDataNeeded(this); }
@Override
public boolean isRawBiomeDataNeeded() { return MapManager.mapman.hdmapman.isRawBiomeDataNeeded(this); }
@Override
public boolean isBlockTypeDataNeeded() { return MapManager.mapman.hdmapman.isBlockTypeDataNeeded(this); }
public boolean render(MapChunkCache cache, String mapname) {
return perspective.render(cache, this, mapname);
}
public List<DynmapChunk> getRequiredChunks() {
return perspective.getRequiredChunks(this);
}
public MapTile[] getAdjecentTiles() {
return perspective.getAdjecentTiles(this);
}
public int tileOrdinalX() { return tx; }
public int tileOrdinalY() { return ty; }
}

View file

@ -1,34 +0,0 @@
package org.dynmap.hdmap;
import java.util.List;
import org.dynmap.DynmapChunk;
import org.dynmap.DynmapWorld;
import org.dynmap.MapTile;
import org.dynmap.utils.MapChunkCache;
import org.json.simple.JSONObject;
public interface HDPerspective {
/* Get name of perspective */
String getName();
/* Get tiles invalidated by change at given location */
MapTile[] getTiles(DynmapWorld w, int x, int y, int z);
/* Get tiles invalidated by change at given volume, defined by 2 opposite corner locations */
MapTile[] getTiles(DynmapWorld w, int minx, int miny, int minz, int maxx, int maxy, int maxz);
/* Get tiles adjacent to given tile */
MapTile[] getAdjecentTiles(MapTile tile);
/* Get chunks needed for given tile */
List<DynmapChunk> getRequiredChunks(MapTile tile);
/* Render given tile */
boolean render(MapChunkCache cache, HDMapTile tile, String mapname);
public boolean isBiomeDataNeeded();
public boolean isHightestBlockYDataNeeded();
public boolean isRawBiomeDataNeeded();
public boolean isBlockTypeDataNeeded();
double getScale();
int getModelScale();
public void addClientConfiguration(JSONObject mapObject);
}

View file

@ -1,64 +0,0 @@
package org.dynmap.hdmap;
import org.dynmap.utils.MapIterator;
import org.dynmap.utils.MapIterator.BlockStep;
import org.dynmap.utils.Vector3D;
public interface HDPerspectiveState {
/**
* Get sky light level - only available if shader requested it
*/
int getSkyLightLevel();
/**
* Get emitted light level - only available if shader requested it
*/
int getEmittedLightLevel();
/**
* Get current block type ID
*/
int getBlockTypeID();
/**
* Get current block data
*/
int getBlockData();
/**
* Get current block render data
*/
int getBlockRenderData();
/**
* Get direction of last block step
*/
BlockStep getLastBlockStep();
/**
* Get perspective scale
*/
double getScale();
/**
* Get start of current ray, in world coordinates
*/
Vector3D getRayStart();
/**
* Get end of current ray, in world coordinates
*/
Vector3D getRayEnd();
/**
* Get pixel X coordinate
*/
int getPixelX();
/**
* Get pixel Y coordinate
*/
int getPixelY();
/**
* Return submodel alpha value (-1 if no submodel rendered)
*/
int getSubmodelAlpha();
/**
* Return subblock coordinates of current ray position
*/
int[] getSubblockCoord();
/**
* Get map iterator
*/
MapIterator getMapIterator();
}

View file

@ -1,34 +0,0 @@
package org.dynmap.hdmap;
import org.dynmap.utils.MapChunkCache;
import org.dynmap.utils.MapIterator;
import org.json.simple.JSONObject;
public interface HDShader {
/* Get shader name */
String getName();
/**
* Get renderer state object for use rendering a tile
* @param map - map being rendered
* @param cache - chunk cache containing data for tile to be rendered
* @param mapiter - iterator used when traversing rays in tile
* @return state object to use for all rays in tile
*/
HDShaderState getStateInstance(HDMap map, MapChunkCache cache, MapIterator mapiter);
/* Test if Biome Data is needed for this renderer */
boolean isBiomeDataNeeded();
/* Test if raw biome temperature/rainfall data is needed */
boolean isRawBiomeDataNeeded();
/* Test if highest block Y data is needed */
boolean isHightestBlockYDataNeeded();
/* Tet if block type data needed */
boolean isBlockTypeDataNeeded();
/* Test if sky light level needed */
boolean isSkyLightLevelNeeded();
/* Test if emitted light level needed */
boolean isEmittedLightLevelNeeded();
/* Add shader's contributions to JSON for map object */
void addClientConfiguration(JSONObject mapObject);
}

View file

@ -1,45 +0,0 @@
package org.dynmap.hdmap;
import org.dynmap.Color;
/**
* This interface is used to define the operational state of a renderer during raytracing
* All method should be considered performance critical
*/
public interface HDShaderState {
/**
* Get our shader
*/
HDShader getShader();
/**
* Get our lighting
*/
HDLighting getLighting();
/**
* Get our map
*/
HDMap getMap();
/**
* Reset renderer state for new ray - passes in pixel coordinate for ray
*/
void reset(HDPerspectiveState ps);
/**
* Process next ray step - called for each block on route
* @return true if ray is done, false if ray needs to continue
*/
boolean processBlock(HDPerspectiveState ps);
/**
* Ray ended - used to report that ray has exited map (called if renderer has not reported complete)
*/
void rayFinished(HDPerspectiveState ps);
/**
* Get result color - get resulting color for ray
* @param c - object to store color value in
* @param index - index of color to request (renderer specific - 0=default, 1=day for night/day renderer
*/
void getRayColor(Color c, int index);
/**
* Clean up state object - called after last ray completed
*/
void cleanup();
}

File diff suppressed because it is too large Load diff

View file

@ -1,97 +0,0 @@
package org.dynmap.hdmap;
import org.dynmap.Color;
import org.dynmap.ConfigurationNode;
import org.dynmap.DynmapCore;
import org.dynmap.Log;
public class ShadowHDLighting extends DefaultHDLighting {
protected int shadowscale[]; /* index=skylight level, value = 256 * scaling value */
protected int lightscale[]; /* scale skylight level (light = lightscale[skylight] */
protected boolean night_and_day; /* If true, render both day (prefix+'-day') and night (prefix) tiles */
public ShadowHDLighting(DynmapCore core, ConfigurationNode configuration) {
super(core, configuration);
double shadowweight = configuration.getDouble("shadowstrength", 0.0);
if(shadowweight > 0.0) {
shadowscale = new int[16];
shadowscale[15] = 256;
/* Normal brightness weight in MC is a 20% relative dropoff per step */
for(int i = 14; i >= 0; i--) {
double v = shadowscale[i+1] * (1.0 - (0.2 * shadowweight));
shadowscale[i] = (int)v;
if(shadowscale[i] > 256) shadowscale[i] = 256;
if(shadowscale[i] < 0) shadowscale[i] = 0;
}
}
int v = configuration.getInteger("ambientlight", -1);
if((v >= 0) && (v < 15)) {
lightscale = new int[16];
for(int i = 0; i < 16; i++) {
if(i < (15-v))
lightscale[i] = 0;
else
lightscale[i] = i - (15-v);
}
}
night_and_day = configuration.getBoolean("night-and-day", false);
if(night_and_day) {
if(lightscale == null) {
Log.severe("night-and-day in lighting '" + getName() + "' requires ambientlight<15");
night_and_day = false;
}
}
}
/* Apply lighting to given pixel colors (1 outcolor if normal, 2 if night/day) */
public void applyLighting(HDPerspectiveState ps, HDShaderState ss, Color incolor, Color[] outcolor) {
int lightlevel = 15, lightlevel_day = 15;
/* If processing for shadows, use sky light level as base lighting */
if(shadowscale != null) {
lightlevel = lightlevel_day = ps.getSkyLightLevel();
}
/* If ambient light, adjust base lighting for it */
if(lightscale != null)
lightlevel = lightscale[lightlevel];
/* If we're below max, see if emitted light helps */
if((lightlevel < 15) || (lightlevel_day < 15)) {
int emitted = ps.getEmittedLightLevel();
lightlevel = Math.max(emitted, lightlevel);
lightlevel_day = Math.max(emitted, lightlevel_day);
}
/* Figure out our color, with lighting if needed */
outcolor[0].setColor(incolor);
if(lightlevel < 15) {
shadowColor(outcolor[0], lightlevel);
}
if(outcolor.length > 1) {
if(lightlevel_day == lightlevel) {
outcolor[1].setColor(outcolor[0]);
}
else {
outcolor[1].setColor(incolor);
if(lightlevel_day < 15) {
shadowColor(outcolor[1], lightlevel_day);
}
}
}
}
private final void shadowColor(Color c, int lightlevel) {
int scale = shadowscale[lightlevel];
if(scale < 256)
c.setRGBA((c.getRed() * scale) >> 8, (c.getGreen() * scale) >> 8,
(c.getBlue() * scale) >> 8, c.getAlpha());
}
/* Test if night/day is enabled for this renderer */
public boolean isNightAndDayEnabled() { return night_and_day; }
/* Test if sky light level needed */
public boolean isSkyLightLevelNeeded() { return (shadowscale != null); }
/* Test if emitted light level needed */
public boolean isEmittedLightLevelNeeded() { return (shadowscale != null) || (lightscale != null); }
}

File diff suppressed because it is too large Load diff

View file

@ -1,240 +0,0 @@
package org.dynmap.hdmap;
import static org.dynmap.JSONUtils.s;
import org.dynmap.Color;
import org.dynmap.ConfigurationNode;
import org.dynmap.DynmapCore;
import org.dynmap.Log;
import org.dynmap.MapManager;
import org.dynmap.utils.MapChunkCache;
import org.dynmap.utils.MapIterator;
import org.json.simple.JSONObject;
public class TexturePackHDShader implements HDShader {
private String tpname;
private String name;
private TexturePack tp;
private boolean biome_shaded;
private boolean swamp_shaded;
private boolean waterbiomeshaded;
private boolean bettergrass;
public TexturePackHDShader(DynmapCore core, ConfigurationNode configuration) {
tpname = configuration.getString("texturepack", "minecraft");
name = configuration.getString("name", tpname);
tp = TexturePack.getTexturePack(core, tpname);
biome_shaded = configuration.getBoolean("biomeshaded", true);
swamp_shaded = configuration.getBoolean("swampshaded", MapManager.mapman.getSwampShading());
waterbiomeshaded = configuration.getBoolean("waterbiomeshaded", MapManager.mapman.getWaterBiomeShading());
bettergrass = configuration.getBoolean("better-grass", MapManager.mapman.getBetterGrass());
if(tp == null) {
Log.severe("Error: shader '" + name + "' cannot load texture pack '" + tpname + "'");
}
}
@Override
public boolean isBiomeDataNeeded() {
return swamp_shaded;
}
@Override
public boolean isRawBiomeDataNeeded() {
return biome_shaded;
}
@Override
public boolean isHightestBlockYDataNeeded() {
return false;
}
@Override
public boolean isBlockTypeDataNeeded() {
return true;
}
@Override
public boolean isSkyLightLevelNeeded() {
return false;
}
@Override
public boolean isEmittedLightLevelNeeded() {
return false;
}
@Override
public String getName() {
return name;
}
class ShaderState implements HDShaderState {
private Color color[];
private Color tmpcolor[];
private Color c;
protected MapIterator mapiter;
protected HDMap map;
private TexturePack scaledtp;
private HDLighting lighting;
private int lastblkid;
boolean do_biome_shading;
boolean do_swamp_shading;
boolean do_water_shading;
boolean do_better_grass;
private ShaderState(MapIterator mapiter, HDMap map, MapChunkCache cache) {
this.mapiter = mapiter;
this.map = map;
this.lighting = map.getLighting();
if(lighting.isNightAndDayEnabled()) {
color = new Color[] { new Color(), new Color() };
tmpcolor = new Color[] { new Color(), new Color() };
}
else {
color = new Color[] { new Color() };
tmpcolor = new Color[] { new Color() };
}
c = new Color();
scaledtp = tp.resampleTexturePack(map.getPerspective().getModelScale());
/* Biome raw data only works on normal worlds at this point */
do_biome_shading = biome_shaded; // && (cache.getWorld().getEnvironment() == Environment.NORMAL);
do_swamp_shading = do_biome_shading && swamp_shaded;
do_water_shading = do_biome_shading && waterbiomeshaded;
do_better_grass = bettergrass;
}
/**
* Get our shader
*/
public HDShader getShader() {
return TexturePackHDShader.this;
}
/**
* Get our map
*/
public HDMap getMap() {
return map;
}
/**
* Get our lighting
*/
public HDLighting getLighting() {
return lighting;
}
/**
* Reset renderer state for new ray
*/
public void reset(HDPerspectiveState ps) {
for(int i = 0; i < color.length; i++)
color[i].setTransparent();
lastblkid = 0;
}
/**
* Process next ray step - called for each block on route
* @return true if ray is done, false if ray needs to continue
*/
public boolean processBlock(HDPerspectiveState ps) {
int blocktype = ps.getBlockTypeID();
int lastblocktype = lastblkid;
lastblkid = blocktype;
if(blocktype == 0) {
return false;
}
/* Get color from textures */
scaledtp.readColor(ps, mapiter, c, blocktype, lastblocktype, ShaderState.this);
if (c.getAlpha() > 0) {
/* Scale brightness depending upon face */
switch(ps.getLastBlockStep()) {
case X_MINUS:
case X_PLUS:
/* 60% brightness */
c.blendColor(0xFFA0A0A0);
break;
case Y_MINUS:
case Y_PLUS:
/* 85% brightness for even, 90% for even*/
if((mapiter.getY() & 0x01) == 0)
c.blendColor(0xFFD9D9D9);
else
c.blendColor(0xFFE6E6E6);
break;
}
/* Handle light level, if needed */
lighting.applyLighting(ps, this, c, tmpcolor);
/* If we got alpha from subblock model, use it instead if it is lower */
/* (disable for now: weighting is wrong, as crosssection is 2D, not 3D based) */
// if(subalpha >= 0) {
// for(Color clr : tmpcolor) {
// int a = clr.getAlpha();
// if(subalpha < a)
// clr.setAlpha(subalpha);
// }
// }
/* If no previous color contribution, use new color */
if(color[0].isTransparent()) {
for(int i = 0; i < color.length; i++)
color[i].setColor(tmpcolor[i]);
return (color[0].getAlpha() == 255);
}
/* Else, blend and generate new alpha */
else {
int alpha = color[0].getAlpha();
int alpha2 = tmpcolor[0].getAlpha() * (255-alpha) / 255;
int talpha = alpha + alpha2;
if(talpha > 0)
for(int i = 0; i < color.length; i++)
color[i].setRGBA((tmpcolor[i].getRed()*alpha2 + color[i].getRed()*alpha) / talpha,
(tmpcolor[i].getGreen()*alpha2 + color[i].getGreen()*alpha) / talpha,
(tmpcolor[i].getBlue()*alpha2 + color[i].getBlue()*alpha) / talpha, talpha);
else
for(int i = 0; i < color.length; i++)
color[i].setTransparent();
return (talpha >= 254); /* If only one short, no meaningful contribution left */
}
}
return false;
}
/**
* Ray ended - used to report that ray has exited map (called if renderer has not reported complete)
*/
public void rayFinished(HDPerspectiveState ps) {
}
/**
* Get result color - get resulting color for ray
* @param c - object to store color value in
* @param index - index of color to request (renderer specific - 0=default, 1=day for night/day renderer
*/
public void getRayColor(Color c, int index) {
c.setColor(color[index]);
}
/**
* Clean up state object - called after last ray completed
*/
public void cleanup() {
}
}
/**
* Get renderer state object for use rendering a tile
* @param map - map being rendered
* @param cache - chunk cache containing data for tile to be rendered
* @param mapiter - iterator used when traversing rays in tile
* @return state object to use for all rays in tile
*/
public HDShaderState getStateInstance(HDMap map, MapChunkCache cache, MapIterator mapiter) {
return new ShaderState(mapiter, map, cache);
}
/* Add shader's contributions to JSON for map object */
public void addClientConfiguration(JSONObject mapObject) {
s(mapObject, "shader", name);
}
}

View file

@ -1,235 +0,0 @@
package org.dynmap.hdmap;
import static org.dynmap.JSONUtils.s;
import org.dynmap.Color;
import org.dynmap.ConfigurationNode;
import org.dynmap.DynmapCore;
import org.dynmap.Log;
import org.dynmap.utils.MapChunkCache;
import org.dynmap.utils.MapIterator;
import org.dynmap.utils.MapIterator.BlockStep;
import org.json.simple.JSONObject;
public class TopoHDShader implements HDShader {
private String name;
private Color linecolor; /* Color for topo lines */
private Color fillcolor[]; /* Color for nontopo surfaces */
private Color watercolor;
private Color readColor(String id, ConfigurationNode cfg) {
String lclr = cfg.getString(id, null);
if((lclr != null) && (lclr.startsWith("#"))) {
try {
int c = Integer.parseInt(lclr.substring(1), 16);
return new Color((c>>16)&0xFF, (c>>8)&0xFF, c&0xFF);
} catch (NumberFormatException nfx) {
Log.severe("Invalid color value: " + lclr + " for '" + id + "'");
}
}
return null;
}
public TopoHDShader(DynmapCore core, ConfigurationNode configuration) {
name = (String) configuration.get("name");
fillcolor = new Color[128]; /* Color by Y */
/* Load defined colors from parameters */
for(int i = 0; i < 128; i++) {
fillcolor[i] = readColor("color" + i, configuration);
}
linecolor = readColor("linecolor", configuration);
watercolor = readColor("watercolor", configuration);
/* Now, interpolate missing colors */
if(fillcolor[0] == null) {
fillcolor[0] = new Color(0, 0, 0);
}
if(fillcolor[127] == null) {
fillcolor[127] = new Color(255, 255, 255);
}
int starty = 0;
for(int i = 1; i < 128; i++) {
if(fillcolor[i] != null) { /* Found color? */
int delta = i - starty;
Color c0 = fillcolor[starty];
Color c1 = fillcolor[i];
/* Interpolate missing colors since last one */
for(int j = 1; j < delta; j++) {
fillcolor[starty + j] = new Color((c0.getRed()*(delta-j) + c1.getRed()*j)/delta, (c0.getGreen()*(delta-j) + c1.getGreen()*j)/delta, (c0.getBlue()*(delta-j) + c1.getBlue()*j)/delta);
}
starty = i; /* New start color */
}
}
}
@Override
public boolean isBiomeDataNeeded() {
return false;
}
@Override
public boolean isRawBiomeDataNeeded() {
return false;
}
@Override
public boolean isHightestBlockYDataNeeded() {
return false;
}
@Override
public boolean isBlockTypeDataNeeded() {
return true;
}
@Override
public boolean isSkyLightLevelNeeded() {
return false;
}
@Override
public boolean isEmittedLightLevelNeeded() {
return false;
}
@Override
public String getName() {
return name;
}
private class OurShaderState implements HDShaderState {
private Color color[];
private Color tmpcolor[];
private Color c;
protected MapIterator mapiter;
protected HDMap map;
private HDLighting lighting;
private int scale;
private OurShaderState(MapIterator mapiter, HDMap map, MapChunkCache cache) {
this.mapiter = mapiter;
this.map = map;
this.lighting = map.getLighting();
if(lighting.isNightAndDayEnabled()) {
color = new Color[] { new Color(), new Color() };
tmpcolor = new Color[] { new Color(), new Color() };
}
else {
color = new Color[] { new Color() };
tmpcolor = new Color[] { new Color() };
}
scale = (int)map.getPerspective().getScale();
c = new Color();
}
/**
* Get our shader
*/
public HDShader getShader() {
return TopoHDShader.this;
}
/**
* Get our map
*/
public HDMap getMap() {
return map;
}
/**
* Get our lighting
*/
public HDLighting getLighting() {
return lighting;
}
/**
* Reset renderer state for new ray
*/
public void reset(HDPerspectiveState ps) {
for(int i = 0; i < color.length; i++)
color[i].setTransparent();
}
/**
* Process next ray step - called for each block on route
* @return true if ray is done, false if ray needs to continue
*/
public boolean processBlock(HDPerspectiveState ps) {
int blocktype = ps.getBlockTypeID();
if(blocktype == 0) {
return false;
}
/* See if we're close to an edge */
int[] xyz = ps.getSubblockCoord();
/* See which face we're on (only do lines on top face) */
switch(ps.getLastBlockStep()) {
case Y_MINUS:
case Y_PLUS:
if((linecolor != null) &&
(((xyz[0] == 0) && (mapiter.getBlockTypeIDAt(BlockStep.X_MINUS) == 0)) ||
((xyz[0] == (scale-1)) && (mapiter.getBlockTypeIDAt(BlockStep.X_PLUS) == 0)) ||
((xyz[2] == 0) && (mapiter.getBlockTypeIDAt(BlockStep.Z_MINUS) == 0)) ||
((xyz[2] == (scale-1)) && (mapiter.getBlockTypeIDAt(BlockStep.Z_PLUS) == 0)))) {
c.setColor(linecolor);
}
else if((watercolor != null) && ((blocktype == 8) || (blocktype == 9))) {
c.setColor(watercolor);
}
else {
c.setColor(fillcolor[mapiter.getY()]);
}
break;
default:
if((linecolor != null) && (xyz[1] == (scale-1)))
c.setColor(linecolor);
else if((watercolor != null) && ((blocktype == 8) || (blocktype == 9))) {
c.setColor(watercolor);
}
else
c.setColor(fillcolor[mapiter.getY()]);
break;
}
/* Handle light level, if needed */
lighting.applyLighting(ps, this, c, tmpcolor);
for(int i = 0; i < color.length; i++)
color[i] = tmpcolor[i];
return true;
}
/**
* Ray ended - used to report that ray has exited map (called if renderer has not reported complete)
*/
public void rayFinished(HDPerspectiveState ps) {
}
/**
* Get result color - get resulting color for ray
* @param c - object to store color value in
* @param index - index of color to request (renderer specific - 0=default, 1=day for night/day renderer
*/
public void getRayColor(Color c, int index) {
c.setColor(color[index]);
}
/**
* Clean up state object - called after last ray completed
*/
public void cleanup() {
}
}
/**
* Get renderer state object for use rendering a tile
* @param map - map being rendered
* @param cache - chunk cache containing data for tile to be rendered
* @param mapiter - iterator used when traversing rays in tile
* @return state object to use for all rays in tile
*/
public HDShaderState getStateInstance(HDMap map, MapChunkCache cache, MapIterator mapiter) {
return new OurShaderState(mapiter, map, cache);
}
/* Add shader's contributions to JSON for map object */
public void addClientConfiguration(JSONObject mapObject) {
s(mapObject, "shader", name);
}
}

View file

@ -1,113 +0,0 @@
package org.dynmap.kzedmap;
import org.dynmap.Color;
import org.dynmap.ConfigurationNode;
import org.dynmap.DynmapCore;
import org.dynmap.DynmapWorld;
import org.dynmap.utils.MapIterator;
import org.dynmap.utils.MapIterator.BlockStep;
public class CaveTileRenderer extends DefaultTileRenderer {
private boolean iflit;
public CaveTileRenderer(DynmapCore core, ConfigurationNode configuration) {
super(core, configuration);
iflit = configuration.getBoolean("onlyiflit", false);
}
public boolean isNightAndDayEnabled() { return false; }
@Override
protected void scan(DynmapWorld world, int seq, boolean isnether, final Color result, final Color result_day,
MapIterator mapiter) {
boolean air = true;
int emitted = 0;
result.setTransparent();
for (;;) {
if (mapiter.getY() < 0)
return;
int id = mapiter.getBlockTypeID();
if(isnether) { /* Make ceiling into air in nether */
if(id != 0)
id = 0;
else
isnether = false;
}
if(iflit && (!air))
emitted = mapiter.getBlockEmittedLight();
switch (seq) {
case 0:
mapiter.stepPosition(BlockStep.X_MINUS);
break;
case 1:
case 3:
mapiter.stepPosition(BlockStep.Y_MINUS);
break;
case 2:
mapiter.stepPosition(BlockStep.Z_PLUS);
break;
}
seq = (seq + 1) & 3;
switch (id) {
case 17:
case 18:
case 20:
case 64:
case 71:
case 78:
case 79:
id = 0;
break;
default:
}
if (id != 0) {
air = false;
continue;
}
if (id == 0 && !air) {
if(iflit && (emitted == 0)) {
continue;
}
int cr, cg, cb;
int mult = 256;
if (mapiter.getY() < 64) {
cr = 0;
cg = 64 + mapiter.getY() * 3;
cb = 255 - mapiter.getY() * 4;
} else {
cr = (mapiter.getY() - 64) * 4;
cg = 255;
cb = 0;
}
switch (seq) {
case 0:
mult = 224;
break;
case 1:
mult = 256;
break;
case 2:
mult = 192;
break;
case 3:
mult = 160;
break;
}
cr = cr * mult / 256;
cg = cg * mult / 256;
cb = cb * mult / 256;
result.setRGBA(cr, cg, cb, 255);
return;
}
}
}
}

View file

@ -1,596 +0,0 @@
package org.dynmap.kzedmap;
import static org.dynmap.JSONUtils.a;
import static org.dynmap.JSONUtils.s;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import javax.imageio.ImageIO;
import org.dynmap.Client;
import org.dynmap.Color;
import org.dynmap.ColorScheme;
import org.dynmap.ConfigurationNode;
import org.dynmap.DynmapCore;
import org.dynmap.DynmapWorld;
import org.dynmap.MapManager;
import org.dynmap.DynmapCore.CompassMode;
import org.dynmap.MapType.ImageFormat;
import org.dynmap.TileHashManager;
import org.dynmap.common.BiomeMap;
import org.dynmap.debug.Debug;
import org.dynmap.utils.DynmapBufferedImage;
import org.dynmap.utils.FileLockManager;
import org.dynmap.utils.MapChunkCache;
import org.dynmap.utils.MapIterator;
import org.dynmap.utils.MapIterator.BlockStep;
import org.json.simple.JSONObject;
public class DefaultTileRenderer implements MapTileRenderer {
protected static final Color translucent = new Color(0, 0, 0, 0);
protected String name;
protected String prefix;
protected ConfigurationNode configuration;
protected int maximumHeight = 127;
protected ColorScheme colorScheme;
protected HashSet<Integer> highlightBlocks = new HashSet<Integer>();
protected Color highlightColor = new Color(255, 0, 0);
protected int shadowscale[]; /* index=skylight level, value = 256 * scaling value */
protected int lightscale[]; /* scale skylight level (light = lightscale[skylight] */
protected boolean night_and_day; /* If true, render both day (prefix+'-day') and night (prefix) tiles */
protected boolean transparency; /* Is transparency support active? */
public enum BiomeColorOption {
NONE, BIOME, TEMPERATURE, RAINFALL
}
protected BiomeColorOption biomecolored = BiomeColorOption.NONE; /* Use biome for coloring */
@Override
public String getPrefix() {
return prefix;
}
public String getName() {
return name;
}
public boolean isNightAndDayEnabled() { return night_and_day; }
public DefaultTileRenderer(DynmapCore core, ConfigurationNode configuration) {
this.configuration = configuration;
name = configuration.getString("name", null);
prefix = configuration.getString("prefix", name);
Object o = configuration.get("maximumheight");
if (o != null) {
maximumHeight = Integer.parseInt(String.valueOf(o));
if (maximumHeight > 127)
maximumHeight = 127;
}
o = configuration.get("shadowstrength");
if(o != null) {
double shadowweight = Double.parseDouble(String.valueOf(o));
if(shadowweight > 0.0) {
shadowscale = new int[16];
shadowscale[15] = 256;
/* Normal brightness weight in MC is a 20% relative dropoff per step */
for(int i = 14; i >= 0; i--) {
double v = shadowscale[i+1] * (1.0 - (0.2 * shadowweight));
shadowscale[i] = (int)v;
if(shadowscale[i] > 256) shadowscale[i] = 256;
if(shadowscale[i] < 0) shadowscale[i] = 0;
}
}
}
o = configuration.get("ambientlight");
if(o != null) {
int v = Integer.parseInt(String.valueOf(o));
lightscale = new int[16];
for(int i = 0; i < 16; i++) {
if(i < (15-v))
lightscale[i] = 0;
else
lightscale[i] = i - (15-v);
}
}
colorScheme = ColorScheme.getScheme(core, (String)configuration.get("colorscheme"));
night_and_day = configuration.getBoolean("night-and-day", false);
transparency = configuration.getBoolean("transparency", true); /* Default on */
String biomeopt = configuration.getString("biomecolored", "none");
if(biomeopt.equals("biome")) {
biomecolored = BiomeColorOption.BIOME;
}
else if(biomeopt.equals("temperature")) {
biomecolored = BiomeColorOption.TEMPERATURE;
}
else if(biomeopt.equals("rainfall")) {
biomecolored = BiomeColorOption.RAINFALL;
}
else {
biomecolored = BiomeColorOption.NONE;
}
}
public boolean isBiomeDataNeeded() { return biomecolored.equals(BiomeColorOption.BIOME); }
public boolean isRawBiomeDataNeeded() {
return biomecolored.equals(BiomeColorOption.RAINFALL) || biomecolored.equals(BiomeColorOption.TEMPERATURE);
}
public boolean render(MapChunkCache cache, KzedMapTile tile, File outputFile) {
DynmapWorld world = tile.getDynmapWorld();
boolean isnether = world.isNether();
DynmapBufferedImage im = DynmapBufferedImage.allocateBufferedImage(KzedMap.tileWidth, KzedMap.tileHeight);
DynmapBufferedImage zim = DynmapBufferedImage.allocateBufferedImage(KzedMap.tileWidth/2, KzedMap.tileHeight/2);
DynmapBufferedImage im_day = null;
DynmapBufferedImage zim_day = null;
if(night_and_day) {
im_day = DynmapBufferedImage.allocateBufferedImage(KzedMap.tileWidth, KzedMap.tileHeight);
zim_day = DynmapBufferedImage.allocateBufferedImage(KzedMap.tileWidth/2, KzedMap.tileHeight/2);
}
int ix = KzedMap.anchorx + tile.px / 2 + tile.py / 2 - ((127-maximumHeight)/2);
int iy = maximumHeight;
int iz = KzedMap.anchorz + tile.px / 2 - tile.py / 2 + ((127-maximumHeight)/2);
/* Don't mess with existing height-clipped renders */
if(maximumHeight < 127)
isnether = false;
int jx, jz;
int x, y;
MapIterator mapiter = cache.getIterator(ix, iy, iz);
Color c1 = new Color();
Color c2 = new Color();
int[] argb = im.argb_buf;
int[] zargb = zim.argb_buf;
Color c1_day = null;
Color c2_day = null;
int[] argb_day = null;
int[] zargb_day = null;
if(night_and_day) {
c1_day = new Color();
c2_day = new Color();
argb_day = im_day.argb_buf;
zargb_day = zim_day.argb_buf;
}
int rowoff = 0;
/* draw the map */
for (y = 0; y < KzedMap.tileHeight;) {
jx = ix;
jz = iz;
for (x = KzedMap.tileWidth - 1; x >= 0; x -= 2) {
mapiter.initialize(jx, iy, jz);
scan(world, 0, isnether, c1, c1_day, mapiter);
mapiter.initialize(jx, iy, jz);
scan(world, 2, isnether, c2, c2_day, mapiter);
argb[rowoff+x] = c1.getARGB();
argb[rowoff+x-1] = c2.getARGB();
if(night_and_day) {
argb_day[rowoff+x] = c1_day.getARGB();
argb_day[rowoff+x-1] = c2_day.getARGB();
}
jx++;
jz++;
}
y++;
rowoff += KzedMap.tileWidth;
jx = ix;
jz = iz - 1;
for (x = KzedMap.tileWidth - 1; x >= 0; x -= 2) {
mapiter.initialize(jx, iy, jz);
scan(world, 2, isnether, c1, c1_day, mapiter);
jx++;
jz++;
mapiter.initialize(jx, iy, jz);
scan(world, 0, isnether, c2, c2_day, mapiter);
argb[rowoff+x] = c1.getARGB();
argb[rowoff+x-1] = c2.getARGB();
if(night_and_day) {
argb_day[rowoff+x] = c1_day.getARGB();
argb_day[rowoff+x-1] = c2_day.getARGB();
}
}
y++;
rowoff += KzedMap.tileWidth;
ix++;
iz--;
}
/* Now, compute zoomed tile - bilinear filter 2x2 -> 1x1 */
doScaleWithBilinear(argb, zargb, KzedMap.tileWidth, KzedMap.tileHeight);
if(night_and_day) {
doScaleWithBilinear(argb_day, zargb_day, KzedMap.tileWidth, KzedMap.tileHeight);
}
/* Hand encoding and writing file off to MapManager */
KzedZoomedMapTile zmtile = new KzedZoomedMapTile(tile.getDynmapWorld(), tile);
File zoomFile = MapManager.mapman.getTileFile(zmtile);
return doFileWrites(outputFile, tile, im, im_day, zmtile, zoomFile, zim, zim_day);
}
private void doScaleWithBilinear(int[] argb, int[] zargb, int width, int height) {
Color c1 = new Color();
/* Now, compute zoomed tile - bilinear filter 2x2 -> 1x1 */
for(int y = 0; y < height; y += 2) {
for(int x = 0; x < width; x += 2) {
int red = 0;
int green = 0;
int blue = 0;
int alpha = 0;
for(int yy = y; yy < y+2; yy++) {
for(int xx = x; xx < x+2; xx++) {
c1.setARGB(argb[(yy*width)+xx]);
red += c1.getRed();
green += c1.getGreen();
blue += c1.getBlue();
alpha += c1.getAlpha();
}
}
c1.setRGBA(red>>2, green>>2, blue>>2, alpha>>2);
zargb[(y*width/4) + (x/2)] = c1.getARGB();
}
}
}
private boolean doFileWrites(final File fname, final KzedMapTile mtile,
final DynmapBufferedImage img, final DynmapBufferedImage img_day,
final KzedZoomedMapTile zmtile, final File zoomFile,
final DynmapBufferedImage zimg, final DynmapBufferedImage zimg_day) {
boolean didwrite = false;
/* Get coordinates of zoomed tile */
int ox = (mtile.px == zmtile.getTileX())?0:KzedMap.tileWidth/2;
int oy = (mtile.py == zmtile.getTileY())?0:KzedMap.tileHeight/2;
/* Test to see if we're unchanged from older tile */
TileHashManager hashman = MapManager.mapman.hashman;
long crc = hashman.calculateTileHash(img.argb_buf);
boolean updated_fname = false;
int tx = mtile.px/KzedMap.tileWidth;
int ty = mtile.py/KzedMap.tileHeight;
FileLockManager.getWriteLock(fname);
try {
if((!fname.exists()) || (crc != hashman.getImageHashCode(mtile.getKey(prefix), null, tx, ty))) {
Debug.debug("saving image " + fname.getPath());
if(!fname.getParentFile().exists())
fname.getParentFile().mkdirs();
try {
FileLockManager.imageIOWrite(img.buf_img, ImageFormat.FORMAT_PNG, fname);
} catch (IOException e) {
Debug.error("Failed to save image: " + fname.getPath(), e);
} catch (java.lang.NullPointerException e) {
Debug.error("Failed to save image (NullPointerException): " + fname.getPath(), e);
}
MapManager.mapman.pushUpdate(mtile.getDynmapWorld(), new Client.Tile(mtile.getFilename()));
hashman.updateHashCode(mtile.getKey(prefix), null, tx, ty, crc);
updated_fname = true;
didwrite = true;
}
} finally {
FileLockManager.releaseWriteLock(fname);
DynmapBufferedImage.freeBufferedImage(img);
}
MapManager.mapman.updateStatistics(mtile, prefix, true, updated_fname, true);
mtile.file = fname;
boolean updated_dfname = false;
File dfname = new File(mtile.getDynmapWorld().worldtilepath, mtile.getDayFilename());
if(img_day != null) {
crc = hashman.calculateTileHash(img.argb_buf);
FileLockManager.getWriteLock(dfname);
try {
if((!dfname.exists()) || (crc != hashman.getImageHashCode(mtile.getKey(prefix), "day", tx, ty))) {
Debug.debug("saving image " + dfname.getPath());
if(!dfname.getParentFile().exists())
dfname.getParentFile().mkdirs();
try {
FileLockManager.imageIOWrite(img_day.buf_img, ImageFormat.FORMAT_PNG, dfname);
} catch (IOException e) {
Debug.error("Failed to save image: " + dfname.getPath(), e);
} catch (java.lang.NullPointerException e) {
Debug.error("Failed to save image (NullPointerException): " + dfname.getPath(), e);
}
MapManager.mapman.pushUpdate(mtile.getDynmapWorld(), new Client.Tile(mtile.getDayFilename()));
hashman.updateHashCode(mtile.getKey(prefix), "day", tx, ty, crc);
updated_dfname = true;
didwrite = true;
}
} finally {
FileLockManager.releaseWriteLock(dfname);
DynmapBufferedImage.freeBufferedImage(img_day);
}
MapManager.mapman.updateStatistics(mtile, prefix+"_day", true, updated_dfname, true);
}
// Since we've already got the new tile, and we're on an async thread, just
// make the zoomed tile here
boolean ztile_updated = false;
FileLockManager.getWriteLock(zoomFile);
try {
if(updated_fname || (!zoomFile.exists())) {
saveZoomedTile(zmtile, zoomFile, zimg, ox, oy, null);
MapManager.mapman.pushUpdate(zmtile.getDynmapWorld(),
new Client.Tile(zmtile.getFilename()));
zmtile.getDynmapWorld().enqueueZoomOutUpdate(zoomFile);
ztile_updated = true;
}
} finally {
FileLockManager.releaseWriteLock(zoomFile);
DynmapBufferedImage.freeBufferedImage(zimg);
}
MapManager.mapman.updateStatistics(zmtile, null, true, ztile_updated, true);
if(zimg_day != null) {
File zoomFile_day = new File(zmtile.getDynmapWorld().worldtilepath, zmtile.getDayFilename());
ztile_updated = false;
FileLockManager.getWriteLock(zoomFile_day);
try {
if(updated_dfname || (!zoomFile_day.exists())) {
saveZoomedTile(zmtile, zoomFile_day, zimg_day, ox, oy, "day");
MapManager.mapman.pushUpdate(zmtile.getDynmapWorld(),
new Client.Tile(zmtile.getDayFilename()));
zmtile.getDynmapWorld().enqueueZoomOutUpdate(zoomFile_day);
ztile_updated = true;
}
} finally {
FileLockManager.releaseWriteLock(zoomFile_day);
DynmapBufferedImage.freeBufferedImage(zimg_day);
}
MapManager.mapman.updateStatistics(zmtile, "day", true, ztile_updated, true);
}
return didwrite;
}
private void saveZoomedTile(final KzedZoomedMapTile zmtile, final File zoomFile,
final DynmapBufferedImage zimg, int ox, int oy, String subkey) {
BufferedImage zIm = null;
DynmapBufferedImage kzIm = null;
try {
zIm = ImageIO.read(zoomFile);
} catch (IOException e) {
} catch (IndexOutOfBoundsException e) {
}
boolean zIm_allocated = false;
if (zIm == null) {
/* create new one */
kzIm = DynmapBufferedImage.allocateBufferedImage(KzedMap.tileWidth, KzedMap.tileHeight);
zIm = kzIm.buf_img;
zIm_allocated = true;
Debug.debug("New zoom-out tile created " + zmtile.getFilename());
} else {
Debug.debug("Loaded zoom-out tile from " + zmtile.getFilename());
}
/* blit scaled rendered tile onto zoom-out tile */
zIm.setRGB(ox, oy, KzedMap.tileWidth/2, KzedMap.tileHeight/2, zimg.argb_buf, 0, KzedMap.tileWidth/2);
/* save zoom-out tile */
if(!zoomFile.getParentFile().exists())
zoomFile.getParentFile().mkdirs();
try {
FileLockManager.imageIOWrite(zIm, ImageFormat.FORMAT_PNG, zoomFile);
Debug.debug("Saved zoom-out tile at " + zoomFile.getName());
} catch (IOException e) {
Debug.error("Failed to save zoom-out tile: " + zoomFile.getName(), e);
} catch (java.lang.NullPointerException e) {
Debug.error("Failed to save zoom-out tile (NullPointerException): " + zoomFile.getName(), e);
}
if(zIm_allocated)
DynmapBufferedImage.freeBufferedImage(kzIm);
else
zIm.flush();
}
protected void scan(DynmapWorld world, int seq, boolean isnether, final Color result, final Color result_day,
MapIterator mapiter) {
int lightlevel = 15;
int lightlevel_day = 15;
BiomeMap bio = null;
double rain = 0.0;
double temp = 0.0;
result.setTransparent();
if(result_day != null)
result_day.setTransparent();
for (;;) {
if (mapiter.getY() < 0) {
return;
}
int id = mapiter.getBlockTypeID();
int data = 0;
if(isnether) { /* Make bedrock ceiling into air in nether */
if(id != 0) {
/* Remember first color we see, in case we wind up solid */
if(result.isTransparent())
if(colorScheme.colors[id] != null)
result.setColor(colorScheme.colors[id][seq]);
id = 0;
}
else
isnether = false;
}
if(id != 0) { /* No update needed for air */
switch(biomecolored) {
case NONE:
if(colorScheme.datacolors[id] != null) { /* If data colored */
data = mapiter.getBlockData();
}
break;
case BIOME:
bio = mapiter.getBiome();
break;
case RAINFALL:
rain = mapiter.getRawBiomeRainfall();
break;
case TEMPERATURE:
temp = mapiter.getRawBiomeTemperature();
break;
}
if((shadowscale != null) && (mapiter.getY() < 127)) {
/* Find light level of previous chunk */
BlockStep last = mapiter.unstepPosition();
lightlevel = lightlevel_day = mapiter.getBlockSkyLight();
if(lightscale != null)
lightlevel = lightscale[lightlevel];
if((lightlevel < 15) || (lightlevel_day < 15)) {
int emitted = mapiter.getBlockEmittedLight();
lightlevel = Math.max(emitted, lightlevel);
lightlevel_day = Math.max(emitted, lightlevel_day);
}
mapiter.stepPosition(last);
}
}
switch (seq) {
case 0:
mapiter.stepPosition(BlockStep.X_MINUS);
break;
case 1:
case 3:
mapiter.stepPosition(BlockStep.Y_MINUS);
break;
case 2:
mapiter.stepPosition(BlockStep.Z_PLUS);
break;
}
seq = (seq + 1) & 3;
if (id != 0) {
if (highlightBlocks.contains(id)) {
result.setColor(highlightColor);
return;
}
Color[] colors = null;
switch(biomecolored) {
case NONE:
if(data != 0)
colors = colorScheme.datacolors[id][data];
else
colors = colorScheme.colors[id];
break;
case BIOME:
if(bio != null)
colors = colorScheme.biomecolors[bio.ordinal()];
break;
case RAINFALL:
colors = colorScheme.getRainColor(rain);
break;
case TEMPERATURE:
colors = colorScheme.getTempColor(temp);
break;
}
if (colors != null) {
Color c = colors[seq];
if (c.getAlpha() > 0) {
/* we found something that isn't transparent, or not doing transparency */
if ((!transparency) || (c.getAlpha() == 255)) {
/* it's opaque - the ray ends here */
result.setARGB(c.getARGB() | 0xFF000000);
if(lightlevel < 15) { /* Not full light? */
shadowColor(result, lightlevel);
}
if(result_day != null) {
if(lightlevel_day == lightlevel) /* Same light = same result */
result_day.setColor(result);
else {
result_day.setColor(c);
if(lightlevel_day < 15)
shadowColor(result_day, lightlevel_day);
}
}
return;
}
/* this block is transparent, so recurse */
scan(world, seq, isnether, result, result_day, mapiter);
int cr = c.getRed();
int cg = c.getGreen();
int cb = c.getBlue();
int ca = c.getAlpha();
if(lightlevel < 15) {
int scale = shadowscale[lightlevel];
cr = (cr * scale) >> 8;
cg = (cg * scale) >> 8;
cb = (cb * scale) >> 8;
}
cr *= ca;
cg *= ca;
cb *= ca;
int na = 255 - ca;
result.setRGBA((result.getRed() * na + cr) >> 8, (result.getGreen() * na + cg) >> 8, (result.getBlue() * na + cb) >> 8, 255);
/* Handle day also */
if(result_day != null) {
cr = c.getRed();
cg = c.getGreen();
cb = c.getBlue();
if(lightlevel_day < 15) {
int scale = shadowscale[lightlevel_day];
cr = (cr * scale) >> 8;
cg = (cg * scale) >> 8;
cb = (cb * scale) >> 8;
}
cr *= ca;
cg *= ca;
cb *= ca;
result_day.setRGBA((result_day.getRed() * na + cr) >> 8, (result_day.getGreen() * na + cg) >> 8, (result_day.getBlue() * na + cb) >> 8,
255);
}
return;
}
}
}
}
}
private final void shadowColor(Color c, int lightlevel) {
int scale = shadowscale[lightlevel];
if(scale < 256)
c.setRGBA((c.getRed() * scale) >> 8, (c.getGreen() * scale) >> 8,
(c.getBlue() * scale) >> 8, c.getAlpha());
}
@Override
public void buildClientConfiguration(JSONObject worldObject, DynmapWorld world, KzedMap map) {
ConfigurationNode c = configuration;
JSONObject o = new JSONObject();
s(o, "type", "KzedMapType");
s(o, "name", c.getString("name"));
s(o, "title", c.getString("title"));
s(o, "icon", c.getString("icon"));
s(o, "prefix", c.getString("prefix"));
s(o, "background", c.getString("background"));
s(o, "nightandday", c.getBoolean("night-and-day", false));
s(o, "backgroundday", c.getString("backgroundday"));
s(o, "backgroundnight", c.getString("backgroundnight"));
s(o, "bigmap", map.isBigWorldMap(world));
s(o, "mapzoomin", c.getInteger("mapzoomin", 2));
s(o, "mapzoomout", world.getExtraZoomOutLevels()+1);
if(MapManager.mapman.getCompassMode() != CompassMode.PRE19)
s(o, "compassview", "NE"); /* Always from northeast */
else
s(o, "compassview", "SE"); /* Always from southeast */
s(o, "image-format", ImageFormat.FORMAT_PNG.getFileExt());
a(worldObject, "maps", o);
}
}

View file

@ -1,107 +0,0 @@
package org.dynmap.kzedmap;
import java.util.HashSet;
import java.util.List;
import org.dynmap.Color;
import org.dynmap.ConfigurationNode;
import org.dynmap.DynmapCore;
import org.dynmap.DynmapWorld;
import org.dynmap.utils.MapIterator;
import org.dynmap.utils.MapIterator.BlockStep;
public class HighlightTileRenderer extends DefaultTileRenderer {
protected HashSet<Integer> highlightBlocks = new HashSet<Integer>();
public HighlightTileRenderer(DynmapCore core, ConfigurationNode configuration) {
super(core, configuration);
List<Integer> highlight = configuration.<Integer>getList("highlight");
for(Integer i : highlight) {
highlightBlocks.add(i);
}
}
@Override
protected void scan(DynmapWorld world,int seq, boolean isnether, final Color result, final Color result_day,
MapIterator mapiter) {
result.setTransparent();
for (;;) {
if (mapiter.getY() < 0) {
break;
}
int id = mapiter.getBlockTypeID();
if(isnether) { /* Make bedrock ceiling into air in nether */
if(id != 0) {
/* Remember first color we see, in case we wind up solid */
if(result.isTransparent())
if(colorScheme.colors[id] != null)
result.setColor(colorScheme.colors[id][seq]);
id = 0;
}
else
isnether = false;
}
int data = 0;
if(colorScheme.datacolors[id] != null) { /* If data colored */
data = mapiter.getBlockData();
}
switch (seq) {
case 0:
mapiter.stepPosition(BlockStep.X_MINUS);
break;
case 1:
case 3:
mapiter.stepPosition(BlockStep.Y_MINUS);
break;
case 2:
mapiter.stepPosition(BlockStep.Z_PLUS);
break;
}
seq = (seq + 1) & 3;
if (id != 0) {
Color[] colors;
if(data != 0)
colors = colorScheme.datacolors[id][data];
else
colors = colorScheme.colors[id];
if (colors != null) {
Color c = colors[seq];
if (highlightBlocks.contains(id)) {
result.setColor(c);
return;
}
if (c.getAlpha() > 0) {
/* we found something that isn't transparent! */
/*
* if (c.getAlpha() == 255) { return c; }
*/
/* this block is transparent, so recurse */
// No need to blend if result is opaque.
if (result.getAlpha() < 255) {
int cr = result.getRed();
int cg = result.getGreen();
int cb = result.getBlue();
int ca = result.getAlpha();
cr *= ca;
cg *= ca;
cb *= ca;
int na = 255 - ca;
result.setRGBA((c.getRed() * na + cr) >> 8, (c.getGreen() * na + cg) >> 8, (c.getBlue() * na + cb) >> 8,
Math.min(255, c.getAlpha()+ca) // Not really correct, but gets the job done without recursion while still looking ok.
);
}
}
}
}
}
}
}

View file

@ -1,336 +0,0 @@
package org.dynmap.kzedmap;
import org.dynmap.DynmapWorld;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;
import org.dynmap.ConfigurationNode;
import org.dynmap.DynmapChunk;
import org.dynmap.DynmapCore;
import org.dynmap.Log;
import org.dynmap.MapTile;
import org.dynmap.MapType;
import org.dynmap.utils.MapChunkCache;
import org.json.simple.JSONObject;
public class KzedMap extends MapType {
protected static final Logger log = Logger.getLogger("Minecraft");
protected static final String LOG_PREFIX = "[dynmap] ";
/* dimensions of a map tile */
public static final int tileWidth = 128;
public static final int tileHeight = 128;
/*
* (logical!) dimensions of a zoomed out map tile must be twice the size of
* the normal tile
*/
public static final int zTileWidth = 256;
public static final int zTileHeight = 256;
/* map x, y, z for projection origin */
public static final int anchorx = 0;
public static final int anchory = 127;
public static final int anchorz = 0;
MapTileRenderer[] renderers;
private boolean isbigmap;
public KzedMap(DynmapCore core, ConfigurationNode configuration) {
Log.verboseinfo("Loading renderers for map '" + getClass().toString() + "'...");
List<MapTileRenderer> renderers = configuration.<MapTileRenderer>createInstances("renderers", new Class<?>[] { DynmapCore.class }, new Object[] { core } );
this.renderers = new MapTileRenderer[renderers.size()];
renderers.toArray(this.renderers);
Log.verboseinfo("Loaded " + renderers.size() + " renderers for map '" + getClass().toString() + "'.");
isbigmap = configuration.getBoolean("isbigmap", false);
}
@Override
public MapTile[] getTiles(DynmapWorld world, int x, int y, int z) {
int dx = x - anchorx;
int dy = y - anchory;
int dz = z - anchorz;
int px = dx + dz;
int py = dx - dz - dy;
int tx = tilex(px);
int ty = tiley(py);
ArrayList<MapTile> tiles = new ArrayList<MapTile>();
addTile(tiles, world, tx, ty);
boolean ledge = tilex(px - 4) != tx;
boolean tedge = tiley(py - 4) != ty;
boolean redge = tilex(px + 4) != tx;
boolean bedge = tiley(py + 4) != ty;
if (ledge)
addTile(tiles, world, tx - tileWidth, ty);
if (redge)
addTile(tiles, world, tx + tileWidth, ty);
if (tedge)
addTile(tiles, world, tx, ty - tileHeight);
if (bedge)
addTile(tiles, world, tx, ty + tileHeight);
if (ledge && tedge)
addTile(tiles, world, tx - tileWidth, ty - tileHeight);
if (ledge && bedge)
addTile(tiles, world, tx - tileWidth, ty + tileHeight);
if (redge && tedge)
addTile(tiles, world, tx + tileWidth, ty - tileHeight);
if (redge && bedge)
addTile(tiles, world, tx + tileWidth, ty + tileHeight);
MapTile[] result = new MapTile[tiles.size()];
tiles.toArray(result);
return result;
}
@Override
public MapTile[] getTiles(DynmapWorld world, int minx, int miny, int minz, int maxx, int maxy, int maxz) {
ArrayList<MapTile> tiles = new ArrayList<MapTile>();
/* Transform both to tile coordinates */
int dx = minx - anchorx;
int dy = miny - anchory;
int dz = minz - anchorz;
int px0 = dx + dz;
int py0 = dx - dz - dy;
dx = maxx - anchorx;
dy = maxy - anchory;
dz = maxz - anchorz;
int px1 = dx + dz;
int py1 = dx - dz - dy;
/* Compute ranges */
int mintx = (px1<px0)?px0:px1;
int maxtx = (px1<px0)?px1+1:px0+1;
int minty = (py1<py0)?py0:py1;
int maxty = (py1<py0)?py1+1:py0+1;
/* Now, add the tiles for the ranges - not perfect, but it works (some extra tiles on corners possible) */
for(int i = mintx >> 7; i <= maxtx >> 7; i++) {
for(int j = minty >> 7; j < maxty >> 7; j++) {
addTile(tiles, world, i << 7, j << 7);
}
}
return tiles.toArray(new MapTile[tiles.size()]);
}
@Override
public MapTile[] getAdjecentTiles(MapTile tile) {
if (tile instanceof KzedMapTile) {
KzedMapTile t = (KzedMapTile) tile;
DynmapWorld world = tile.getDynmapWorld();
MapTileRenderer renderer = t.renderer;
return new MapTile[] {
new KzedMapTile(world, this, renderer, t.px - tileWidth, t.py + tileHeight),
new KzedMapTile(world, this, renderer, t.px + tileWidth, t.py - tileHeight),
new KzedMapTile(world, this, renderer, t.px - tileWidth, t.py - tileHeight),
new KzedMapTile(world, this, renderer, t.px + tileWidth, t.py + tileHeight),
new KzedMapTile(world, this, renderer, t.px - tileWidth, t.py),
new KzedMapTile(world, this, renderer, t.px + tileWidth, t.py),
new KzedMapTile(world, this, renderer, t.px, t.py - tileHeight),
new KzedMapTile(world, this, renderer, t.px, t.py + tileHeight) };
}
return new MapTile[0];
}
public void addTile(ArrayList<MapTile> tiles, DynmapWorld world, int px, int py) {
for (int i = 0; i < renderers.length; i++) {
tiles.add(new KzedMapTile(world, this, renderers[i], px, py));
}
}
/**
* Test if point x,z is inside rectangle with corner at r0x,r0z and with
* size vectors s1x,s1z and s2x,s2z
*
*/
private boolean testPointInRectangle(int x, int z, int r0x, int r0z, int s1x, int s1z,
int s2x, int s2z) {
int xr = x - r0x;
int zr = z - r0z; /* Get position relative to rectangle corner */
int dots1 = xr*s1x + zr*s1z;
int dots2 = xr*s2x + zr*s2z;
/* If dot product of relative point and each side is between zero and dot product
* of each side and itself, we're inside
*/
if((dots1 >= 0) && (dots1 <= (s1x*s1x+s1z*s1z)) &&
(dots2 >= 0) && (dots2 <= (s2x*s2x+s2z*s2z))) {
return true;
}
return false;
}
@Override
public List<DynmapChunk> getRequiredChunks(MapTile tile) {
if (tile instanceof KzedMapTile) {
KzedMapTile t = (KzedMapTile) tile;
int ix = KzedMap.anchorx + t.px / 2 + t.py / 2;
//int iy = 127;
int iz = KzedMap.anchorz + t.px / 2 - t.py / 2;
int x1 = ix - KzedMap.tileHeight / 2;
int x2 = ix + KzedMap.tileWidth / 2 + KzedMap.tileHeight / 2;
int z1 = iz - KzedMap.tileHeight / 2;
int z2 = iz + KzedMap.tileWidth / 2 + KzedMap.tileHeight / 2;
int x, z;
/* Actual pattern of chunks needed is create by the slanted
* square prism corresponding to the render path of the tile.
* Top of prism (corresponding to y=127) is diamond shape from
* ix, iz to ix+64,iz+64 to ix+128,iz to ix+64,iz-64
* Bottom is same shape, offset by -64 on x, +64 on z (net
* render path to y=0), correspond to ix-64, iz+64 to
* ix,iz+128 to ix+64,iz+64 to ix,iz. Projection of
* the prism on to the x,z plane (which is all that matters for
* chunks) yields a diagonal rectangular area from ix-64(x1),iz+64
* to ix,iz+128(z2) to ix+128(x2),iz to ix+64,iz-64(z1).
* Chunks outside this are not needed - we scan a simple rectangle
* (chunk grid aligned) and skip adding the ones that are outside.
* This results in 42% less chunks being loaded.
*/
ArrayList<DynmapChunk> chunks = new ArrayList<DynmapChunk>();
for (x = x1; x < x2; x += 16) {
for (z = z1; z < z2; z += 16) {
/* If any of the chunk corners are inside the rectangle, we need it */
if((!testPointInRectangle(x, z, x1, iz + KzedMap.tileWidth/2,
KzedMap.tileWidth/2, KzedMap.tileHeight/2,
KzedMap.tileWidth, -KzedMap.tileHeight)) &&
(!testPointInRectangle(x+15, z, x1, iz + KzedMap.tileWidth/2,
KzedMap.tileWidth/2, KzedMap.tileHeight/2,
KzedMap.tileWidth, -KzedMap.tileHeight)) &&
(!testPointInRectangle(x+15, z+15, x1, iz + KzedMap.tileWidth/2,
KzedMap.tileWidth/2, KzedMap.tileHeight/2,
KzedMap.tileWidth, -KzedMap.tileHeight)) &&
(!testPointInRectangle(x, z+15, x1, iz + KzedMap.tileWidth/2,
KzedMap.tileWidth/2, KzedMap.tileHeight/2,
KzedMap.tileWidth, -KzedMap.tileHeight)))
continue;
DynmapChunk chunk = new DynmapChunk(x / 16, z / 16);
chunks.add(chunk);
}
}
return chunks;
} else {
return new ArrayList<DynmapChunk>();
}
}
public boolean render(MapChunkCache cache, MapTile tile, File outputFile) {
if (tile instanceof KzedMapTile) {
return ((KzedMapTile) tile).renderer.render(cache, (KzedMapTile) tile, outputFile);
}
return false;
}
/* tile X for position x */
static int tilex(int x) {
if (x < 0)
return x - (tileWidth + (x % tileWidth));
else
return x - (x % tileWidth);
}
/* tile Y for position y */
static int tiley(int y) {
if (y < 0)
return y - (tileHeight + (y % tileHeight));
else
return y - (y % tileHeight);
}
/* zoomed-out tile X for tile position x */
static int ztilex(int x) {
if (x < 0)
return x + x % zTileWidth;
else
return x - (x % zTileWidth);
}
/* zoomed-out tile Y for tile position y */
static int ztiley(int y) {
if (y < 0)
return y + y % zTileHeight;
// return y - (zTileHeight + (y % zTileHeight));
else
return y - (y % zTileHeight);
}
public boolean isBiomeDataNeeded() {
for(MapTileRenderer r : renderers) {
if(r.isBiomeDataNeeded())
return true;
}
return false;
}
public boolean isRawBiomeDataNeeded() {
for(MapTileRenderer r : renderers) {
if(r.isRawBiomeDataNeeded())
return true;
}
return false;
}
public List<ZoomInfo> baseZoomFileInfo() {
ArrayList<ZoomInfo> s = new ArrayList<ZoomInfo>();
for(MapTileRenderer r : renderers) {
s.add(new ZoomInfo("z" + r.getPrefix(), 0));
if(r.isNightAndDayEnabled())
s.add(new ZoomInfo("z" + r.getPrefix() + "_day", 0));
}
return s;
}
public int baseZoomFileStepSize() { return zTileWidth; }
public MapStep zoomFileMapStep() { return MapStep.X_MINUS_Y_PLUS; }
private static final int[] stepseq = { 0, 2, 1, 3 };
public int[] zoomFileStepSequence() { return stepseq; }
/* How many bits of coordinate are shifted off to make big world directory name */
public int getBigWorldShift() { return 12; }
/* Returns true if big world file structure is in effect for this map */
@Override
public boolean isBigWorldMap(DynmapWorld w) {
return w.bigworld || isbigmap;
}
public String getName() {
return "KzedMap";
}
/* Get maps rendered concurrently with this map in this world */
public List<MapType> getMapsSharingRender(DynmapWorld w) {
return Collections.singletonList((MapType)this);
}
/* Get names of maps rendered concurrently with this map type in this world */
public List<String> getMapNamesSharingRender(DynmapWorld w) {
ArrayList<String> lst = new ArrayList<String>();
for(MapTileRenderer rend : renderers) {
if(rend.isNightAndDayEnabled())
lst.add(rend.getName() + "(night/day)");
else
lst.add(rend.getName());
}
return lst;
}
@Override
public void buildClientConfiguration(JSONObject worldObject, DynmapWorld world) {
for(MapTileRenderer renderer : renderers) {
renderer.buildClientConfiguration(worldObject, world, this);
}
}
}

View file

@ -1,133 +0,0 @@
package org.dynmap.kzedmap;
import org.dynmap.DynmapChunk;
import org.dynmap.DynmapWorld;
import org.dynmap.MapManager;
import org.dynmap.MapType;
import java.io.File;
import java.util.List;
import org.dynmap.MapTile;
import org.dynmap.utils.MapChunkCache;
public class KzedMapTile extends MapTile {
public KzedMap map;
public MapTileRenderer renderer;
public int px, py;
private String fname;
private String fname_day;
// Hack.
public File file = null;
public KzedMapTile(DynmapWorld world, KzedMap map, MapTileRenderer renderer, int px, int py) {
super(world);
this.map = map;
this.renderer = renderer;
this.px = px;
this.py = py;
}
public KzedMapTile(DynmapWorld world, String parm) throws Exception {
super(world);
String[] parms = parm.split(",");
if(parms.length < 4) throw new Exception("wrong parameter count");
this.px = Integer.parseInt(parms[0]);
this.py = Integer.parseInt(parms[1]);
for(MapType t : world.maps) {
if(t.getName().equals(parms[2]) && (t instanceof KzedMap)) {
this.map = (KzedMap)t;
break;
}
}
if(this.map == null) throw new Exception("invalid map");
for(MapTileRenderer r : map.renderers) {
if(r.getName().equals(parms[3])) {
this.renderer = r;
break;
}
}
if(this.renderer == null) throw new Exception("invalid renderer");
}
@Override
protected String saveTileData() {
return String.format("%d,%d,%s,%s", px, py, map.getName(), renderer.getName());
}
@Override
public String getFilename() {
if(fname == null) {
if(map.isBigWorldMap(world))
fname = renderer.getPrefix() + "/" + (px >> 12) + '_' + (py >> 12) + '/' + px + "_" + py + ".png";
else
fname = renderer.getPrefix() + "_" + px + "_" + py + ".png";
}
return fname;
}
@Override
public String getDayFilename() {
if(fname_day == null) {
if(map.isBigWorldMap(world))
fname_day = renderer.getPrefix() + "_day/" + (px >> 12) + '_' + (py >> 12) + '/' + px + "_" + py + ".png";
else
fname_day = renderer.getPrefix() + "_day_" + px + "_" + py + ".png";
}
return fname_day;
}
@Override
public int hashCode() {
return px ^ py ^ map.getName().hashCode() ^ world.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof KzedMapTile) {
return equals((KzedMapTile) obj);
}
return false;
}
public boolean equals(KzedMapTile o) {
return o.px == px && o.py == py && (o.map == map) && (o.world == world);
}
public String getKey(String prefix) {
return world.getName() + "." + prefix;
}
public String toString() {
return world.getName() + ":" + getFilename();
}
public boolean render(MapChunkCache cache, String mapname) {
boolean rslt = false;
for(MapTileRenderer r : map.renderers) {
if((mapname == null) || (r.getName().equals(mapname))) {
KzedMapTile t = new KzedMapTile(world, map, r, px, py);
rslt |= map.render(cache, t, MapManager.mapman.getTileFile(t));
}
}
return rslt;
}
public List<DynmapChunk> getRequiredChunks() {
return map.getRequiredChunks(this);
}
public MapTile[] getAdjecentTiles() {
return map.getAdjecentTiles(this);
}
public boolean isBiomeDataNeeded() { return map.isBiomeDataNeeded(); }
public boolean isHightestBlockYDataNeeded() { return false; }
public boolean isRawBiomeDataNeeded() { return map.isRawBiomeDataNeeded(); }
public boolean isBlockTypeDataNeeded() { return true; }
public int tileOrdinalX() { return px >> 7; }
public int tileOrdinalY() { return py >> 7; }
}

View file

@ -1,113 +0,0 @@
package org.dynmap.kzedmap;
import java.util.List;
import org.dynmap.DynmapChunk;
import org.dynmap.DynmapWorld;
import org.dynmap.MapTile;
import org.dynmap.utils.MapChunkCache;
public class KzedZoomedMapTile extends MapTile {
private String fname;
private String fname_day;
@Override
public String getFilename() {
if(fname == null) {
if(world.bigworld)
fname = "z" + originalTile.renderer.getPrefix() + "/" + (getTileX()>>12) + '_' +
(getTileY() >> 12) + '/' + getTileX() + "_" + getTileY() + ".png";
else
fname = "z" + originalTile.renderer.getPrefix() + "_" + getTileX() + "_" + getTileY() + ".png";
}
return fname;
}
@Override
public String getDayFilename() {
if(fname_day == null) {
if(world.bigworld)
fname_day = "z" + originalTile.renderer.getPrefix() + "_day/" + (getTileX()>>12) + '_' +
(getTileY() >> 12) + '/' + getTileX() + "_" + getTileY() + ".png";
else
fname_day = "z" + originalTile.renderer.getPrefix() + "_day_" + getTileX() + "_" + getTileY() + ".png";
}
return fname_day;
}
public KzedMapTile originalTile;
public KzedZoomedMapTile(DynmapWorld world, KzedMapTile original) {
super(world);
this.originalTile = original;
}
@Override
protected String saveTileData() {
return originalTile.saveTileData();
}
public int getTileX() {
return ztilex(originalTile.px + KzedMap.tileWidth);
}
public int getTileY() {
return ztiley(originalTile.py);
}
private static int ztilex(int x) {
if (x < 0)
return x + (x % (KzedMap.tileWidth * 2));
else
return x - (x % (KzedMap.tileWidth * 2));
}
/* zoomed-out tile Y for tile position y */
private static int ztiley(int y) {
if (y < 0)
return y + (y % (KzedMap.tileHeight * 2));
else
return y - (y % (KzedMap.tileHeight * 2));
}
@Override
public int hashCode() {
return getFilename().hashCode() ^ world.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof KzedZoomedMapTile) {
return ((KzedZoomedMapTile) obj).originalTile.equals(originalTile);
}
return false;
}
public String getKey(String prefix) {
return world.getName() + ".z" + prefix;
}
@Override
public boolean render(MapChunkCache cache, String mapname) {
return false;
}
@Override
public List<DynmapChunk> getRequiredChunks() {
return null;
}
@Override
public MapTile[] getAdjecentTiles() {
return null;
}
public boolean isBiomeDataNeeded() { return originalTile.isBiomeDataNeeded(); }
public boolean isHightestBlockYDataNeeded() { return false; }
public boolean isRawBiomeDataNeeded() { return originalTile.isRawBiomeDataNeeded(); }
public boolean isBlockTypeDataNeeded() { return true; }
public int tileOrdinalX() { return originalTile.px >> 8; }
public int tileOrdinalY() { return originalTile.py >> 8; }
}

View file

@ -1,21 +0,0 @@
package org.dynmap.kzedmap;
import java.io.File;
import org.dynmap.DynmapWorld;
import org.dynmap.utils.MapChunkCache;
import org.json.simple.JSONObject;
public interface MapTileRenderer {
String getPrefix();
String getName();
boolean render(MapChunkCache cache, KzedMapTile tile, File outputFile);
void buildClientConfiguration(JSONObject worldObject, DynmapWorld w, KzedMap map);
boolean isBiomeDataNeeded();
boolean isRawBiomeDataNeeded();
boolean isNightAndDayEnabled();
}

View file

@ -1,332 +0,0 @@
package org.dynmap.markers.impl;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.dynmap.ConfigurationNode;
import org.dynmap.markers.AreaMarker;
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 persistent - true if persistent
* @param set - marker set
*/
AreaMarkerImpl(String id, String lbl, boolean markup, String world, double x[], double z[], 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.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.getList("x");
List<Double> zz = node.getList("z");
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.getInteger("strokeWeight", 3);
lineopacity = node.getDouble("strokeOpacity", 0.8);
linecolor = node.getInteger("strokeColor", 0xFF0000);
fillopacity = node.getDouble("fillOpacity", 0.35);
fillcolor = node.getInteger("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);
List<Double> xx = new ArrayList<Double>();
List<Double> zz = new ArrayList<Double>();
for(int i = 0; i < corners.size(); i++) {
xx.add(corners.get(i).x);
zz.add(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) {
/* Check if equals */
if(x.length == corners.size()) {
boolean match = true;
for(int i = 0; i < x.length; i++) {
Coord c = corners.get(i);
if((c.x != x[i]) || (c.z != z[i])) {
match = false;
break;
}
}
if(match)
return;
}
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;
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,101 +0,0 @@
package org.dynmap.markers.impl;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import org.dynmap.ConfigurationNode;
import org.dynmap.markers.MarkerIcon;
class MarkerIconImpl implements MarkerIcon {
private String iconid;
private String label;
private boolean is_builtin;
private MarkerSize size = MarkerSize.MARKER_16x16;
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 void setMarkerIconLabel(String lbl) {
if(lbl == null) lbl = iconid;
if(label.equals(lbl) == false) {
label = lbl;
MarkerAPIImpl.saveMarkers();
}
}
@Override
public void setMarkerIconImage(InputStream in) {
if(MarkerAPIImpl.api.loadMarkerIconStream(this.iconid, in))
MarkerAPIImpl.api.publishMarkerIcon(this);
}
@Override
public void deleteIcon() {
MarkerAPIImpl.removeIcon(this);
}
@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;
}
@Override
public MarkerSize getMarkerIconSize() {
return size;
}
void setMarkerIconSize(MarkerSize sz) {
size = sz;
}
}

View file

@ -1,217 +0,0 @@
package org.dynmap.markers.impl;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.dynmap.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 boolean markup;
private String desc;
private MarkerSetImpl markerset;
private double x, y, z;
private String world;
private MarkerIconImpl icon;
private boolean ispersistent;
/**
* Create marker
* @param id - marker ID
* @param lbl - label
* @param markup - if true, label is HTML markup
* @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, boolean markup, String world, double x, double y, double z, MarkerIconImpl icon, boolean persistent, MarkerSetImpl set) {
markerid = id;
if(lbl != null)
label = lbl;
else
label = id;
this.markup = markup;
this.x = x; this.y = y; this.z = z;
this.world = world;
this.icon = icon;
this.desc = null;
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;
markup = false;
desc = null;
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);
markup = node.getBoolean("markup", false);
x = node.getDouble("x", 0);
y = node.getDouble("y", 64);
z = node.getDouble("z", 0);
world = node.getString("world", "world");
desc = node.getString("desc", null);
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) {
setLabel(lbl, false);
}
@Override
public void setLabel(String lbl, boolean markup) {
label = lbl;
this.markup = markup;
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("markup", markup);
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());
if(desc != null)
node.put("desc", desc);
return node;
}
@Override
public String getWorld() {
return world;
}
@Override
public double getX() {
return x;
}
@Override
public double getY() {
return y;
}
@Override
public double getZ() {
return z;
}
@Override
public void setLocation(String worldid, double x, double y, double z) {
this.world = worldid;
this.x = x;
this.y = y;
this.z = z;
MarkerAPIImpl.markerUpdated(this, MarkerUpdate.UPDATED);
if(ispersistent)
MarkerAPIImpl.saveMarkers();
}
@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.markerUpdated(this, MarkerUpdate.UPDATED);
if(ispersistent)
MarkerAPIImpl.saveMarkers();
}
}
/**
* Get marker description
* @return descrption
*/
public String getDescription() {
return this.desc;
}
}

View file

@ -1,389 +0,0 @@
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.dynmap.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;
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;
private boolean hide_by_def;
private boolean ispersistent;
private int prio = 0;
private int minzoom = 0;
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();
for(AreaMarkerImpl m : areamarkers.values())
m.cleanup();
markers.clear();
}
@Override
public Set<Marker> getMarkers() {
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);
}
@Override
public Marker createMarker(String id, String label, boolean markup, 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 {
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, markup, 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 Marker findMarkerByLabel(String lbl) {
Marker match = null;
int matchlen = Integer.MAX_VALUE;
for(Marker m : markers.values()) {
if(m.getLabel().contains(lbl)) {
if(matchlen > m.getLabel().length()) {
match = m;
matchlen = m.getLabel().length();
}
}
}
return match;
}
@Override
public String getMarkerSetID() {
return setid;
}
@Override
public String getMarkerSetLabel() {
return label;
}
@Override
public void setMarkerSetLabel(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 void removeAllowedMarkerIcon(MarkerIcon icon) {
if(!(icon instanceof MarkerIconImpl)) return;
if(allowedicons == null) return;
allowedicons.remove(icon.getMarkerIconID());
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);
}
/**
* Remove marker from set
*
* @param marker
*/
void removeAreaMarker(AreaMarkerImpl marker) {
areamarkers.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
* @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());
}
}
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);
if(allowedicons != null) {
ArrayList<String> allowed = new ArrayList<String>(allowedicons.keySet());
setnode.put("allowedicons", allowed);
}
setnode.put("markers", node);
setnode.put("areas", anode);
setnode.put("hide", hide_by_def);
setnode.put("layerprio", prio);
setnode.put("minzoom", minzoom);
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.keySet()) {
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();
}
}
}
ConfigurationNode areamarkernode = node.getNode("areas");
if(areamarkernode != null) {
for(String id : areamarkernode.keySet()) {
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.getList("allowedicons");
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 + "'");
}
}
hide_by_def = node.getBoolean("hide", false);
prio = node.getInteger("layerprio", 0);
minzoom = node.getInteger("minzoom", 0);
ispersistent = true;
return true;
}
@Override
public void setHideByDefault(boolean hide) {
if(hide_by_def != hide) {
hide_by_def = hide;
MarkerAPIImpl.markerSetUpdated(this, MarkerUpdate.UPDATED);
if(ispersistent)
MarkerAPIImpl.saveMarkers();
}
}
@Override
public boolean getHideByDefault() {
return hide_by_def;
}
@Override
public void setLayerPriority(int prio) {
if(this.prio != prio) {
this.prio = prio;
MarkerAPIImpl.markerSetUpdated(this, MarkerUpdate.UPDATED);
if(ispersistent)
MarkerAPIImpl.saveMarkers();
}
}
@Override
public int getLayerPriority() {
return this.prio;
}
@Override
public AreaMarker createAreaMarker(String id, String lbl, boolean markup, String world, double[] x, double[] z, 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, lbl, markup, world, x, z, 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;
}
@Override
public void setMinZoom(int minzoom) {
if(this.minzoom != minzoom) {
this.minzoom = minzoom;
MarkerAPIImpl.markerSetUpdated(this, MarkerUpdate.UPDATED);
if(ispersistent)
MarkerAPIImpl.saveMarkers();
}
}
@Override
public int getMinZoom() {
return this.minzoom;
}
}

View file

@ -1,127 +0,0 @@
package org.dynmap.markers.impl;
import java.util.Set;
import org.dynmap.DynmapCore;
import org.dynmap.common.DynmapChatColor;
import org.dynmap.common.DynmapListenerManager;
import org.dynmap.common.DynmapListenerManager.EventType;
import org.dynmap.common.DynmapPlayer;
import org.dynmap.markers.Marker;
import org.dynmap.markers.MarkerIcon;
import org.dynmap.markers.MarkerSet;
public class MarkerSignManager {
private static MarkerSignManager mgr = null;
private static DynmapCore plugin = null;
private static final int SIGNPOST_ID = 63;
private static final int WALLSIGN_ID = 68;
private static class SignListener implements DynmapListenerManager.BlockEventListener, DynmapListenerManager.SignChangeEventListener {
@Override
public void signChangeEvent(int blkid, String wname, int x, int y, int z, String[] lines, DynmapPlayer p) {
if(mgr == null)
return;
if(!lines[0].equalsIgnoreCase("[dynmap]")) { /* If not dynmap sign, quit */
return;
}
/* If allowed to do marker signs */
if((p == null) || ((plugin != null) && (plugin.checkPlayerPermission(p, "marker.sign")))) {
String id = getSignMarkerID(wname, x, y, z); /* Get marker ID */
String set = MarkerSet.DEFAULT;
String icon = MarkerIcon.SIGN;
String label = "";
lines[0] = ""; /* Blank out [dynmap] */
for(int i = 1; i < 4; i++) { /* Check other lines for icon: or set: */
String v = plugin.getServer().stripChatColor(lines[i]);
if(v.startsWith("icon:")) { /* icon: */
icon = v.substring(5);
lines[i] = "";
}
else if(v.startsWith("set:")) { /* set: */
set = v.substring(4);
lines[i] = "";
}
else if(v.length() > 0) {
if(label.length() > 0) {
label = label + "<br/>";
}
label = label + escapeMarkup(v);
}
}
/* Get the set and see if the marker is already defined */
MarkerSet ms = MarkerAPIImpl.api.getMarkerSet(set);
if(ms == null) {
if(p != null) p.sendMessage("Bad marker set - [dynmap] sign invalid");
lines[0] = DynmapChatColor.RED + "<Bad Marker Set>";
return;
}
MarkerIcon mi = MarkerAPIImpl.api.getMarkerIcon(icon); /* Get icon */
if(mi == null) {
if(p != null) p.sendMessage("Bad marker icon - [dynmap] sign invalid");
lines[0] = DynmapChatColor.RED + "<Bad Marker Icon>";
return;
}
Marker marker = ms.findMarker(id);
/* If exists, update it */
if(marker != null) {
marker.setLabel(label, true);
marker.setMarkerIcon(mi);
}
else { /* Make new marker */
marker = ms.createMarker(id, label, true, wname, (double)x + 0.5, (double)y + 0.5, (double)z + 0.5,
mi, true);
if(marker == null) {
if(p != null) p.sendMessage("Bad marker - [dynmap] sign invalid");
lines[0] = DynmapChatColor.RED + "<Bad Marker>";
return;
}
}
}
}
@Override
public void blockEvent(int blkid, String wname, int x, int y, int z) {
if(mgr == null)
return;
if((blkid == WALLSIGN_ID) || (blkid == SIGNPOST_ID)) { /* If sign */
String id = getSignMarkerID(wname, x, y, z); /* Marker sign? */
Set<MarkerSet> sets = MarkerAPIImpl.api.getMarkerSets();
for(MarkerSet ms : sets) {
Marker marker = ms.findMarker(id); /* See if in this set */
if(marker != null) {
marker.deleteMarker();
}
}
}
}
}
private static SignListener sl = null; /* Do once - /dynmap reload doesn't reset listeners */
private static String escapeMarkup(String v) {
v = v.replace("&", "&amp;");
v = v.replace("\"", "&quote;");
v = v.replace("<", "&lt;");
v = v.replace(">", "&gt;");
return v;
}
public static MarkerSignManager initializeSignManager(DynmapCore plugin) {
mgr = new MarkerSignManager();
if(sl == null) {
sl = new SignListener();
plugin.listenerManager.addListener(EventType.BLOCK_BREAK, sl);
plugin.listenerManager.addListener(EventType.SIGN_CHANGE, sl);
}
MarkerSignManager.plugin = plugin;
return mgr;
}
public static void terminateSignManager(DynmapCore plugin) {
mgr = null;
}
private static String getSignMarkerID(String wname, int x, int y, int z) {
return "_sign_" + wname + "_" + x + "_" + y + "_" + z;
}
}

View file

@ -1,23 +0,0 @@
package org.dynmap.regions;
import org.dynmap.Component;
import org.dynmap.ConfigurationNode;
import org.dynmap.DynmapCore;
import org.dynmap.Log;
public class RegionsComponent extends Component {
private static String deprecated_ids[] = { "Residence", "Factions", "Towny", "WorldGuard" };
private static String deprecated_new_plugins[] = { "dynmap-residence", "Dynmap-Factions", "Dynmap-Towny", "Dynmap-WorldGuard" };
public RegionsComponent(final DynmapCore plugin, final ConfigurationNode configuration) {
super(plugin, configuration);
String regiontype = configuration.getString("name", "WorldGuard");
/* Check if a deprecated component */
for(int i = 0; i < deprecated_ids.length; i++) {
if(regiontype.equals(deprecated_ids[i])) { /* If match */
Log.info("Region component for '" + regiontype + "' has been RETIRED - migrate to '" + deprecated_new_plugins[i] + "' plugin");
}
}
}
}

View file

@ -1,55 +0,0 @@
package org.dynmap.servlet;
import java.io.IOException;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.dynmap.DynmapCore;
import org.dynmap.DynmapWorld;
import org.dynmap.Event;
import org.json.simple.JSONObject;
public class ClientConfigurationServlet extends HttpServlet {
private static final long serialVersionUID = 9106801553080522469L;
private DynmapCore plugin;
private byte[] cachedConfiguration = null;
private int cached_config_hashcode = 0;
public ClientConfigurationServlet(DynmapCore plugin) {
this.plugin = plugin;
plugin.events.addListener("worldactivated", new Event.Listener<DynmapWorld>() {
@Override
public void triggered(DynmapWorld t) {
cachedConfiguration = null;
}
});
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
byte[] outputBytes = cachedConfiguration;
if ((outputBytes == null) || (cached_config_hashcode != plugin.getConfigHashcode())) {
JSONObject json = new JSONObject();
plugin.events.<JSONObject>trigger("buildclientconfiguration", json);
String s = json.toJSONString();
outputBytes = s.getBytes("UTF-8");
}
if (outputBytes != null) {
cachedConfiguration = outputBytes;
cached_config_hashcode = plugin.getConfigHashcode();
}
String dateStr = new Date().toString();
res.addHeader("Date", dateStr);
res.setContentType("text/plain; charset=utf-8");
res.addHeader("Expires", "Thu, 01 Dec 1994 16:00:00 GMT");
res.addHeader("Last-modified", dateStr);
res.setContentLength(outputBytes.length);
res.getOutputStream().write(outputBytes);
}
}

View file

@ -1,74 +0,0 @@
package org.dynmap.servlet;
import static org.dynmap.JSONUtils.s;
import java.io.IOException;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.dynmap.ClientUpdateEvent;
import org.dynmap.DynmapCore;
import org.dynmap.DynmapWorld;
import org.dynmap.web.HttpField;
import org.json.simple.JSONObject;
@SuppressWarnings("serial")
public class ClientUpdateServlet extends HttpServlet {
private DynmapCore plugin;
public ClientUpdateServlet(DynmapCore plugin) {
this.plugin = plugin;
}
Pattern updatePathPattern = Pattern.compile("/([^/]+)/([0-9]*)");
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String path = req.getPathInfo();
Matcher match = updatePathPattern.matcher(path);
if (!match.matches()) {
resp.sendError(404, "World not found");
return;
}
String worldName = match.group(1);
String timeKey = match.group(2);
DynmapWorld dynmapWorld = null;
if(plugin.mapManager != null) {
dynmapWorld = plugin.mapManager.getWorld(worldName);
}
if (dynmapWorld == null || !dynmapWorld.isLoaded()) {
resp.sendError(404, "World not found");
return;
}
long current = System.currentTimeMillis();
long since = 0;
try {
since = Long.parseLong(timeKey);
} catch (NumberFormatException e) {
}
JSONObject u = new JSONObject();
s(u, "timestamp", current);
plugin.events.trigger("buildclientupdate", new ClientUpdateEvent(since, dynmapWorld, u));
byte[] bytes = u.toJSONString().getBytes("UTF-8");
String dateStr = new Date().toString();
resp.addHeader(HttpField.Date, dateStr);
resp.addHeader(HttpField.ContentType, "text/plain; charset=utf-8");
resp.addHeader(HttpField.Expires, "Thu, 01 Dec 1994 16:00:00 GMT");
resp.addHeader(HttpField.LastModified, dateStr);
resp.addHeader(HttpField.ContentLength, Integer.toString(bytes.length));
resp.getOutputStream().write(bytes);
}
}

View file

@ -1,579 +0,0 @@
/*
* net/balusc/webapp/FileServlet.java
*
* Copyright (C) 2009 BalusC
*
* This program is free software: you can redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this library.
* If not, see <http://www.gnu.org/licenses/>.
*/
package org.dynmap.servlet;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.URLDecoder;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPOutputStream;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* A file servlet supporting resume of downloads and client-side caching and GZIP of text content.
* This servlet can also be used for images, client-side caching would become more efficient.
* This servlet can also be used for text files, GZIP would decrease network bandwidth.
*
* @author BalusC
* @link http://balusc.blogspot.com/2009/02/fileservlet-supporting-resume-and.html
*/
@SuppressWarnings("serial")
public class FileServlet extends HttpServlet {
// Constants ----------------------------------------------------------------------------------
private static final int DEFAULT_BUFFER_SIZE = 10240; // ..bytes = 10KB.
private static final String MULTIPART_BOUNDARY = "MULTIPART_BYTERANGES";
// Properties ---------------------------------------------------------------------------------
private String basePath = null;
private boolean allow_symlinks = true;
private String[] indexFiles = new String[] {
"index.html"
};
// Actions ------------------------------------------------------------------------------------
public FileServlet() {
}
public FileServlet(String basePath, boolean allow_symlinks) {
this.basePath = new File(basePath).getAbsolutePath();
this.allow_symlinks = allow_symlinks;
}
/**
* Initialize the servlet.
* @see HttpServlet#init().
*/
public void init() throws ServletException {
if (basePath == null) {
setBasePath(new File(getServletContext().getRealPath(getInitParameter("basePath"))).getAbsolutePath());
}
}
public void setBasePath(String basePath) {
// Validate base path.
if (basePath == null) {
throw new InvalidParameterException("'basePath' is required.");
} else {
File path = new File(basePath);
if (!path.exists()) {
throw new InvalidParameterException("'basePath' value '"
+ basePath + "' does actually not exist in file system.");
} else if (!path.isDirectory()) {
throw new InvalidParameterException("'basePath' value '"
+ basePath + "' is actually not a directory in file system.");
} else if (!path.canRead()) {
throw new InvalidParameterException("'basePath' value '"
+ basePath + "' is actually not readable in file system.");
}
}
this.basePath = basePath;
}
/**
* Process HEAD request. This returns the same headers as GET request, but without content.
* @see HttpServlet#doHead(HttpServletRequest, HttpServletResponse).
*/
protected void doHead(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
// Process request without content.
processRequest(request, response, false);
}
/**
* Process GET request.
* @see HttpServlet#doGet(HttpServletRequest, HttpServletResponse).
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
// Process request with content.
processRequest(request, response, true);
}
private static String getNormalizedPath(String p) {
p = p.replace('\\', '/');
String[] tok = p.split("/");
int i, j;
for(i = 0, j = 0; i < tok.length; i++) {
if((tok[i] == null) || (tok[i].length() == 0) || (tok[i].equals("."))) {
tok[i] = null;
}
else if(tok[i].equals("..")) {
if(j > 0) { j--; tok[j] = null; }
tok[i] = null;
}
else {
tok[j] = tok[i];
j++;
}
}
String path = "";
for(i = 0; i < j; i++) {
if(tok[i] != null)
path = path + "/" + tok[i];
}
return path;
}
/**
* Process the actual request.
* @param request The request to be processed.
* @param response The response to be created.
* @param content Whether the request body should be written (GET) or not (HEAD).
* @throws IOException If something fails at I/O level.
*/
private void processRequest
(HttpServletRequest request, HttpServletResponse response, boolean content)
throws IOException
{
// Validate the requested file ------------------------------------------------------------
// Get requested file by path info.
String requestedFile = request.getPathInfo();
if (requestedFile != null)
requestedFile = getNormalizedPath(requestedFile);
// Check if file is actually supplied to the request URL.
if (requestedFile == null) {
// Do your thing if the file is not supplied to the request URL.
// Throw an exception, or send 404, or show default/warning page, or just ignore it.
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
// URL-decode the file name (might contain spaces and on) and prepare file object.
File file = new File(basePath, URLDecoder.decode(requestedFile, "UTF-8"));
String fpath = null;
if(allow_symlinks)
fpath = file.getAbsolutePath();
else
fpath = file.getCanonicalPath();
if (!fpath.startsWith(basePath)) {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
if (file.isDirectory()) {
File directory = file;
for (int i = 0; i < indexFiles.length; i++) {
file = new File(directory, indexFiles[i]);
if (file.isFile())
break;
}
}
// Check if file actually exists in filesystem.
if (!file.exists()) {
// Do your thing if the file appears to be non-existing.
// Throw an exception, or send 404, or show default/warning page, or just ignore it.
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
// Prepare some variables. The ETag is an unique identifier of the file.
String fileName = file.getName();
long length = file.length();
long lastModified = file.lastModified();
String eTag = fileName + "_" + length + "_" + lastModified;
// Validate request headers for caching ---------------------------------------------------
// If-None-Match header should contain "*" or ETag. If so, then return 304.
String ifNoneMatch = request.getHeader("If-None-Match");
if (ifNoneMatch != null && matches(ifNoneMatch, eTag)) {
response.setHeader("ETag", eTag); // Required in 304.
response.sendError(HttpServletResponse.SC_NOT_MODIFIED);
return;
}
// If-Modified-Since header should be greater than LastModified. If so, then return 304.
// This header is ignored if any If-None-Match header is specified.
long ifModifiedSince = request.getDateHeader("If-Modified-Since");
if (ifNoneMatch == null && ifModifiedSince != -1 && ifModifiedSince + 1000 > lastModified) {
response.setHeader("ETag", eTag); // Required in 304.
response.sendError(HttpServletResponse.SC_NOT_MODIFIED);
return;
}
// Validate request headers for resume ----------------------------------------------------
// If-Match header should contain "*" or ETag. If not, then return 412.
String ifMatch = request.getHeader("If-Match");
if (ifMatch != null && !matches(ifMatch, eTag)) {
response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
return;
}
// If-Unmodified-Since header should be greater than LastModified. If not, then return 412.
long ifUnmodifiedSince = request.getDateHeader("If-Unmodified-Since");
if (ifUnmodifiedSince != -1 && ifUnmodifiedSince + 1000 <= lastModified) {
response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
return;
}
// Validate and process range -------------------------------------------------------------
// Prepare some variables. The full Range represents the complete file.
Range full = new Range(0, length - 1, length);
List<Range> ranges = new ArrayList<Range>();
// Validate and process Range and If-Range headers.
String range = request.getHeader("Range");
if (range != null) {
// Range header should match format "bytes=n-n,n-n,n-n...". If not, then return 416.
if (!range.matches("^bytes=\\d*-\\d*(,\\d*-\\d*)*$")) {
response.setHeader("Content-Range", "bytes */" + length); // Required in 416.
response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
return;
}
// If-Range header should either match ETag or be greater then LastModified. If not,
// then return full file.
String ifRange = request.getHeader("If-Range");
if (ifRange != null && !ifRange.equals(eTag)) {
try {
long ifRangeTime = request.getDateHeader("If-Range"); // Throws IAE if invalid.
if (ifRangeTime != -1 && ifRangeTime + 1000 < lastModified) {
ranges.add(full);
}
} catch (IllegalArgumentException ignore) {
ranges.add(full);
}
}
// If any valid If-Range header, then process each part of byte range.
if (ranges.isEmpty()) {
String[] rangesParts = range.substring(6).split(",");
if (rangesParts.length > 1) {
response.setHeader("Content-Range", "bytes */" + length); // Required in 416.
response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
return;
}
for (String part : rangesParts) {
// Assuming a file with length of 100, the following examples returns bytes at:
// 50-80 (50 to 80), 40- (40 to length=100), -20 (length-20=80 to length=100).
long start = sublong(part, 0, part.indexOf("-"));
long end = sublong(part, part.indexOf("-") + 1, part.length());
if (start == -1) {
start = length - end;
end = length - 1;
} else if (end == -1 || end > length - 1) {
end = length - 1;
}
// Check if Range is syntactically valid. If not, then return 416.
if (start > end) {
response.setHeader("Content-Range", "bytes */" + length); // Required in 416.
response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
return;
}
// Add range.
ranges.add(new Range(start, end, length));
}
}
}
// Prepare and initialize response --------------------------------------------------------
// Get content type by file name and set default GZIP support and content disposition.
boolean acceptsGzip = false;
String disposition = "inline";
String contentType = getContentType(fileName);
// If content type is text, then determine whether GZIP content encoding is supported by
// the browser and expand content type with the one and right character encoding.
if (contentType.startsWith("text")) {
String acceptEncoding = request.getHeader("Accept-Encoding");
acceptsGzip = acceptEncoding != null && accepts(acceptEncoding, "gzip");
contentType += ";charset=UTF-8";
}
// Else, expect for images, determine content disposition. If content type is supported by
// the browser, then set to inline, else attachment which will pop a 'save as' dialogue.
else if (!contentType.startsWith("image")) {
String accept = request.getHeader("Accept");
disposition = accept != null && accepts(accept, contentType) ? "inline" : "attachment";
}
// Initialize response.
response.reset();
response.setBufferSize(DEFAULT_BUFFER_SIZE);
response.setHeader("Content-Disposition", disposition + ";filename=\"" + fileName + "\"");
response.setHeader("Accept-Ranges", "bytes");
response.setHeader("ETag", eTag);
response.setDateHeader("Last-Modified", lastModified);
// Send requested file (part(s)) to client ------------------------------------------------
// Prepare streams.
RandomAccessFile input = null;
OutputStream output = null;
try {
// Open streams.
input = new RandomAccessFile(file, "r");
output = response.getOutputStream();
if (ranges.isEmpty() || ranges.get(0) == full) {
// Return full file.
Range r = full;
response.setContentType(contentType);
response.setHeader("Content-Range", "bytes " + r.start + "-" + r.end + "/" + r.total);
if (content) {
if (acceptsGzip) {
// The browser accepts GZIP, so GZIP the content.
response.setHeader("Content-Encoding", "gzip");
output = new GZIPOutputStream(output, DEFAULT_BUFFER_SIZE);
} else {
// Content length is not directly predictable in case of GZIP.
// So only add it if there is no means of GZIP, else browser will hang.
response.setHeader("Content-Length", String.valueOf(r.length));
}
// Copy full range.
copy(input, output, r.start, r.length);
}
} else if (ranges.size() == 1) {
// Return single part of file.
Range r = ranges.get(0);
response.setContentType(contentType);
response.setHeader("Content-Range", "bytes " + r.start + "-" + r.end + "/" + r.total);
response.setHeader("Content-Length", String.valueOf(r.length));
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); // 206.
if (content) {
// Copy single part range.
copy(input, output, r.start, r.length);
}
} else {
// Return multiple parts of file.
response.setContentType("multipart/byteranges; boundary=" + MULTIPART_BOUNDARY);
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); // 206.
if (content) {
// Cast back to ServletOutputStream to get the easy println methods.
ServletOutputStream sos = (ServletOutputStream) output;
// Copy multi part range.
for (Range r : ranges) {
// Add multipart boundary and header fields for every range.
sos.println();
sos.println("--" + MULTIPART_BOUNDARY);
sos.println("Content-Type: " + contentType);
sos.println("Content-Range: bytes " + r.start + "-" + r.end + "/" + r.total);
// Copy single part range of multi part range.
copy(input, output, r.start, r.length);
}
// End with multipart boundary.
sos.println();
sos.println("--" + MULTIPART_BOUNDARY + "--");
}
}
} finally {
// Gently close streams.
close(output);
close(input);
}
}
// Helpers (can be refactored to public utility class) ----------------------------------------
final static Map<String, String> mimeTypes = new HashMap<String, String>() {{
this.put(".html", "text/html");
this.put(".htm", "text/html");
this.put(".js", "text/javascript");
this.put(".png", "image/png");
this.put(".jpg", "image/jpeg");
this.put(".css", "text/css");
this.put(".txt", "text/plain");
}};
public String getContentType(String fileName) {
// Don't use getServetContext!
/*String contentType = getServletContext().getMimeType(fileName);
*/
String contentType = null;
int i = fileName.lastIndexOf('.');
if (i >= 0) {
String extension = fileName.substring(i);
contentType = mimeTypes.get(extension);
}
if (contentType == null) {
contentType = "application/octet-stream";
}
return contentType;
}
/**
* Returns true if the given accept header accepts the given value.
* @param acceptHeader The accept header.
* @param toAccept The value to be accepted.
* @return True if the given accept header accepts the given value.
*/
private static boolean accepts(String acceptHeader, String toAccept) {
String[] acceptValues = acceptHeader.split("\\s*(,|;)\\s*");
Arrays.sort(acceptValues);
return Arrays.binarySearch(acceptValues, toAccept) > -1
|| Arrays.binarySearch(acceptValues, toAccept.replaceAll("/.*$", "/*")) > -1
|| Arrays.binarySearch(acceptValues, "*/*") > -1;
}
/**
* Returns true if the given match header matches the given value.
* @param matchHeader The match header.
* @param toMatch The value to be matched.
* @return True if the given match header matches the given value.
*/
private static boolean matches(String matchHeader, String toMatch) {
String[] matchValues = matchHeader.split("\\s*,\\s*");
Arrays.sort(matchValues);
return Arrays.binarySearch(matchValues, toMatch) > -1
|| Arrays.binarySearch(matchValues, "*") > -1;
}
/**
* Returns a substring of the given string value from the given begin index to the given end
* index as a long. If the substring is empty, then -1 will be returned
* @param value The string value to return a substring as long for.
* @param beginIndex The begin index of the substring to be returned as long.
* @param endIndex The end index of the substring to be returned as long.
* @return A substring of the given string value as long or -1 if substring is empty.
*/
private static long sublong(String value, int beginIndex, int endIndex) {
String substring = value.substring(beginIndex, endIndex);
return (substring.length() > 0) ? Long.parseLong(substring) : -1;
}
/**
* Copy the given byte range of the given input to the given output.
* @param input The input to copy the given range to the given output for.
* @param output The output to copy the given range from the given input for.
* @param start Start of the byte range.
* @param length Length of the byte range.
* @throws IOException If something fails at I/O level.
*/
private static void copy(RandomAccessFile input, OutputStream output, long start, long length)
throws IOException
{
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
int read;
if (input.length() == length) {
// Write full range.
while ((read = input.read(buffer)) > 0) {
output.write(buffer, 0, read);
}
} else {
// Write partial range.
input.seek(start);
long toRead = length;
while ((read = input.read(buffer)) > 0) {
if ((toRead -= read) > 0) {
output.write(buffer, 0, read);
} else {
output.write(buffer, 0, (int) toRead + read);
break;
}
}
}
}
/**
* Close the given resource.
* @param resource The resource to be closed.
*/
private static void close(Closeable resource) {
if (resource != null) {
try {
resource.close();
} catch (IOException ignore) {
// Ignore IOException. If you want to handle this anyway, it might be useful to know
// that this will generally only be thrown when the client aborted the request.
}
}
}
// Inner classes ------------------------------------------------------------------------------
/**
* This class represents a byte range.
*/
protected class Range {
long start;
long end;
long length;
long total;
/**
* Construct a byte range.
* @param start Start of the byte range.
* @param end End of the byte range.
* @param total Total length of the byte source.
*/
public Range(long start, long end, long total) {
this.start = start;
this.end = end;
this.length = end - start + 1;
this.total = total;
}
}
}

View file

@ -1,17 +0,0 @@
package org.dynmap.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletResponse;
import org.json.simple.JSONStreamAware;
public class JSONServlet {
public static void respond(HttpServletResponse response, JSONStreamAware json) throws IOException {
response.setContentType("application/json");
PrintWriter writer = response.getWriter();
json.writeJSONString(writer);
writer.close();
}
}

View file

@ -1,145 +0,0 @@
package org.dynmap.servlet;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
@SuppressWarnings("serial")
public class MainServlet extends HttpServlet {
public static class Header {
public String name;
public String value;
public Header(String name, String value) {
this.name = name;
this.value = value;
}
}
private static class Registration {
public String pattern;
public HttpServlet servlet;
public Registration(String pattern, HttpServlet servlet) {
this.pattern = pattern;
this.servlet = servlet;
}
}
List<Registration> registrations = new LinkedList<Registration>();
public List<Header> customHeaders = new LinkedList<Header>();
public void addServlet(String pattern, HttpServlet servlet) {
registrations.add(new Registration(pattern, servlet));
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HashMap<String, Object> properties = new HashMap<String, Object>();
String path = req.getPathInfo();
for(Header header : customHeaders) {
resp.setHeader(header.name, header.value);
}
Registration bestMatch = null;
String bestMatchPart = null;
HashMap<String, Object> bestProperties = null;
for (Registration r : registrations) {
String matchingPart = match(r.pattern, path, properties);
if (matchingPart != null) {
if (bestMatchPart == null || bestMatchPart.length() < matchingPart.length()) {
bestMatch = r;
bestMatchPart = matchingPart;
bestProperties = properties;
properties = new HashMap<String, Object>();
}
}
}
if (bestMatch == null) {
resp.sendError(404);
} else {
String leftOverPath = path.substring(bestMatchPart.length());
HttpServletRequest newreq = new RequestWrapper(req, leftOverPath);
for(String key : bestProperties.keySet()) {
newreq.setAttribute(key, bestProperties.get(key));
}
bestMatch.servlet.service(newreq, resp);
}
}
public String match(String pattern, String path, Map<String, Object> properties) {
int patternStart = 0;
int pathStart = 0;
while (patternStart < pattern.length()) {
if (pattern.charAt(patternStart) == '{') {
// Found a variable.
int endOfVariable = pattern.indexOf('}', patternStart+1);
String variableName = pattern.substring(patternStart+1, endOfVariable);
int endOfSection = indexOfAny(path, new char[] { '/', '?' }, pathStart);
if (endOfSection < 0) {
endOfSection = path.length();
}
String variableValue = path.substring(pathStart, endOfSection);
// Store variable.
properties.put(variableName, variableValue);
patternStart = endOfVariable+1;
pathStart = endOfSection;
} else {
int endOfLiteral = pattern.indexOf('{', patternStart);
if (endOfLiteral < 0) {
endOfLiteral = pattern.length();
}
String literal = pattern.substring(patternStart, endOfLiteral);
int endOfPathLiteral = pathStart + literal.length();
if (endOfPathLiteral > path.length()) {
return null;
}
String matchingLiteral = path.substring(pathStart, endOfPathLiteral);
if (!literal.equals(matchingLiteral)) {
return null;
}
patternStart = endOfLiteral;
pathStart = endOfPathLiteral;
}
}
// Return the part of the url that matches the pattern. (if the pattern does not contain any variables, this will be equal to the pattern)
return path.substring(0, pathStart);
}
private int indexOfAny(String s, char[] cs, int startIndex) {
for(int i = startIndex; i < s.length(); i++) {
char c = s.charAt(i);
for(int j = 0; j < cs.length; j++) {
if (c == cs[j]) {
return i;
}
}
}
return -1;
}
class RequestWrapper extends HttpServletRequestWrapper {
String pathInfo;
public RequestWrapper(HttpServletRequest request, String pathInfo) {
super(request);
this.pathInfo = pathInfo;
}
@Override
public String getPathInfo() {
return pathInfo;
}
}
}

View file

@ -1,148 +0,0 @@
package org.dynmap.servlet;
import org.dynmap.DynmapCore;
import org.dynmap.Event;
import org.dynmap.Log;
import org.dynmap.web.HttpStatus;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Logger;
@SuppressWarnings("serial")
public class SendMessageServlet extends HttpServlet {
protected static final Logger log = Logger.getLogger("Minecraft");
private static final JSONParser parser = new JSONParser();
public Event<Message> onMessageReceived = new Event<Message>();
private Charset cs_utf8 = Charset.forName("UTF-8");
public int maximumMessageInterval = 1000;
public boolean hideip = false;
public boolean trustclientname = false;
public String spamMessage = "\"You may only chat once every %interval% seconds.\"";
private HashMap<String, WebUser> disallowedUsers = new HashMap<String, WebUser>();
private LinkedList<WebUser> disallowedUserQueue = new LinkedList<WebUser>();
private Object disallowedUsersLock = new Object();
private HashMap<String,String> useralias = new HashMap<String,String>();
private int aliasindex = 1;
public boolean use_player_login_ip = false;
public boolean require_player_login_ip = false;
public boolean check_user_ban = false;
public DynmapCore core;
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
InputStreamReader reader = new InputStreamReader(request.getInputStream(), cs_utf8);
JSONObject o = null;
try {
o = (JSONObject)parser.parse(reader);
} catch (ParseException e) {
response.sendError(HttpStatus.BadRequest.getCode());
return;
}
final Message message = new Message();
message.name = "";
if(trustclientname) {
message.name = String.valueOf(o.get("name"));
}
boolean isip = true;
if((message.name == null) || message.name.equals("")) {
/* If proxied client address, get original */
if(request.getHeader("X-Forwarded-For") != null)
message.name = request.getHeader("X-Forwarded-For");
/* If from loopback, we're probably getting from proxy - need to trust client */
else if(request.getRemoteAddr() == "127.0.0.1")
message.name = String.valueOf(o.get("name"));
else
message.name = request.getRemoteAddr();
}
if (use_player_login_ip) {
List<String> ids = core.getIDsForIP(message.name);
if (ids != null) {
String id = ids.get(0);
if (check_user_ban) {
if (core.getServer().isPlayerBanned(id)) {
Log.info("Ignore message from '" + message.name + "' - banned player (" + id + ")");
response.sendError(HttpStatus.Forbidden.getCode());
return;
}
}
message.name = ids.get(0);
isip = false;
} else if (require_player_login_ip) {
Log.info("Ignore message from '" + message.name + "' - no matching player login recorded");
response.sendError(HttpStatus.Forbidden.getCode());
return;
}
}
if (hideip && isip) { /* If hiding IP, find or assign alias */
synchronized (disallowedUsersLock) {
String n = useralias.get(message.name);
if (n == null) { /* Make ID */
n = String.format("web-%03d", aliasindex);
aliasindex++;
useralias.put(message.name, n);
}
message.name = n;
}
}
message.message = String.valueOf(o.get("message"));
final long now = System.currentTimeMillis();
synchronized (disallowedUsersLock) {
// Allow users that user that are now allowed to send messages.
while (!disallowedUserQueue.isEmpty()) {
WebUser wu = disallowedUserQueue.getFirst();
if (now >= wu.nextMessageTime) {
disallowedUserQueue.remove();
disallowedUsers.remove(wu.name);
} else {
break;
}
}
WebUser user = disallowedUsers.get(message.name);
if (user == null) {
user = new WebUser() {
{
name = message.name;
nextMessageTime = now + maximumMessageInterval;
}
};
disallowedUsers.put(user.name, user);
disallowedUserQueue.add(user);
} else {
response.sendError(HttpStatus.Forbidden.getCode());
return;
}
}
onMessageReceived.trigger(message);
}
public static class Message {
public String name;
public String message;
}
public static class WebUser {
public long nextMessageTime;
public String name;
}
}

View file

@ -1,88 +0,0 @@
package org.dynmap.utils;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferInt;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
public class DynmapBufferedImage {
public BufferedImage buf_img;
public int[] argb_buf;
public int width;
public int height;
/* BufferedImage cache - we use the same things a lot... */
private static Object lock = new Object();
private static HashMap<Long, LinkedList<DynmapBufferedImage>> imgcache =
new HashMap<Long, LinkedList<DynmapBufferedImage>>(); /* Indexed by resolution - X<<32+Y */
private static final int CACHE_LIMIT = 10;
/**
* Allocate buffered image from pool, if possible
* @param x - x dimension
* @param y - y dimension
*/
public static DynmapBufferedImage allocateBufferedImage(int x, int y) {
DynmapBufferedImage img = null;
synchronized(lock) {
long k = (x<<16) + y;
LinkedList<DynmapBufferedImage> ll = imgcache.get(k);
if(ll != null) {
img = ll.poll();
}
}
if(img != null) { /* Got it - reset it for use */
Arrays.fill(img.argb_buf, 0);
}
else {
img = new DynmapBufferedImage();
img.width = x;
img.height = y;
img.argb_buf = new int[x*y];
}
img.buf_img = createBufferedImage(img.argb_buf, img.width, img.height);
return img;
}
/**
* Return buffered image to pool
*/
public static void freeBufferedImage(DynmapBufferedImage img) {
img.buf_img.flush();
img.buf_img = null; /* Toss bufferedimage - seems to hold on to other memory */
synchronized(lock) {
long k = (img.width<<16) + img.height;
LinkedList<DynmapBufferedImage> ll = imgcache.get(k);
if(ll == null) {
ll = new LinkedList<DynmapBufferedImage>();
imgcache.put(k, ll);
}
if(ll.size() < CACHE_LIMIT) {
ll.add(img);
img = null;
}
}
}
/* ARGB band masks */
private static final int [] band_masks = {0xFF0000, 0xFF00, 0xff, 0xff000000};
/**
* Build BufferedImage from provided ARGB array and dimensions
*/
public static BufferedImage createBufferedImage(int[] argb_buf, int w, int h) {
/* Create integer-base data buffer */
DataBuffer db = new DataBufferInt (argb_buf, w*h);
/* Create writable raster */
WritableRaster raster = Raster.createPackedRaster(db, w, h, w, band_masks, null);
/* RGB color model */
ColorModel color_model = ColorModel.getRGBdefault ();
/* Return buffered image */
return new BufferedImage (color_model, raster, false, null);
}
}

View file

@ -1,227 +0,0 @@
package org.dynmap.utils;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.RandomAccessFile;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.awt.image.BufferedImage;
import java.awt.image.DirectColorModel;
import java.awt.image.WritableRaster;
import java.io.IOException;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import org.dynmap.Log;
import org.dynmap.MapType.ImageFormat;
import org.dynmap.debug.Debug;
/**
* Implements soft-locks for prevent concurrency issues with file updates
*/
public class FileLockManager {
private static Object lock = new Object();
private static HashMap<String, Integer> filelocks = new HashMap<String, Integer>();
private static final Integer WRITELOCK = new Integer(-1);
/**
* Get write lock on file - exclusive lock, no other writers or readers
* @throws InterruptedException
*/
public static boolean getWriteLock(File f) {
String fn = f.getPath();
synchronized(lock) {
boolean got_lock = false;
while(!got_lock) {
Integer lockcnt = filelocks.get(fn); /* Get lock count */
if(lockcnt != null) { /* If any locks, can't get write lock */
try {
lock.wait();
} catch (InterruptedException ix) {
Log.severe("getWriteLock(" + fn + ") interrupted");
return false;
}
}
else {
filelocks.put(fn, WRITELOCK);
got_lock = true;
}
}
}
//Log.info("getWriteLock(" + f + ")");
return true;
}
/**
* Release write lock
*/
public static void releaseWriteLock(File f) {
String fn = f.getPath();
synchronized(lock) {
Integer lockcnt = filelocks.get(fn); /* Get lock count */
if(lockcnt == null)
Log.severe("releaseWriteLock(" + fn + ") on unlocked file");
else if(lockcnt.equals(WRITELOCK)) {
filelocks.remove(fn); /* Remove lock */
lock.notifyAll(); /* Wake up folks waiting for locks */
}
else
Log.severe("releaseWriteLock(" + fn + ") on read-locked file");
}
//Log.info("releaseWriteLock(" + f + ")");
}
/**
* Get read lock on file - multiple readers allowed, blocks writers
*/
public static boolean getReadLock(File f) {
return getReadLock(f, -1);
}
/**
* Get read lock on file - multiple readers allowed, blocks writers - with timeout (msec)
*/
public static boolean getReadLock(File f, long timeout) {
String fn = f.getPath();
synchronized(lock) {
boolean got_lock = false;
long starttime = 0;
if(timeout > 0)
starttime = System.currentTimeMillis();
while(!got_lock) {
Integer lockcnt = filelocks.get(fn); /* Get lock count */
if(lockcnt == null) {
filelocks.put(fn, Integer.valueOf(1)); /* First lock */
got_lock = true;
}
else if(!lockcnt.equals(WRITELOCK)) { /* Other read locks */
filelocks.put(fn, Integer.valueOf(lockcnt+1));
got_lock = true;
}
else { /* Write lock in place */
try {
if(timeout < 0) {
lock.wait();
}
else {
long now = System.currentTimeMillis();
long elapsed = now-starttime;
if(elapsed > timeout) /* Give up on timeout */
return false;
lock.wait(timeout-elapsed);
}
} catch (InterruptedException ix) {
Log.severe("getReadLock(" + fn + ") interrupted");
return false;
}
}
}
}
//Log.info("getReadLock(" + f + ")");
return true;
}
/**
* Release read lock
*/
public static void releaseReadLock(File f) {
String fn = f.getPath();
synchronized(lock) {
Integer lockcnt = filelocks.get(fn); /* Get lock count */
if(lockcnt == null)
Log.severe("releaseReadLock(" + fn + ") on unlocked file");
else if(lockcnt.equals(WRITELOCK))
Log.severe("releaseReadLock(" + fn + ") on write-locked file");
else if(lockcnt > 1) {
filelocks.put(fn, Integer.valueOf(lockcnt-1));
}
else {
filelocks.remove(fn); /* Remove lock */
lock.notifyAll(); /* Wake up folks waiting for locks */
}
}
//Log.info("releaseReadLock(" + f + ")");
}
private static final int MAX_WRITE_RETRIES = 6;
private static LinkedList<ByteArrayOutputStream> baoslist = new LinkedList<ByteArrayOutputStream>();
private static Object baos_lock = new Object();
/**
* Wrapper for IOImage.write - implements retries for busy files
*/
public static void imageIOWrite(BufferedImage img, ImageFormat fmt, File fname) throws IOException {
int retrycnt = 0;
boolean done = false;
byte[] rslt;
ByteArrayOutputStream baos;
synchronized(baos_lock) {
if(baoslist.isEmpty()) {
baos = new ByteArrayOutputStream();
}
else {
baos = baoslist.removeFirst();
baos.reset();
}
}
ImageIO.setUseCache(false); /* Don't use file cache - too small to be worth it */
if(fmt.getFileExt().equals("jpg")) {
WritableRaster raster = img.getRaster();
WritableRaster newRaster = raster.createWritableChild(0, 0, img.getWidth(),
img.getHeight(), 0, 0, new int[] {0, 1, 2});
DirectColorModel cm = (DirectColorModel)img.getColorModel();
DirectColorModel newCM = new DirectColorModel(cm.getPixelSize(),
cm.getRedMask(), cm.getGreenMask(), cm.getBlueMask());
// now create the new buffer that is used ot write the image:
BufferedImage rgbBuffer = new BufferedImage(newCM, newRaster, false, null);
// Find a jpeg writer
ImageWriter writer = null;
Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName("jpg");
if (iter.hasNext()) {
writer = iter.next();
}
if(writer == null) {
Log.severe("No JPEG ENCODER - Java VM does not support JPEG encoding");
return;
}
ImageWriteParam iwp = writer.getDefaultWriteParam();
iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
iwp.setCompressionQuality(fmt.getQuality());
ImageOutputStream ios = ImageIO.createImageOutputStream(baos);
writer.setOutput(ios);
writer.write(null, new IIOImage(rgbBuffer, null, null), iwp);
writer.dispose();
rgbBuffer.flush();
}
else {
ImageIO.write(img, fmt.getFileExt(), baos); /* Write to byte array stream - prevent bogus I/O errors */
}
rslt = baos.toByteArray();
synchronized(baos_lock) {
baoslist.addFirst(baos);
}
while(!done) {
RandomAccessFile f = null;
try {
f = new RandomAccessFile(fname, "rw");
f.write(rslt);
done = true;
} catch (IOException fnfx) {
if(retrycnt < MAX_WRITE_RETRIES) {
Debug.debug("Image file " + fname.getPath() + " - unable to write - retry #" + retrycnt);
try { Thread.sleep(50 << retrycnt); } catch (InterruptedException ix) { throw fnfx; }
retrycnt++;
}
else {
Log.info("Image file " + fname.getPath() + " - unable to write - failed");
throw fnfx;
}
} finally {
if(f != null) {
try { f.close(); } catch (IOException iox) {}
}
}
}
}
}

View file

@ -1,16 +0,0 @@
package org.dynmap.utils;
import java.util.LinkedHashMap;
import java.util.Map;
@SuppressWarnings("serial")
public class LRULinkedHashMap<T, K> extends LinkedHashMap<T, K> {
private int limit;
public LRULinkedHashMap(int lim) {
super(16, (float)0.75, true);
limit = lim;
}
protected boolean removeEldestEntry(Map.Entry<T, K> last) {
return(size() >= limit);
}
}

View file

@ -1,119 +0,0 @@
package org.dynmap.utils;
import org.dynmap.DynmapWorld;
import org.dynmap.common.BiomeMap;
public interface MapChunkCache {
public enum HiddenChunkStyle {
FILL_AIR,
FILL_STONE_PLAIN,
FILL_OCEAN
};
public static class VisibilityLimit {
public int x0, x1, z0, z1;
}
/**
* Set chunk data type needed
* @param blockdata - need block type and data for chunk
* @param biome - need biome data
* @param highestblocky - need highest-block-y data
* @param rawbiome - need raw biome temp/rain data
* @return true if all data types can be retrieved, false if not
*/
boolean setChunkDataTypes(boolean blockdata, boolean biome, boolean highestblocky, boolean rawbiome);
/**
* Load chunks into cache
* @param maxToLoad - maximum number to load at once
* @return number loaded
*/
int loadChunks(int maxToLoad);
/**
* Test if done loading
*/
boolean isDoneLoading();
/**
* Test if all empty blocks
*/
boolean isEmpty();
/**
* Unload chunks
*/
void unloadChunks();
/**
* Get block ID at coordinates
*/
int getBlockTypeID(int x, int y, int z);
/**
* Get block data at coordiates
*/
byte getBlockData(int x, int y, int z);
/**
* Get highest block Y
*/
int getHighestBlockYAt(int x, int z);
/**
* Get sky light level
*/
int getBlockSkyLight(int x, int y, int z);
/**
* Get emitted light level
*/
int getBlockEmittedLight(int x, int y, int z);
/**
* Get biome at coordinates
*/
public BiomeMap getBiome(int x, int z);
/**
* Get raw temperature data (0.0-1.0)
*/
public double getRawBiomeTemperature(int x, int z);
/**
* Get raw rainfall data (0.0-1.0)
*/
public double getRawBiomeRainfall(int x, int z);
/**
* Get cache iterator
*/
public MapIterator getIterator(int x, int y, int z);
/**
* Set hidden chunk style (default is FILL_AIR)
*/
public void setHiddenFillStyle(HiddenChunkStyle style);
/**
* Add visible area limit - can be called more than once
* Needs to be set before chunks are loaded
* Coordinates are block coordinates
*/
public void setVisibleRange(VisibilityLimit limit);
/**
* Add hidden area limit - can be called more than once
* Needs to be set before chunks are loaded
* Coordinates are block coordinates
*/
public void setHiddenRange(VisibilityLimit limit);
/**
* Set autogenerate - must be done after at least one visible range has been set
*/
public void setAutoGenerateVisbileRanges(DynmapWorld.AutoGenerateOption do_generate);
/**
* Get world
*/
public DynmapWorld getWorld();
/**
* Get total chunks loaded
* @return
*/
public int getChunksLoaded();
/**
* Get total chunk loads attempted
* @return
*/
public int getChunkLoadsAttempted();
/**
* Get total run time processing chunks
* @return
*/
public long getTotalRuntimeNanos();
public long getExceptionCount();
}

View file

@ -1,103 +0,0 @@
package org.dynmap.utils;
import org.dynmap.common.BiomeMap;
/**
* Iterator for traversing map chunk cache (base is for non-snapshot)
*/
public interface MapIterator {
/* Represents last step of movement of the ray (don't alter order here - ordinal sensitive) */
public enum BlockStep {
X_PLUS,
Y_PLUS,
Z_PLUS,
X_MINUS,
Y_MINUS,
Z_MINUS;
};
/**
* Initialize iterator at given coordinates
*
* @param x0
* @param y0
* @param z0
*/
void initialize(int x0, int y0, int z0);
/**
* Get block ID at current coordinates
*
* @return block id
*/
int getBlockTypeID();
/**
* Get block data at current coordinates
* @return block data
*/
int getBlockData();
/**
* Get highest block Y coordinate at current X,Z
* @return highest block coord
*/
int getHighestBlockYAt();
/**
* Get block sky light level at current coordinate
* @return sky light level
*/
int getBlockSkyLight();
/**
* Get emitted light level at current coordinate
* @return emitted light level
*/
int getBlockEmittedLight();
/**
* Get biome at coordinates
*/
public BiomeMap getBiome();
/**
* Get raw temperature data (0.0-1.0)
*/
public double getRawBiomeTemperature();
/**
* Get raw rainfall data (0.0-1.0)
*/
public double getRawBiomeRainfall();
/**
* Step current position in given direction
*/
void stepPosition(BlockStep step);
/**
* Step current position in opposite of given direction
*/
void unstepPosition(BlockStep step);
/**
* Unstep current position to previous position : return step to take to return
*/
BlockStep unstepPosition();
/**
* Set Y coordinate of current position
* @param y
*/
void setY(int y);
/**
* Get X coordinate
*/
int getX();
/**
* Get Y coordinate
*/
int getY();
/**
* Get Z coordinate
*/
int getZ();
/**
* Get block ID at 1 step in given direction
*
* @return block id
*/
int getBlockTypeIDAt(BlockStep s);
/**
* Get last step taken
*/
BlockStep getLastStep();
}

View file

@ -1,139 +0,0 @@
package org.dynmap.utils;
import org.json.simple.JSONArray;
/**
* Basic 3D matrix math class - prevent dependency on Java 3D for this
*/
public class Matrix3D {
private double m11, m12, m13, m21, m22, m23, m31, m32, m33;
/**
* Construct identity matrix
*/
public Matrix3D() {
m11 = m22 = m33 = 1.0;
m12 = m13 = m21 = m23 = m31 = m32 = 0.0;
}
/**
* Construct matrix with given parms
*
* @param m11 - first cell of first row
* @param m12 - second cell of first row
* @param m13 - third cell of first row
* @param m21 - first cell of second row
* @param m22 - second cell of second row
* @param m23 - third cell of second row
* @param m31 - first cell of third row
* @param m32 - second cell of third row
* @param m33 - third cell of third row
*/
public Matrix3D(double m11, double m12, double m13, double m21, double m22, double m23, double m31, double m32, double m33) {
this.m11 = m11; this.m12 = m12; this.m13 = m13;
this.m21 = m21; this.m22 = m22; this.m23 = m23;
this.m31 = m31; this.m32 = m32; this.m33 = m33;
}
/**
* Multiply matrix by another matrix (this = mat * this), and store result in self
* @param mat
*/
public void multiply(Matrix3D mat) {
double new_m11 = mat.m11*m11 + mat.m12*m21 + mat.m13*m31;
double new_m12 = mat.m11*m12 + mat.m12*m22 + mat.m13*m32;
double new_m13 = mat.m11*m13 + mat.m12*m23 + mat.m13*m33;
double new_m21 = mat.m21*m11 + mat.m22*m21 + mat.m23*m31;
double new_m22 = mat.m21*m12 + mat.m22*m22 + mat.m23*m32;
double new_m23 = mat.m21*m13 + mat.m22*m23 + mat.m23*m33;
double new_m31 = mat.m31*m11 + mat.m32*m21 + mat.m33*m31;
double new_m32 = mat.m31*m12 + mat.m32*m22 + mat.m33*m32;
double new_m33 = mat.m31*m13 + mat.m32*m23 + mat.m33*m33;
m11 = new_m11; m12 = new_m12; m13 = new_m13;
m21 = new_m21; m22 = new_m22; m23 = new_m23;
m31 = new_m31; m32 = new_m32; m33 = new_m33;
}
/**
* Scale each coordinate by given values
*
* @param s1
* @param s2
* @param s3
*/
public void scale(double s1, double s2, double s3) {
Matrix3D scalemat = new Matrix3D(s1, 0, 0, 0, s2, 0, 0, 0, s3);
multiply(scalemat);
}
/**
* Rotate XY clockwise around +Z axis
* @param rot_deg - degrees of rotation
*/
public void rotateXY(double rot_deg) {
double rot_rad = Math.toRadians(rot_deg);
double sin_rot = Math.sin(rot_rad);
double cos_rot = Math.cos(rot_rad);
Matrix3D rotmat = new Matrix3D(cos_rot, sin_rot, 0, -sin_rot, cos_rot, 0, 0, 0, 1);
multiply(rotmat);
}
/**
* Rotate YZ clockwise around +X axis
* @param rot_deg - degrees of rotation
*/
public void rotateYZ(double rot_deg) {
double rot_rad = Math.toRadians(rot_deg);
double sin_rot = Math.sin(rot_rad);
double cos_rot = Math.cos(rot_rad);
Matrix3D rotmat = new Matrix3D(1, 0, 0, 0, cos_rot, sin_rot, 0, -sin_rot, cos_rot);
multiply(rotmat);
}
/**
* Shear along Z axis by factor of X and Y
*/
public void shearZ(double x_fact, double y_fact) {
Matrix3D shearmat = new Matrix3D(1, 0, 0, 0, 1, 0, x_fact, y_fact, 1);
multiply(shearmat);
}
/**
* Transform a given vector using the matrix
*/
public final void transform(double[] v) {
double v1 = m11*v[0] + m12*v[1] + m13*v[2];
double v2 = m21*v[0] + m22*v[1] + m23*v[2];
double v3 = m31*v[0] + m32*v[1] + m33*v[2];
v[0] = v1; v[1] = v2; v[2] = v3;
}
/**
* Transform a given vector using the matrix
*/
public final void transform(Vector3D v) {
double v1 = m11*v.x + m12*v.y + m13*v.z;
double v2 = m21*v.x + m22*v.y + m23*v.z;
double v3 = m31*v.x + m32*v.y + m33*v.z;
v.x = v1; v.y = v2; v.z = v3;
}
/**
* Transform a given vector using the matrix - put result in provided output vector
*/
public final void transform(Vector3D v, Vector3D outv) {
outv.x = m11*v.x + m12*v.y + m13*v.z;
outv.y = m21*v.x + m22*v.y + m23*v.z;
outv.z = m31*v.x + m32*v.y + m33*v.z;
}
public String toString() {
return "[ [" + m11 + " " + m12 + " " + m13 + "] [" + m21 + " " + m22 + " " + m23 + "] [" + m31 + " " + m32 + " " + m33 + "] ]";
}
@SuppressWarnings("unchecked")
public JSONArray toJSON() {
JSONArray array = new JSONArray();
array.add(m11);
array.add(m12);
array.add(m13);
array.add(m21);
array.add(m22);
array.add(m23);
array.add(m31);
array.add(m32);
array.add(m33);
return array;
}
}

View file

@ -1,106 +0,0 @@
package org.dynmap.utils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.dynmap.Log;
/**
* scalable flags primitive - used for keeping track of potentially huge number of tiles
*
* Represents a flag for each tile, with 2D coordinates based on 0,0 origin. Flags are grouped
* 64 x 64, represented by an array of 64 longs. Each set is stored in a hashmap, keyed by a long
* computed by ((x/64)<<32)+(y/64).
*
*/
public class TileFlags {
private HashMap<Long, long[]> chunkmap = new HashMap<Long, long[]>();
private long last_key = Long.MAX_VALUE;
private long[] last_row;
public TileFlags() {
}
public List<String> save() {
ArrayList<String> v = new ArrayList<String>();
StringBuilder sb = new StringBuilder();
for(Map.Entry<Long, long[]> ent : chunkmap.entrySet()) {
long v1 = ent.getKey().longValue();
sb.append(String.format("%x/%x", ((v1>>32)&0xFFFFFFFFL), (v1 & 0xFFFFFFFFL) ));
long[] val = ent.getValue();
for(long vv : val) {
sb.append(String.format(":%x/%x", ((vv>>32) & 0xFFFFFFFFL), (vv & 0xFFFFFFFFL)));
}
v.add(sb.toString());
sb.setLength(0);
}
return v;
}
public void load(List<String> vals) {
clear();
for(String v : vals) {
String[] tok = v.split(":");
long[] row = new long[64];
try {
String ss[] = tok[0].split("/");
long rowaddr = (Long.parseLong(ss[0], 16)<<32) | Long.parseLong(ss[1],16);
for(int i = 0; (i < 64) && (i < (tok.length-1)); i++) {
ss = tok[i+1].split("/");
row[i] = (Long.parseLong(ss[0], 16)<<32) | Long.parseLong(ss[1],16);
}
chunkmap.put(rowaddr, row);
} catch (NumberFormatException nfx) {
Log.info("parse error - " + nfx);
}
}
}
public boolean getFlag(int x, int y) {
long k = (((long)(x >> 6)) << 32) | (0xFFFFFFFFL & (long)(y >> 6));
long[] row;
if(k == last_key) {
row = last_row;
}
else {
row = chunkmap.get(k);
last_key = k;
last_row = row;
}
if(row == null)
return false;
else
return (row[y & 0x3F] & (1L << (x & 0x3F))) != 0;
}
public void setFlag(int x, int y, boolean f) {
long k = (((long)(x >> 6)) << 32) | (0xFFFFFFFFL & (long)(y >> 6));
long[] row;
if(k == last_key) {
row = last_row;
}
else {
row = chunkmap.get(k);
last_key = k;
last_row = row;
}
if(f) {
if(row == null) {
row = new long[64];
chunkmap.put(k, row);
last_row = row;
}
row[y & 0x3F] |= (1L << (x & 0x3F));
}
else {
if(row != null)
row[y & 0x3F] &= ~(1L << (x & 0x3F));
}
}
public void clear() {
chunkmap.clear();
last_row = null;
last_key = Long.MAX_VALUE;
}
}

View file

@ -1,16 +0,0 @@
package org.dynmap.utils;
import org.dynmap.DynmapLocation;
/**
* Simple vector class
*/
public class Vector3D {
public double x, y, z;
public Vector3D() { x = y = z = 0.0; }
public void setFromLocation(DynmapLocation l) { x = l.x; y = l.y; z = l.z; }
public String toString() {
return "{ " + x + ", " + y + ", " + z + " }";
}
}

View file

@ -1,61 +0,0 @@
package org.dynmap.web;
import org.dynmap.DynmapCore;
import org.dynmap.Log;
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashSet;
public class BanIPFilter implements Filter {
private DynmapCore core;
private HashSet<String> banned_ips = new HashSet<String>();
private HashSet<String> banned_ips_notified = new HashSet<String>();
private long last_loaded = 0;
private static final long BANNED_RELOAD_INTERVAL = 15000; /* Every 15 seconds */
public BanIPFilter(DynmapCore core) {
this.core = core;
}
@Override
public void init(FilterConfig filterConfig) throws ServletException { }
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletResponse resp = (HttpServletResponse)response;
String ipaddr = request.getRemoteAddr();
if (isIpBanned(ipaddr)) {
Log.info("Rejected connection by banned IP address - " + ipaddr);
resp.sendError(403);
} else {
chain.doFilter(request, response);
}
}
private void loadBannedIPs() {
banned_ips.clear();
banned_ips_notified.clear();
banned_ips.addAll(core.getIPBans());
}
/* Return true if address is banned */
public boolean isIpBanned(String ipaddr) {
long t = System.currentTimeMillis();
if((t < last_loaded) || ((t-last_loaded) > BANNED_RELOAD_INTERVAL)) {
loadBannedIPs();
last_loaded = t;
}
if(banned_ips.contains(ipaddr)) {
if(!banned_ips_notified.contains(ipaddr)) {
banned_ips_notified.add(ipaddr);
}
return true;
}
return false;
}
@Override
public void destroy() { }
}

View file

@ -1,62 +0,0 @@
package org.dynmap.web;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Logger;
public class BoundInputStream extends InputStream {
protected static final Logger log = Logger.getLogger("Minecraft");
protected static final String LOG_PREFIX = "[dynmap] ";
private InputStream base;
private long bound;
public BoundInputStream(InputStream base, long bound) {
this.base = base;
this.bound = bound;
}
@Override
public int read() throws IOException {
if (bound <= 0) return -1;
int r = base.read();
if (r >= 0)
bound--;
return r;
}
@Override
public int available() throws IOException {
return (int)Math.min(base.available(), bound);
}
@Override
public boolean markSupported() {
return false;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
if (bound <= 0) return -1;
len = (int)Math.min(bound, len);
int r = base.read(b, off, len);
bound -= r;
return r;
}
@Override
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
@Override
public long skip(long n) throws IOException {
long r = base.skip(Math.min(bound, n));
bound -= r;
return r;
}
@Override
public void close() throws IOException {
base.close();
}
}

View file

@ -1,38 +0,0 @@
package org.dynmap.web;
import org.dynmap.ConfigurationNode;
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class CustomHeaderFilter implements Filter {
private final ConfigurationNode custhttp;
public CustomHeaderFilter(ConfigurationNode configuration) {
this.custhttp = configuration;
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletResponse resp = (HttpServletResponse) response;
if (custhttp != null) {
for (String k : custhttp.keySet()) {
String v = custhttp.getString(k);
if (v != null) {
resp.setHeader(k, v);
}
}
}
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}

View file

@ -1,62 +0,0 @@
package org.dynmap.web;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.servlet.FilterHolder;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;
public class FilterHandler extends AbstractHandler {
private Handler handler;
private LinkedList<FilterHolder> filters = new LinkedList<FilterHolder>();
public FilterHandler() {
}
public FilterHandler(Handler handler, Iterable<Filter> filters) {
this.handler = handler;
for(Filter f : filters) {
this.filters.add(new FilterHolder(f));
}
}
public Handler getHandler() {
return handler;
}
public void setHandler(Handler handler) {
this.handler = handler;
}
public Iterable<FilterHolder> getFilters() {
return filters;
}
public void addFilter(Filter filter) {
filters.add(new FilterHolder(filter));
}
@Override
public void handle(final String target, final Request baseRequest, final HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException {
final Handler handler = this.getHandler();
final Iterator<FilterHolder> iterator = getFilters().iterator();
final FilterChain chain = new FilterChain() {
@Override
public void doFilter(ServletRequest re, ServletResponse rs) throws IOException, ServletException {
if (iterator.hasNext()) {
Filter f = iterator.next().getFilter();
f.doFilter(request, response, this);
} else {
handler.handle(target, baseRequest, request, response);
}
}
};
chain.doFilter(request, response);
}
}

View file

@ -1,59 +0,0 @@
package org.dynmap.web;
import org.eclipse.jetty.http.PathMap;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class HandlerRouter extends AbstractHandler {
PathMap pathMap = new PathMap();
public HandlerRouter() {
}
public void addHandler(String path, Handler handler) {
pathMap.put(path, handler);
}
public void addServlet(String path, Servlet servlet) {
pathMap.put(path, servlet);
}
public void clear() {
pathMap.clear();
}
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
String pathInfo = request.getPathInfo();
PathMap.Entry e = pathMap.getMatch(pathInfo);
String mappedPath = e.getMapped();
String childPathInfo = pathInfo;
if (mappedPath != null) {
int i = 0;
while(i<mappedPath.length() && mappedPath.charAt(i) == pathInfo.charAt(i)){ i++; }
childPathInfo = childPathInfo.substring(i);
}
org.eclipse.jetty.server.Request r = (org.eclipse.jetty.server.Request)request;
r.setPathInfo(childPathInfo);
Object o = e.getValue();
if (o instanceof Handler) {
Handler h = (Handler)o;
h.handle(target, baseRequest, request, response);
} else if (o instanceof Servlet) {
Servlet s = (Servlet)o;
s.service(request, response);
}
r.setPathInfo(pathInfo);
}
}

View file

@ -1,52 +0,0 @@
package org.dynmap.web;
public class HttpField {
// Reference: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
public static final String Accept = "Accept";
public static final String AcceptCharset = "Accept-Charset";
public static final String AcceptEncoding = "Accept-Encoding";
public static final String AcceptLanguage = "Accept-Language";
public static final String AcceptRanges = "Accept-Ranges";
public static final String Age = "Age";
public static final String Allow = "Allow";
public static final String Authorization = "Authorization";
public static final String CacheControl = "Cache-Control";
public static final String Connection = "Connection";
public static final String ContentEncoding = "Content-Encoding";
public static final String ContentLanguage = "Content-Language";
public static final String ContentLength = "Content-Length";
public static final String ContentLocation = "Content-Location";
public static final String ContentRange = "Content-Range";
public static final String ContentType = "Content-Type";
public static final String Date = "Date";
public static final String ETag = "ETag";
public static final String Expect = "Expect";
public static final String Expires = "Expires";
public static final String From = "From";
public static final String Host = "Host";
public static final String IfMatch = "If-Match";
public static final String IfModifiedSince = "If-Modified-Since";
public static final String IfNoneMatch = "If-None-Match";
public static final String IfRange = "If-Range";
public static final String IfUnmodifiedSince = "If-Unmodified-Since";
public static final String LastModified = "Last-Modified";
public static final String Location = "Location";
public static final String MaxForwards = "Max-Forwards";
public static final String Pragma = "Pragma";
public static final String ProxyAuthenticate = "Proxy-Authenticate";
public static final String ProxyAuthorization = "Proxy-Authorization";
public static final String Range = "Range";
public static final String Referer = "Referer";
public static final String RetryAfter = "Retry-After";
public static final String Server = "Server";
public static final String TE = "TE";
public static final String Trailer = "Trailer";
public static final String TransferEncoding = "Transfer-Encoding";
public static final String Upgrade = "Upgrade";
public static final String UserAgent = "User-Agent";
public static final String Vary = "Vary";
public static final String Via = "Via";
public static final String Warning = "Warning";
public static final String WwwAuthenticate = "WWW-Authenticate";
}

View file

@ -1,8 +0,0 @@
package org.dynmap.web;
public final class HttpMethod {
public static final String Get = "GET";
public static final String Post = "POST";
public static final String Put = "PUT";
public static final String Delete = "DELETE";
}

View file

@ -1,61 +0,0 @@
package org.dynmap.web;
public final class HttpStatus {
private int code;
private String text;
public int getCode() {
return code;
}
public String getText() {
return text;
}
public HttpStatus(int code, String text) {
this.code = code;
this.text = text;
}
// Reference: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
public static final HttpStatus Continue = new HttpStatus(100, "Continue");
public static final HttpStatus SwitchingProtocols = new HttpStatus(101, "Switching Protocols");
public static final HttpStatus OK = new HttpStatus(200, "OK");
public static final HttpStatus Created = new HttpStatus(201, "Created");
public static final HttpStatus Accepted = new HttpStatus(202, "Accepted");
public static final HttpStatus NonAuthoritativeInformation = new HttpStatus(203, "Non-Authoritative Information");
public static final HttpStatus NoContent = new HttpStatus(204, "No Content");
public static final HttpStatus ResetContent = new HttpStatus(205, "Reset Content");
public static final HttpStatus PartialContent = new HttpStatus(206, "Partial Content");
public static final HttpStatus MultipleChoices = new HttpStatus(300, "Multiple Choices");
public static final HttpStatus MovedPermanently = new HttpStatus(301, "Moved Permanently");
public static final HttpStatus Found = new HttpStatus(302, "Found");
public static final HttpStatus SeeOther = new HttpStatus(303, "See Other");
public static final HttpStatus NotModified = new HttpStatus(304, "Not Modified");
public static final HttpStatus UseProxy = new HttpStatus(305, "Use Proxy");
public static final HttpStatus TemporaryRedirect = new HttpStatus(307, "Temporary Redirect");
public static final HttpStatus BadRequest = new HttpStatus(400, "Bad Request");
public static final HttpStatus Unauthorized = new HttpStatus(401, "Unauthorized");
public static final HttpStatus PaymentRequired = new HttpStatus(402, "Payment Required");
public static final HttpStatus Forbidden = new HttpStatus(403, "Forbidden");
public static final HttpStatus NotFound = new HttpStatus(404, "Not Found");
public static final HttpStatus MethodNotAllowed = new HttpStatus(405, "Method Not Allowed");
public static final HttpStatus NotAcceptable = new HttpStatus(406, "Not Acceptable");
public static final HttpStatus ProxyAuthenticationRequired = new HttpStatus(407, "Proxy Authentication Required");
public static final HttpStatus RequestTimeout = new HttpStatus(408, "Request Timeout");
public static final HttpStatus Conflict = new HttpStatus(409, "Conflict");
public static final HttpStatus Gone = new HttpStatus(410, "Gone");
public static final HttpStatus LengthRequired = new HttpStatus(411, "Length Required");
public static final HttpStatus PreconditionFailed = new HttpStatus(412, "Precondition Failed");
public static final HttpStatus RequestEntityTooLarge = new HttpStatus(413, "Request Entity Too Large");
public static final HttpStatus RequestURITooLong = new HttpStatus(414, "Request-URI Too Long");
public static final HttpStatus UnsupportedMediaType = new HttpStatus(415, "Unsupported Media Type");
public static final HttpStatus RequestedRangeNotSatisfiable = new HttpStatus(416, "Requested Range Not Satisfiable");
public static final HttpStatus ExpectationFailed = new HttpStatus(417, "Expectation Failed");
public static final HttpStatus InternalServerError = new HttpStatus(500, "Internal Server Error");
public static final HttpStatus NotImplemented = new HttpStatus(501, "Not Implemented");
public static final HttpStatus BadGateway = new HttpStatus(502, "Bad Gateway");
public static final HttpStatus ServiceUnavailable = new HttpStatus(503, "Service Unavailable");
public static final HttpStatus GatewayTimeout = new HttpStatus(504, "Gateway Timeout");
public static final HttpStatus HttpVersionNotSupported = new HttpStatus(505, "HTTP Version Not Supported");
}

View file

@ -1,135 +0,0 @@
package org.dynmap.web;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.Map;
public class Json {
public static String stringifyJson(Object o) {
StringBuilder sb = new StringBuilder();
appendJson(o, sb);
return sb.toString();
}
public static void escape(String s, StringBuilder s2) {
for(int i=0;i<s.length();i++){
char ch=s.charAt(i);
switch(ch){
case '"':
s2.append("\\\"");
break;
case '\\':
s2.append("\\\\");
break;
case '\b':
s2.append("\\b");
break;
case '\f':
s2.append("\\f");
break;
case '\n':
s2.append("\\n");
break;
case '\r':
s2.append("\\r");
break;
case '\t':
s2.append("\\t");
break;
case '/':
s2.append("\\/");
break;
default:
if((ch>='\u0000' && ch<='\u001F') || (ch>='\u007F')){
String ss=Integer.toHexString(ch);
s2.append("\\u");
for(int k=0;k<4-ss.length();k++){
s2.append('0');
}
s2.append(ss.toUpperCase());
}
else{
s2.append(ch);
}
}
}//for
}
public static void appendJson(Object o, StringBuilder s) {
if (o == null) {
s.append("null");
} else if (o instanceof Boolean) {
s.append(((Boolean) o) ? "true" : "false");
} else if (o instanceof String) {
s.append("\"");
escape((String)o, s);
s.append("\"");
} else if (o instanceof Integer || o instanceof Long || o instanceof Float || o instanceof Double) {
s.append(o.toString());
} else if (o instanceof Map<?, ?>) {
Map<?, ?> m = (Map<?, ?>) o;
s.append("{");
boolean first = true;
for (Map.Entry<?, ?> entry : m.entrySet()) {
if (first)
first = false;
else
s.append(",");
appendJson(entry.getKey(), s);
s.append(": ");
appendJson(entry.getValue(), s);
}
s.append("}");
} else if (o instanceof List<?>) {
List<?> l = (List<?>) o;
s.append("[");
int count = 0;
for (int i = 0; i < l.size(); i++) {
if (count++ > 0) s.append(",");
appendJson(l.get(i), s);
}
s.append("]");
} else if (o.getClass().isArray()) {
int length = Array.getLength(o);
s.append("[");
int count = 0;
for (int i = 0; i < length; i++) {
if (count++ > 0) s.append(",");
appendJson(Array.get(o, i), s);
}
s.append("]");
} else if (o instanceof Object) /* TODO: Always true, maybe interface? */ {
s.append("{");
boolean first = true;
Class<?> c = o.getClass();
for(Field field : c.getFields()) {
if (!Modifier.isPublic(field.getModifiers()))
continue;
String fieldName = field.getName();
Object fieldValue;
try {
fieldValue = field.get(o);
} catch (IllegalArgumentException e) {
continue;
} catch (IllegalAccessException e) {
continue;
}
if (first)
first = false;
else
s.append(",");
appendJson(fieldName, s);
s.append(": ");
appendJson(fieldValue, s);
}
s.append("}");
} else {
s.append("undefined");
}
}
}