Compare commits

...

45 Commits

Author SHA1 Message Date
mikeprimm bf2ea7d1e3 Fix zoom so that markers are placed properly 2011-05-14 12:34:36 +02:00
FrozenCow e25c9a82b3 Changed version to 0.16.1 2011-05-14 12:33:03 +02:00
Mike Primm 1e3ceed5d7 Add zooming to flat map (why not? :) ) 2011-05-13 10:59:06 +02:00
FrozenCow 88ff70ac48 Added formatting profile which is used for Dynmap. This should look a lot like the profile used in Bukkit. 2011-05-13 10:48:37 +02:00
FrozenCow 84d01c530a Replaced tabs with spaces to conform the Bukkit standards. 2011-05-13 10:41:02 +02:00
Mike Primm daa2d0f186 Pull debug message 2011-05-13 10:31:50 +02:00
Mike Primm 17644a5778 Add tile data coloring (aka colored wool support), combine rendering
of default tiles and their zoomed counterparts (saves reloading the
default tile, and keeps the scale levels of the map consistent during
a fullrender and otherwise)
2011-05-13 10:31:38 +02:00
Mike Primm 0a8f2a182a Shift all imageIO and file I/O to async thread
Minus the version change in plugin.yml.
2011-05-13 10:29:38 +02:00
zeeZ 619485212d First iteration of weather icons 2011-05-10 12:51:52 +02:00
zeeZ 7f5d3ab23d Consistency to make Kilandor happy :-). 2011-05-10 12:51:52 +02:00
zeeZ bb45cc10cb Added weather to json world output (hasStorm and isThundering) 2011-05-10 12:51:52 +02:00
zeeZ c0479bff05 Fixed NPE if using regionless config. 2011-05-10 12:51:52 +02:00
zeeZ cf1d6c414d Organize imports 2011-05-10 12:51:52 +02:00
zeeZ 9eab216525 Use Bukkit's way to strip colors. 2011-05-10 12:51:52 +02:00
FrozenCow b8fe65bc99 Partly reverted previous change to get back to zeeZ' getDisplayName. 2011-05-10 12:51:52 +02:00
FrozenCow 1a5ddeeda5 Removed generation of .tar.bz2. 2011-05-10 12:26:26 +02:00
Mike Primm 5f23afe608 Don't need additional delay - using AsycnQueue for that 2011-05-10 12:26:18 +02:00
Mike Primm 0a1de1b18e Add option to run incremental renders on sync thread, using same chunk
logic as timesliced full render, in order to handle cases where
assumption that all chunks needed for incremental render are already
resident (which can be false if player telepots, move quickly,
multiple players are active, etc).
2011-05-10 12:26:11 +02:00
Mike Primm 88db6445f9 Added timeslicing to configuration 2011-05-10 12:26:02 +02:00
Mike Primm 6c708d1b3a Add version log message - keep track builds easier 2011-05-10 12:25:56 +02:00
Mike Primm dcdfb3da5d Trap on bogus world names or player with bad current location 2011-05-10 12:25:48 +02:00
Mike Primm 95cc3ae869 Add "time-sliced" implementation of fullrender, which does one tile at
a time using the Bukkit scheduler while using a tunable interval
between tiles (0.5 second default), and avoids player timeouts and
blooming the chunk and entity population.
2011-05-10 12:25:34 +02:00
FrozenCow 106f95d8b6 Removed a println. 2011-05-08 21:15:44 +02:00
FrozenCow be60623719 Fixed tabs. 2011-05-07 22:11:41 +02:00
FrozenCow ff026e91b6 Disabled regions component by default. 2011-05-07 00:20:34 +02:00
FrozenCow b66be7a47c Merge remote-tracking branch 'kilandor/master' 2011-05-07 00:04:05 +02:00
FrozenCow 92e3ec5f08 Merge remote-tracking branch 'zeez/master' 2011-05-06 23:19:37 +02:00
FrozenCow c4e1362274 Added another way to specify configuration file. 2011-05-06 23:18:46 +02:00
zeeZ 63b9579fa5 Strip colors off chat, use getDisplayName instead of getName 2011-05-01 23:11:29 +02:00
zeeZ 5f32f8fb99 Added Google Maps API version selection to fix map changes 2011-04-28 16:58:30 +02:00
zeeZ ca9aa0727f Fix for worlds with weird names and URLDecode mumbo-jumbo 2011-04-28 16:34:50 +02:00
Jason Booth b3ccd203c8 Added some info
Fix for spam warning for php(Thanks for bug report flames)
2011-04-13 20:23:24 -05:00
Jason Booth 8e59f37995 Initial Support for Regions system on dynmap
Included Worldguard support(default)
Also residence support(incomplete)
2011-04-13 19:58:25 -05:00
zeeZ 91b60be572 Less config checks in loop, added newline at EOF 2011-04-11 23:57:10 +02:00
zeeZ 69fcc1706e Option to treat hiddenplayers.txt as a whitelist. 2011-04-11 04:10:47 +02:00
zeeZ ab6352a17d Hidden players stored in lowercase. 2011-04-11 02:40:03 +02:00
zeeZ 631f06d091 More detailed permissions 2011-04-11 02:27:56 +02:00
zeeZ 8d5f081cdf Compass style based on map type. Hacky because widgets have classes, not IDs 2011-04-09 08:24:52 +02:00
zeeZ 553a956949 Flipped flat map so North is up 2011-04-08 21:40:16 +02:00
FrozenCow d53b3bc340 Added HighlightTileRenderer (thanks in part to rockNme2349) 2011-04-07 15:46:50 +02:00
FrozenCow eb276dd59d Another attempt to make server conform http. 2011-04-06 00:54:48 +02:00
FrozenCow ad33ef79d9 Fixed up.php. 2011-04-05 23:25:11 +02:00
FrozenCow b47bbee4e8 Cleaned up join/quit messages (not being send as chat messages) 2011-04-05 22:58:46 +02:00
FrozenCow e1e13df4b2 Removed redundant configuration values and made use of customizable join/quit messages. 2011-04-05 22:30:43 +02:00
FrozenCow d4a2d2d32f Changed version to 0.16. 2011-04-05 01:05:51 +02:00
43 changed files with 1543 additions and 232 deletions
+16
View File
@@ -68,6 +68,22 @@ Black Cloth
34 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255
Wool
35 222 222 222 255 177 177 177 255 111 111 111 255 88 88 88 255
35:0 222 222 222 255 177 177 177 255 111 111 111 255 88 88 88 255
35:1 204 111 48 255 162 89 38 255 102 56 24 255 81 44 19 255
35:2 166 66 175 255 133 53 140 255 83 33 87 255 66 26 69 255
35:3 91 121 185 255 73 96 147 255 46 61 92 255 36 48 73 255
35:4 170 158 24 255 135 126 19 255 85 79 12 255 67 62 10 255
35:5 51 165 42 255 41 131 33 255 26 82 21 255 20 65 17 255
35:6 190 115 135 255 151 92 108 255 95 57 67 255 75 46 53 255
35:7 58 58 58 255 47 47 47 255 29 29 29 255 23 23 23 255
35:8 138 145 145 255 110 115 115 255 69 72 72 255 55 57 57 255
35:9 34 102 131 255 27 81 104 255 17 51 65 255 13 40 52 255
35:10 113 47 171 255 90 37 136 255 57 24 85 255 45 19 68 255
35:11 34 44 134 255 27 35 107 255 17 22 67 255 13 18 53 255
35:12 75 44 24 255 60 35 19 255 37 22 12 255 30 18 10 255
35:13 49 67 21 255 39 53 17 255 24 34 10 255 19 27 8 255
35:14 143 39 36 255 114 31 28 255 71 20 18 255 57 16 14 255
35:15 24 20 20 255 19 16 16 255 12 10 10 255 9 8 8 255
Gray Cloth
36 125 125 125 255 114 114 114 255 104 104 104 255 86 86 86 255
Yellow Flower
+16
View File
@@ -68,6 +68,22 @@ Black Cloth
34 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255
Wool
35 247 255 239 255 244 251 236 255 204 210 197 255 244 251 236 255
35:0 247 255 239 255 244 251 236 255 204 210 197 255 244 251 236 255
35:1 227 128 52 255 224 126 51 255 187 105 42 255 224 126 51 255
35:2 185 76 188 255 183 75 186 255 153 63 155 255 183 75 186 255
35:3 102 139 199 255 100 137 196 255 84 114 164 255 100 137 196 255
35:4 189 181 26 255 187 178 26 255 156 149 22 255 187 178 26 255
35:5 57 189 45 255 56 186 44 255 47 156 37 255 56 186 44 255
35:6 211 132 145 255 209 130 143 255 174 109 120 255 209 130 143 255
35:7 65 67 63 255 64 66 62 255 54 55 52 255 64 66 62 255
35:8 154 166 156 255 152 163 154 255 127 137 128 255 152 163 154 255
35:9 38 117 141 255 37 115 139 255 31 96 116 255 37 115 139 255
35:10 126 54 184 255 124 53 181 255 104 44 151 255 124 53 181 255
35:11 38 51 144 255 37 50 143 255 31 42 119 255 37 50 143 255
35:12 83 51 26 255 82 50 26 255 69 42 22 255 82 50 26 255
35:13 54 77 22 255 54 76 22 255 45 63 19 255 54 76 22 255
35:14 159 45 38 255 157 44 38 255 131 37 32 255 157 44 38 255
35:15 26 23 22 255 26 23 21 255 22 19 18 255 26 23 21 255
Gray Cloth
36 125 125 125 255 114 114 114 255 104 104 104 255 86 86 86 255
Yellow Flower
+16
View File
@@ -68,6 +68,22 @@ Black Cloth
34 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255
Wool
35 222 222 222 255 177 177 177 255 111 111 111 255 88 88 88 255
35:0 222 222 222 255 177 177 177 255 111 111 111 255 88 88 88 255
35:1 204 111 48 255 162 89 38 255 102 56 24 255 81 44 19 255
35:2 166 66 175 255 133 53 140 255 83 33 87 255 66 26 69 255
35:3 91 121 185 255 73 96 147 255 46 61 92 255 36 48 73 255
35:4 170 158 24 255 135 126 19 255 85 79 12 255 67 62 10 255
35:5 51 165 42 255 41 131 33 255 26 82 21 255 20 65 17 255
35:6 190 115 135 255 151 92 108 255 95 57 67 255 75 46 53 255
35:7 58 58 58 255 47 47 47 255 29 29 29 255 23 23 23 255
35:8 138 145 145 255 110 115 115 255 69 72 72 255 55 57 57 255
35:9 34 102 131 255 27 81 104 255 17 51 65 255 13 40 52 255
35:10 113 47 171 255 90 37 136 255 57 24 85 255 45 19 68 255
35:11 34 44 134 255 27 35 107 255 17 22 67 255 13 18 53 255
35:12 75 44 24 255 60 35 19 255 37 22 12 255 30 18 10 255
35:13 49 67 21 255 39 53 17 255 24 34 10 255 19 27 8 255
35:14 143 39 36 255 114 31 28 255 71 20 18 255 57 16 14 255
35:15 24 20 20 255 19 16 16 255 12 10 10 255 9 8 8 255
Gray Cloth
36 125 125 125 255 114 114 114 255 104 104 104 255 86 86 86 255
Yellow Flower
+16
View File
@@ -17,6 +17,22 @@
18 27 69 37 180 22 57 31 180 19 48 25 180 22 57 31 180
20 178 217 223 90 148 181 186 90 124 151 155 90 148 181 186 90
35 247 255 239 255 244 251 236 255 204 210 197 255 244 251 236 255
35:0 247 255 239 255 244 251 236 255 204 210 197 255 244 251 236 255
35:1 227 128 52 255 224 126 51 255 187 105 42 255 224 126 51 255
35:2 185 76 188 255 183 75 186 255 153 63 155 255 183 75 186 255
35:3 102 139 199 255 100 137 196 255 84 114 164 255 100 137 196 255
35:4 189 181 26 255 187 178 26 255 156 149 22 255 187 178 26 255
35:5 57 189 45 255 56 186 44 255 47 156 37 255 56 186 44 255
35:6 211 132 145 255 209 130 143 255 174 109 120 255 209 130 143 255
35:7 65 67 63 255 64 66 62 255 54 55 52 255 64 66 62 255
35:8 154 166 156 255 152 163 154 255 127 137 128 255 152 163 154 255
35:9 38 117 141 255 37 115 139 255 31 96 116 255 37 115 139 255
35:10 126 54 184 255 124 53 181 255 104 44 151 255 124 53 181 255
35:11 38 51 144 255 37 50 143 255 31 42 119 255 37 50 143 255
35:12 83 51 26 255 82 50 26 255 69 42 22 255 82 50 26 255
35:13 54 77 22 255 54 76 22 255 45 63 19 255 54 76 22 255
35:14 159 45 38 255 157 44 38 255 131 37 32 255 157 44 38 255
35:15 26 23 22 255 26 23 21 255 22 19 18 255 26 23 21 255
36 0 0 0 254 0 0 0 254 0 0 0 254 0 0 0 254
37 73 108 60 254 61 90 50 254 51 75 42 254 61 90 50 254
38 84 139 187 254 70 116 155 254 59 97 130 254 70 116 155 254
+41 -8
View File
@@ -1,8 +1,14 @@
# All paths in this configuration file are relative to Dynmap's data-folder: minecraft_server/plugins/dynmap/
# Treat hiddenplayers.txt as a whitelist for players to be shown on the map? (Default false)
display-whitelist: false
# How often a tile gets rendered (in seconds).
renderinterval: 1
# Do render on main thread - may generate more server load, but safer and fixes broken tiles
renderonsync: true
render-triggers:
# - playermove
# - playerjoin
@@ -30,6 +36,12 @@ jsonfile: false
# How often the json file gets written to(in seconds)
jsonfile-interval: 1
# Use timesliced fullrender - takes a bit longer, but much more polite for server
timeslicerender: true
# Period between tile renders for timesliced fullrender, in seconds
timesliceinterval: 0.5
# The maptypes Dynmap will use to render.
worlds:
- name: world
@@ -43,6 +55,14 @@ worlds:
prefix: t
maximumheight: 127
colorscheme: default
#- class: org.dynmap.kzedmap.HighlightTileRenderer
# prefix: ht
# maximumheight: 127
# colorscheme: default
# highlight: # For highlighting multiple block-types.
# - 56 # Highlight diamond-ore
# - 66 # Highlight minecart track
# highlight: 56 # For highlighting a single block-type.
- class: org.dynmap.kzedmap.CaveTileRenderer
prefix: ct
maximumheight: 127
@@ -61,19 +81,14 @@ worlds:
web:
# Handles the clientside updates differently only enable if using jsonfile
jsonfile: false
# Interval the browser should poll for updates.
updaterate: 2000
showchatballoons: false
focuschatballoons: false
showchatwindow: true
allowchat: true
allowwebchat: true
webchat-interval: 5
messagettl: 15
showplayerfacesonmap: true
showplayerfacesinmenu: true
joinmessage: "%playername% joined"
@@ -92,6 +107,20 @@ web:
#- type: digitalclock
- type: timeofdayclock
showdigitalclock: true
#showweather: true
#- type: regions
# name: WorldGuard
# useworldpath: true
# filename: regions.yml
# basenode: regions
# use3dregions: true
# infowindow: '<div class="infowindow"><span style="font-size:120%;">%regionname% - %priority% (%parent%)</span><br /> Owners <span style="font-weight:bold;">%playerowners% %groupowners%</span><br />Members <span style="font-weight:bold;">%playermembers% %groupmembers%</span><br />Flags<br /><span style="font-weight:bold;">%flags%</span></div>'
# regionstyle:
# strokeColor: "#FF0000"
# strokeOpacity: 0.8
# strokeWeight: 3
# fillColor: "#FF0000"
# fillOpacity: 0.35
defaultworld: world
worlds:
@@ -106,6 +135,10 @@ web:
title: Surface
name: surface
prefix: t
#- type: KzedMapType
# title: Highlighted Map
# name: highlight
# prefix: ht
- type: KzedMapType
title: Cave
name: cave
+6
View File
@@ -0,0 +1,6 @@
dynmap.render # Render current chunk
dynmap.fullrender # Issue a full render
dynmap.hide.self # Hide self from map
dynmap.hide.others # Hide others from map
dynmap.show.self # Reveal self on map
dynmap.show.others # Reveal others on map
+1 -1
View File
@@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.dynmap</groupId>
<artifactId>dynmap</artifactId>
<version>0.15</version>
<version>0.16.1</version>
<name>dynmap</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-1
View File
@@ -2,7 +2,6 @@
<id>bin</id>
<includeBaseDirectory>false</includeBaseDirectory>
<formats>
<format>tar.bz2</format>
<format>zip</format>
</formats>
<fileSets>
+22 -11
View File
@@ -1,9 +1,13 @@
package org.dynmap;
import org.bukkit.ChatColor;
public class Client {
public static class Update {
public long timestamp;
public long servertime;
public boolean hasStorm;
public boolean isThundering;
public Player[] players;
public Object[] updates;
}
@@ -15,7 +19,7 @@ public class Client {
public double x, y, z;
public Player(String name, String world, double x, double y, double z) {
this.name = name;
this.name = ChatColor.stripColor(name);
this.world = world;
this.x = x;
this.y = y;
@@ -29,23 +33,30 @@ public class Client {
public static class ChatMessage extends Stamped {
public String type = "chat";
public String source;
public String playerName;
public String message;
public ChatMessage(String playerName, String message) {
this.playerName = playerName;
this.message = message;
public ChatMessage(String source, String playerName, String message) {
this.source = source;
this.playerName = ChatColor.stripColor(playerName);
this.message = ChatColor.stripColor(message);
}
}
public static class WebChatMessage extends Stamped {
public String type = "webchat";
public static class PlayerJoinMessage extends Stamped {
public String type = "playerjoin";
public String playerName;
public String message;
public WebChatMessage(String playerName, String message) {
this.playerName = playerName;
this.message = message;
public PlayerJoinMessage(String playerName) {
this.playerName = ChatColor.stripColor(playerName);
}
}
public static class PlayerQuitMessage extends Stamped {
public String type = "playerquit";
public String playerName;
public PlayerQuitMessage(String playerName) {
this.playerName = ChatColor.stripColor(playerName);
}
}
+48 -8
View File
@@ -17,11 +17,14 @@ public class ColorScheme {
private static final HashMap<String, ColorScheme> cache = new HashMap<String, ColorScheme>();
public String name;
public java.util.Map<Integer, Color[]> colors;
/* Switch to arrays - faster than map */
public Color[][] colors; /* [blk-type][step] */
public Color[][][] datacolors; /* [bkt-type][blk-dat][step] */
public ColorScheme(String name, java.util.Map<Integer, Color[]> colors) {
public ColorScheme(String name, Color[][] colors, Color[][][] datacolors) {
this.name = name;
this.colors = colors;
this.datacolors = datacolors;
}
private static File getColorSchemeDirectory() {
@@ -41,8 +44,10 @@ public class ColorScheme {
public static ColorScheme loadScheme(String name) {
File colorSchemeFile = new File(getColorSchemeDirectory(), name + ".txt");
java.util.Map<Integer, Color[]> colors = new HashMap<Integer, Color[]>();
Color[][] colors = new Color[256][];
Color[][][] datacolors = new Color[256][][];
InputStream stream;
boolean enab_datacolor = MapManager.mapman.doSyncRender();
try {
Debug.debug("Loading colors from '" + colorSchemeFile + "'...");
stream = new FileInputStream(colorSchemeFile);
@@ -59,9 +64,16 @@ public class ColorScheme {
if (split.length < 17) {
continue;
}
Integer id = new Integer(split[0]);
Integer id;
Integer dat = null;
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 {
id = new Integer(split[0]);
}
Color[] c = new Color[4];
/* store colors by raycast sequence number */
@@ -70,16 +82,44 @@ public class ColorScheme {
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]));
colors.put(id, c);
if(dat != null) {
if(enab_datacolor) {
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;
}
}
}
} catch (RuntimeException e) {
log.log(Level.SEVERE, "Could not load colors '" + name + "' ('" + colorSchemeFile + "').", e);
return null;
} catch (FileNotFoundException e) {
log.log(Level.SEVERE, "Could not load colors '" + name + "' ('" + colorSchemeFile + "'): File not found.", e);
}
return new ColorScheme(name, colors);
return new ColorScheme(name, colors, datacolors);
}
}
@@ -15,21 +15,17 @@ public class DynmapPlayerChatListener extends PlayerListener {
@Override
public void onPlayerChat(PlayerChatEvent event) {
if(event.isCancelled()) return;
plugin.mapManager.pushUpdate(new Client.ChatMessage(event.getPlayer().getName(), event.getMessage()));
plugin.mapManager.pushUpdate(new Client.ChatMessage("player", event.getPlayer().getDisplayName(), event.getMessage()));
}
@Override
public void onPlayerJoin(PlayerJoinEvent event) {
String joinMessage = plugin.configuration.getString("joinmessage", "%playername% joined");
joinMessage = joinMessage.replaceAll("%playername%", event.getPlayer().getName());
plugin.mapManager.pushUpdate(new Client.ChatMessage("Server", joinMessage));
plugin.mapManager.pushUpdate(new Client.PlayerJoinMessage(event.getPlayer().getDisplayName()));
}
@Override
public void onPlayerQuit(PlayerQuitEvent event) {
String quitMessage = plugin.configuration.getString("quitmessage", "%playername% quit");
quitMessage = quitMessage.replaceAll("%playername%", event.getPlayer().getName());
plugin.mapManager.pushUpdate(new Client.ChatMessage("Server", quitMessage));
plugin.mapManager.pushUpdate(new Client.PlayerQuitMessage(event.getPlayer().getDisplayName()));
}
}
+42 -24
View File
@@ -32,6 +32,7 @@ import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.world.ChunkLoadEvent;
import org.bukkit.event.world.WorldListener;
import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.util.config.Configuration;
@@ -88,7 +89,7 @@ public class DynmapPlugin extends JavaPlugin {
log.warning("Could not create directory for tiles ('" + tilesDirectory + "').");
}
playerList = new PlayerList(getServer(), getFile("hiddenplayers.txt"));
playerList = new PlayerList(getServer(), getFile("hiddenplayers.txt"), configuration);
playerList.load();
mapManager = new MapManager(this, configuration);
@@ -136,7 +137,7 @@ public class DynmapPlugin extends JavaPlugin {
if (configuration.getNode("web").getBoolean("allowwebchat", false)) {
SendMessageHandler messageHandler = new SendMessageHandler() {{
maximumMessageInterval = (configuration.getNode("web").getInt("webchat-interval", 1) * 1000);
spamMessage = "\""+configuration.getNode("web").getString("spammessage", "You may only chat once every %interval% seconds.")+"\"";
spamMessage = "\""+configuration.getNode("web").getString("spammessage", "You may only chat once every %interval% seconds.")+"\"";
onMessageReceived.addListener(new Listener<SendMessageHandler.Message>() {
@Override
public void triggered(Message t) {
@@ -153,6 +154,9 @@ public class DynmapPlugin extends JavaPlugin {
} catch (IOException e) {
log.severe("Failed to start WebServer on " + bindAddress + ":" + port + "!");
}
/* Print version info */
PluginDescriptionFile pdfFile = this.getDescription();
log.info("[dynmap] version " + pdfFile.getVersion() + " is enabled" );
}
public void onDisable() {
@@ -235,7 +239,7 @@ public class DynmapPlugin extends JavaPlugin {
}
// To announce when players have joined/quit/chatted.
if (configuration.getNode("web").getBoolean("showchatballoons", false) || configuration.getNode("web").getBoolean("showchatwindow", false)) {
if (configuration.getNode("web").getBoolean("allowchat", false)) {
// To handle webchat.
PlayerListener playerListener = new DynmapPlayerChatListener(this);
//getServer().getPluginManager().registerEvent(Event.Type.PLAYER_COMMAND, playerListener, Priority.Normal, this);
@@ -308,12 +312,8 @@ public class DynmapPlugin extends JavaPlugin {
if (!commands.contains(c)) {
return false;
}
if (!permissions.has(sender, c.toLowerCase())) {
sender.sendMessage("You don't have permission to use this command!");
return true;
}
if (c.equals("render")) {
if (c.equals("render") && checkPlayerPermission(sender,"render")) {
if (player != null) {
int invalidates = mapManager.touch(player.getLocation());
sender.sendMessage("Queued " + invalidates + " tiles" + (invalidates == 0
@@ -322,45 +322,63 @@ public class DynmapPlugin extends JavaPlugin {
return true;
}
} else if (c.equals("hide")) {
if (args.length == 1 && player != null) {
playerList.hide(player.getName());
sender.sendMessage("You are now hidden on Dynmap.");
return true;
} else {
if (args.length == 1) {
if(player != null && checkPlayerPermission(sender,"hide.self")) {
playerList.setVisible(player.getName(),false);
sender.sendMessage("You are now hidden on Dynmap.");
return true;
}
} else if (checkPlayerPermission(sender,"hide.others")) {
for (int i = 1; i < args.length; i++) {
playerList.hide(args[i]);
playerList.setVisible(args[i],false);
sender.sendMessage(args[i] + " is now hidden on Dynmap.");
}
return true;
}
} else if (c.equals("show")) {
if (args.length == 1 && player != null) {
playerList.show(player.getName());
sender.sendMessage("You are now visible on Dynmap.");
return true;
} else {
if (args.length == 1) {
if(player != null && checkPlayerPermission(sender,"show.self")) {
playerList.setVisible(player.getName(),true);
sender.sendMessage("You are now visible on Dynmap.");
return true;
}
} else if (checkPlayerPermission(sender,"show.others")) {
for (int i = 1; i < args.length; i++) {
playerList.show(args[i]);
playerList.setVisible(args[i],true);
sender.sendMessage(args[i] + " is now visible on Dynmap.");
}
return true;
}
} else if (c.equals("fullrender")) {
} else if (c.equals("fullrender") && checkPlayerPermission(sender,"fullrender")) {
if (args.length > 1) {
for (int i = 1; i < args.length; i++) {
World w = getServer().getWorld(args[i]);
mapManager.renderFullWorld(new Location(w, 0, 0, 0));
if(w != null)
mapManager.renderFullWorld(new Location(w, 0, 0, 0));
}
return true;
} else if (player != null) {
mapManager.renderFullWorld(player.getLocation());
Location loc = player.getLocation();
if(loc != null)
mapManager.renderFullWorld(loc);
return true;
}
}
return true;
}
return false;
}
private boolean checkPlayerPermission(CommandSender sender, String permission) {
if (!(sender instanceof Player)) {
return true;
} else if (!permissions.has(sender, permission.toLowerCase())) {
sender.sendMessage("You don't have permission to use this command!");
return false;
}
return true;
}
private void jsonConfig() {
File outputFile;
Map<?, ?> clientConfig = (Map<?, ?>) configuration.getProperty("web");
@@ -382,7 +400,7 @@ public class DynmapPlugin extends JavaPlugin {
}
public void webChat(String name, String message) {
mapManager.pushUpdate(new Client.WebChatMessage(name, message));
mapManager.pushUpdate(new Client.ChatMessage("web", name, message));
log.info("[WEB]" + name + ": " + message);
getServer().broadcastMessage("[WEB]" + name + ": " + message);
}
+60 -1
View File
@@ -6,6 +6,7 @@ import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -15,6 +16,7 @@ import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.util.config.Configuration;
import org.bukkit.util.config.ConfigurationNode;
import org.dynmap.web.Json;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
@@ -28,6 +30,7 @@ class JsonTimerTask extends TimerTask {
private Server server;
private MapManager mapManager;
private Configuration configuration;
private ConfigurationNode regions;
private static final JSONParser parser = new JSONParser();
private long lastTimestamp = 0;
@@ -36,6 +39,11 @@ class JsonTimerTask extends TimerTask {
this.server = this.plugin.getServer();
this.mapManager = this.plugin.getMapManager();
this.configuration = config;
for(ConfigurationNode type : configuration.getNodeList("web.components", null))
if(type.getString("type").equalsIgnoreCase("regions")) {
this.regions = type;
break;
}
}
public void run() {
@@ -77,19 +85,26 @@ class JsonTimerTask extends TimerTask {
//Handles Updates
for (World world : this.server.getWorlds()) {
//Parse region file for multi world style
if (regions != null)
if (regions.getBoolean("useworldpath", false))
parseRegionFile(world.getName() + "/" + regions.getString("filename", "regions.yml"), regions.getString("filename", "regions.yml").replace(".", "_" + world.getName() + ".yml"));
current = System.currentTimeMillis();
Client.Update update = new Client.Update();
update.timestamp = current;
update.servertime = world.getTime() % 24000;
update.hasStorm = world.hasStorm();
update.isThundering = world.isThundering();
Player[] players = plugin.playerList.getVisiblePlayers();
update.players = new Client.Player[players.length];
for (int i = 0; i < players.length; i++) {
Player p = players[i];
Location pl = p.getLocation();
update.players[i] = new Client.Player(p.getName(), pl.getWorld().getName(), pl.getX(), pl.getY(), pl.getZ());
update.players[i] = new Client.Player(p.getDisplayName(), pl.getWorld().getName(), pl.getX(), pl.getY(), pl.getZ());
}
update.updates = mapManager.getWorldUpdates(world.getName(), current - (jsonInterval + 10000));
@@ -111,5 +126,49 @@ class JsonTimerTask extends TimerTask {
}
}
lastTimestamp = System.currentTimeMillis();
//Parse regions file for non worlds style
if (regions != null)
if (!regions.getBoolean("useworldpath", false))
parseRegionFile(regions.getString("filename", "regions.yml"), regions.getString("filename", "regions.yml"));
}
//handles parsing and writing region json files
private void parseRegionFile(String regionFile, String outputFileName)
{
File outputFile;
Configuration regionConfig = null;
if(regions.getBoolean("useworldpath", false))
{
if(new File("plugins/"+regions.getString("name", "WorldGuard"), regionFile).exists())
regionConfig = new Configuration(new File("plugins/"+regions.getString("name", "WorldGuard"), regionFile));
else if(new File("plugins/"+regions.getString("name", "WorldGuard")+"/worlds", regionFile).exists())
regionConfig = new Configuration(new File("plugins/"+regions.getString("name", "WorldGuard")+"/worlds", regionFile));
}
else
regionConfig = new Configuration(new File("plugins/"+regions.getString("name", "WorldGuard"), regionFile));
//File didn't exist
if(regionConfig == null)
return;
regionConfig.load();
outputFileName = outputFileName.substring(0, outputFileName.lastIndexOf("."))+".json";
File webWorldPath = new File(this.configuration.getString("webpath", "web")+"/standalone/", outputFileName);
Map<?, ?> regionData = (Map<?, ?>) regionConfig.getProperty(regions.getString("basenode", "regions"));
if (webWorldPath.isAbsolute())
outputFile = webWorldPath;
else {
outputFile = new File(plugin.getDataFolder(), webWorldPath.toString());
}
try {
FileOutputStream fos = new FileOutputStream(outputFile);
fos.write(Json.stringifyJson(regionData).getBytes());
fos.close();
} catch (FileNotFoundException ex) {
log.log(Level.SEVERE, "Exception while writing JSON-file.", ex);
} catch (IOException ioe) {
log.log(Level.SEVERE, "Exception while writing JSON-file.", ioe);
}
}
}
+189 -5
View File
@@ -1,6 +1,8 @@
package org.dynmap;
import java.io.File;
import java.io.IOException;
import java.awt.image.BufferedImage;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.HashMap;
@@ -10,31 +12,179 @@ import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.HashMap;
import javax.imageio.ImageIO;
import org.dynmap.kzedmap.KzedMapTile;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.util.config.ConfigurationNode;
import org.dynmap.DynmapWorld;
import org.dynmap.MapTile;
import org.dynmap.debug.Debug;
import org.dynmap.kzedmap.KzedMap;
import org.dynmap.kzedmap.KzedZoomedMapTile;
import org.bukkit.Chunk;
public class MapManager {
protected static final Logger log = Logger.getLogger("Minecraft");
public AsynchronousQueue<MapTile> tileQueue;
public AsynchronousQueue<ImageWriter> writeQueue;
public Map<String, DynmapWorld> worlds = new HashMap<String, DynmapWorld>();
public Map<String, DynmapWorld> inactiveworlds = new HashMap<String, DynmapWorld>();
private BukkitScheduler scheduler;
private DynmapPlugin plug_in;
private boolean do_timesliced_render = false;
private double timeslice_interval = 0.0;
private boolean do_sync_render = false; /* Do incremental renders on sync thread too */
/* Which timesliced renders are active */
private HashMap<String, FullWorldRenderState> active_renders = new HashMap<String, FullWorldRenderState>();
/* lock for our data structures */
public static final Object lock = new Object();
public static MapManager mapman; /* Our singleton */
private static class ImageWriter {
Runnable run;
}
private class FullWorldRenderState implements Runnable {
DynmapWorld world; /* Which world are we rendering */
Location loc; /* Start location */
int map_index = -1; /* Which map are we on */
MapType map;
HashSet<MapTile> found = null;
HashSet<MapTile> rendered = null;
LinkedList<MapTile> renderQueue = null;
MapTile tile0 = null;
/* Full world, all maps render */
FullWorldRenderState(DynmapWorld dworld, Location l) {
world = dworld;
loc = l;
found = new HashSet<MapTile>();
rendered = new HashSet<MapTile>();
renderQueue = new LinkedList<MapTile>();
}
/* Single tile render - used for incremental renders */
FullWorldRenderState(MapTile t) {
world = worlds.get(t.getWorld().getName());
tile0 = t;
}
public void run() {
MapTile tile;
if(tile0 == null) { /* Not single tile render */
/* If render queue is empty, start next map */
if(renderQueue.isEmpty()) {
found.clear();
rendered.clear();
map_index++; /* Next map */
if(map_index >= world.maps.size()) { /* Last one done? */
log.info("Full render finished.");
active_renders.remove(world.world.getName());
return;
}
map = world.maps.get(map_index);
/* Now, prime the render queue */
for (MapTile mt : map.getTiles(loc)) {
if (!found.contains(mt)) {
found.add(mt);
renderQueue.add(mt);
}
}
}
tile = renderQueue.pollFirst();
}
else { /* Else, single tile render */
tile = tile0;
}
DynmapChunk[] requiredChunks = tile.getMap().getRequiredChunks(tile);
LinkedList<DynmapChunk> loadedChunks = new LinkedList<DynmapChunk>();
World w = world.world;
// Load the required chunks.
for (DynmapChunk chunk : requiredChunks) {
boolean wasLoaded = w.isChunkLoaded(chunk.x, chunk.z);
boolean didload = w.loadChunk(chunk.x, chunk.z, false);
if ((!wasLoaded) && didload)
loadedChunks.add(chunk);
}
if(tile0 != null) { /* Single tile? */
render(tile); /* Just render */
}
else {
if (render(tile)) {
found.remove(tile);
rendered.add(tile);
for (MapTile adjTile : map.getAdjecentTiles(tile)) {
if (!found.contains(adjTile) && !rendered.contains(adjTile)) {
found.add(adjTile);
renderQueue.add(adjTile);
}
}
}
found.remove(tile);
}
/* And unload what we loaded */
while (!loadedChunks.isEmpty()) {
DynmapChunk c = loadedChunks.pollFirst();
/* It looks like bukkit "leaks" entities - they don't get removed from the world-level table
* when chunks are unloaded but not saved - removing them seems to do the trick */
Chunk cc = w.getChunkAt(c.x, c.z);
if(cc != null) {
for(Entity e: cc.getEntities())
e.remove();
}
/* Since we only remember ones we loaded, and we're synchronous, no player has
* moved, so it must be safe (also prevent chunk leak, which appears to happen
* because isChunkInUse defined "in use" as being within 256 blocks of a player,
* while the actual in-use chunk area for a player where the chunks are managed
* by the MC base server is 21x21 (or about a 160 block radius) */
w.unloadChunk(c.x, c.z, false, false);
}
if(tile0 == null) { /* fullrender */
/* Schedule the next tile to be worked */
scheduler.scheduleSyncDelayedTask(plug_in, this, (int)(timeslice_interval*20));
}
}
}
public MapManager(DynmapPlugin plugin, ConfigurationNode configuration) {
mapman = this;
this.tileQueue = new AsynchronousQueue<MapTile>(new Handler<MapTile>() {
@Override
public void handle(MapTile t) {
render(t);
if(do_sync_render)
scheduler.scheduleSyncDelayedTask(plug_in,
new FullWorldRenderState(t), 1);
else
render(t);
}
}, (int) (configuration.getDouble("renderinterval", 0.5) * 1000));
this.writeQueue = new AsynchronousQueue<ImageWriter>(
new Handler<ImageWriter>() {
@Override
public void handle(ImageWriter w) {
w.run.run();
}
}, 10);
do_timesliced_render = configuration.getBoolean("timeslicerender", true);
timeslice_interval = configuration.getDouble("timesliceinterval", 0.5);
do_sync_render = configuration.getBoolean("renderonsync", true);
for(Object worldConfigurationObj : (List<?>)configuration.getProperty("worlds")) {
Map<?, ?> worldConfiguration = (Map<?, ?>)worldConfigurationObj;
String worldName = (String)worldConfiguration.get("name");
@@ -51,16 +201,38 @@ public class MapManager {
activateWorld(bukkitWorld);
}
scheduler = plugin.getServer().getScheduler();
plug_in = plugin;
tileQueue.start();
writeQueue.start();
}
void renderFullWorld(Location l) {
DynmapWorld world = worlds.get(l.getWorld().getName());
if (world == null) {
log.severe("Could not render: world '" + l.getWorld().getName() + "' not defined in configuration.");
return;
}
if(do_timesliced_render) {
String wname = l.getWorld().getName();
FullWorldRenderState rndr = active_renders.get(wname);
if(rndr != null) {
log.info("Full world render of world '" + wname + "' already active.");
return;
}
rndr = new FullWorldRenderState(world,l); /* Make new activation record */
active_renders.put(wname, rndr); /* Add to active table */
/* Schedule first tile to be worked */
scheduler.scheduleSyncDelayedTask(plug_in, rndr, (int)(timeslice_interval*20));
log.info("Full render starting on world '" + wname + "' (timesliced)...");
return;
}
World w = world.world;
log.info("Full render starting on world '" + w.getName() + "'...");
for (MapType map : world.maps) {
int requiredChunkCount = 200;
@@ -183,21 +355,23 @@ public class MapManager {
public void startRendering() {
tileQueue.start();
writeQueue.start();
}
public void stopRendering() {
tileQueue.stop();
writeQueue.stop();
}
public boolean render(MapTile tile) {
boolean result = tile.getMap().render(tile, getTileFile(tile));
pushUpdate(tile.getWorld(), new Client.Tile(tile.getFilename()));
//Do update after async file write
return result;
}
}
private HashMap<World, File> worldTileDirectories = new HashMap<World, File>();
private File getTileFile(MapTile tile) {
public File getTileFile(MapTile tile) {
World world = tile.getWorld();
File worldTileDirectory = worldTileDirectories.get(world);
if (worldTileDirectory == null) {
@@ -231,4 +405,14 @@ public class MapManager {
return new Object[0];
return world.updates.getUpdatedObjects(since);
}
public void enqueueImageWrite(Runnable run) {
ImageWriter handler = new ImageWriter();
handler.run = run;
writeQueue.push(handler);
}
public boolean doSyncRender() {
return do_sync_render;
}
}
+11 -6
View File
@@ -12,15 +12,18 @@ import java.util.Scanner;
import org.bukkit.Server;
import org.bukkit.entity.Player;
import org.bukkit.util.config.Configuration;
public class PlayerList {
private Server server;
private HashSet<String> hiddenPlayerNames = new HashSet<String>();
private File hiddenPlayersFile;
private Configuration configuration;
public PlayerList(Server server, File hiddenPlayersFile) {
public PlayerList(Server server, File hiddenPlayersFile, Configuration configuration) {
this.server = server;
this.hiddenPlayersFile = hiddenPlayersFile;
this.configuration = configuration;
}
public void save() {
@@ -53,17 +56,17 @@ public class PlayerList {
}
public void hide(String playerName) {
hiddenPlayerNames.add(playerName);
hiddenPlayerNames.add(playerName.toLowerCase());
save();
}
public void show(String playerName) {
hiddenPlayerNames.remove(playerName);
hiddenPlayerNames.remove(playerName.toLowerCase());
save();
}
public void setVisible(String playerName, boolean visible) {
if (visible)
if (visible ^ configuration.getBoolean("display-whitelist", false))
show(playerName);
else
hide(playerName);
@@ -73,9 +76,10 @@ public class PlayerList {
public Player[] getVisiblePlayers(String worldName) {
ArrayList<Player> visiblePlayers = new ArrayList<Player>();
Player[] onlinePlayers = server.getOnlinePlayers();
boolean useWhitelist = configuration.getBoolean("display-whitelist", false);
for (int i = 0; i < onlinePlayers.length; i++) {
Player p = onlinePlayers[i];
if (p.getWorld().getName().equals(worldName) && !hiddenPlayerNames.contains(p.getName())) {
if (p.getWorld().getName().equals(worldName) && !(useWhitelist ^ hiddenPlayerNames.contains(p.getName().toLowerCase()))) {
visiblePlayers.add(p);
}
}
@@ -87,9 +91,10 @@ public class PlayerList {
public Player[] getVisiblePlayers() {
ArrayList<Player> visiblePlayers = new ArrayList<Player>();
Player[] onlinePlayers = server.getOnlinePlayers();
boolean useWhitelist = configuration.getBoolean("display-whitelist", false);
for (int i = 0; i < onlinePlayers.length; i++) {
Player p = onlinePlayers[i];
if (!hiddenPlayerNames.contains(p.getName())) {
if (!(useWhitelist ^ hiddenPlayerNames.contains(p.getName().toLowerCase()))) {
visiblePlayers.add(p);
}
}
@@ -1,6 +1,7 @@
package org.dynmap.debug;
import java.util.Map;
import org.bukkit.plugin.java.JavaPlugin;
public class NullDebugger implements Debugger {
+24 -11
View File
@@ -11,8 +11,10 @@ import javax.imageio.ImageIO;
import org.bukkit.Location;
import org.bukkit.World;
import org.dynmap.Client;
import org.dynmap.ColorScheme;
import org.dynmap.DynmapChunk;
import org.dynmap.MapManager;
import org.dynmap.MapTile;
import org.dynmap.MapType;
import org.dynmap.debug.Debug;
@@ -79,7 +81,7 @@ public class FlatMap extends MapType {
int mz = y + t.y * t.size;
int my = w.getHighestBlockYAt(mx, mz) - 1;
int blockType = w.getBlockTypeIdAt(mx, my, mz);
Color[] colors = colorScheme.colors.get(blockType);
Color[] colors = colorScheme.colors[blockType];
if (colors == null)
continue;
Color c = colors[0];
@@ -117,18 +119,29 @@ public class FlatMap extends MapType {
pixel[2] += (255-pixel[2]) * scale;
}
raster.setPixel(x, y, pixel);
raster.setPixel(t.size-y-1, x, pixel);
rendered = true;
}
/* Hand encoding and writing file off to MapManager */
final File fname = outputFile;
final MapTile mtile = tile;
final BufferedImage img = im;
MapManager.mapman.enqueueImageWrite(new Runnable() {
public void run() {
Debug.debug("saving image " + fname.getPath());
try {
ImageIO.write(img, "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);
}
img.flush();
MapManager.mapman.pushUpdate(mtile.getWorld(),
new Client.Tile(mtile.getFilename()));
}
});
try {
ImageIO.write(im, "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);
}
im.flush();
return rendered;
}
@@ -148,7 +161,7 @@ public class FlatMap extends MapType {
@Override
public String getFilename() {
return map.prefix + "_" + size + "_" + x + "_" + y + ".png";
return map.prefix + "_" + size + "_" + -(y+1) + "_" + x + ".png";
}
}
}
@@ -1,23 +1,51 @@
package org.dynmap.kzedmap;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Map;
import javax.imageio.ImageIO;
import org.bukkit.World;
import org.dynmap.Client;
import org.dynmap.ColorScheme;
import org.dynmap.MapManager;
import org.dynmap.MapTile;
import org.dynmap.debug.Debug;
public class DefaultTileRenderer implements MapTileRenderer {
protected static final Color translucent = new Color(0, 0, 0, 0);
private String name;
protected String name;
protected int maximumHeight = 127;
private ColorScheme colorScheme;
protected ColorScheme colorScheme;
protected HashSet<Integer> highlightBlocks = new HashSet<Integer>();
protected Color highlightColor = new Color(255, 0, 0);
private static final Color[] woolshades = {
Color.WHITE,
Color.ORANGE,
Color.MAGENTA,
new Color(51,204,255),
Color.YELLOW,
new Color(102,255,102),
Color.PINK,
Color.GRAY,
Color.LIGHT_GRAY,
Color.CYAN,
new Color(255,0,255),
Color.BLUE,
new Color(102,51,51),
Color.GREEN,
Color.RED,
Color.BLACK
};
@Override
public String getName() {
@@ -100,15 +128,94 @@ public class DefaultTileRenderer implements MapTileRenderer {
iz--;
}
/* save the generated tile */
saveImage(im, outputFile);
im.flush();
/* Hand encoding and writing file off to MapManager */
final File fname = outputFile;
final KzedMapTile mtile = tile;
final BufferedImage img = im;
final KzedZoomedMapTile zmtile = new KzedZoomedMapTile(mtile.getWorld(),
(KzedMap) mtile.getMap(), mtile);
final File zoomFile = MapManager.mapman.getTileFile(zmtile);
tile.file = outputFile;
((KzedMap) tile.getMap()).invalidateTile(new KzedZoomedMapTile(world, (KzedMap) tile.getMap(), tile));
MapManager.mapman.enqueueImageWrite(new Runnable() {
public void run() {
doFileWrites(fname, mtile, img, zmtile, zoomFile);
}
});
return !isempty;
}
private void doFileWrites(final File fname, final KzedMapTile mtile,
final BufferedImage img, final KzedZoomedMapTile zmtile, final File zoomFile) {
Debug.debug("saving image " + fname.getPath());
try {
ImageIO.write(img, "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);
}
mtile.file = fname;
// Since we've already got the new tile, and we're on an async thread, just
// make the zoomed tile here
int px = mtile.px;
int py = mtile.py;
int zpx = zmtile.getTileX();
int zpy = zmtile.getTileY();
/* scaled size */
int scw = KzedMap.tileWidth / 2;
int sch = KzedMap.tileHeight / 2;
/* origin in zoomed-out tile */
int ox = 0;
int oy = 0;
if (zpx != px)
ox = scw;
if (zpy != py)
oy = sch;
BufferedImage zIm = null;
try {
zIm = ImageIO.read(zoomFile);
} catch (IOException e) {
} catch (IndexOutOfBoundsException e) {
}
if (zIm == null) {
/* create new one */
zIm = new BufferedImage(KzedMap.tileWidth, KzedMap.tileHeight, BufferedImage.TYPE_INT_RGB);
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 */
Graphics2D g2 = zIm.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(img, ox, oy, scw, sch, null);
img.flush();
/* save zoom-out tile */
try {
ImageIO.write(zIm, "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);
}
zIm.flush();
/* Push updates for both files.*/
MapManager.mapman.pushUpdate(mtile.getWorld(),
new Client.Tile(mtile.getFilename()));
MapManager.mapman.pushUpdate(zmtile.getWorld(),
new Client.Tile(zmtile.getFilename()));
}
protected Color scan(World world, int x, int y, int z, int seq) {
for (;;) {
@@ -116,7 +223,10 @@ public class DefaultTileRenderer implements MapTileRenderer {
return translucent;
int id = world.getBlockTypeIdAt(x, y, z);
byte data = 0;
if(colorScheme.datacolors[id] != null) { /* If data colored */
data = world.getBlockAt(x, y, z).getData();
}
switch (seq) {
case 0:
x--;
@@ -135,7 +245,14 @@ public class DefaultTileRenderer implements MapTileRenderer {
seq = (seq + 1) & 3;
if (id != 0) {
Color[] colors = colorScheme.colors.get(id);
if (highlightBlocks.contains(id)) {
return highlightColor;
}
Color[] colors;
if(data != 0)
colors = colorScheme.datacolors[id][data];
else
colors = colorScheme.colors[id];
if (colors != null) {
Color c = colors[seq];
if (c.getAlpha() > 0) {
@@ -163,17 +280,4 @@ public class DefaultTileRenderer implements MapTileRenderer {
}
}
}
/* save rendered tile, update zoom-out tile */
public void saveImage(BufferedImage im, File outputFile) {
Debug.debug("saving image " + outputFile.getPath());
/* save image */
try {
ImageIO.write(im, "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);
}
}
}
@@ -0,0 +1,101 @@
package org.dynmap.kzedmap;
import java.awt.Color;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import org.bukkit.World;
public class HighlightTileRenderer extends DefaultTileRenderer {
protected HashSet<Integer> highlightBlocks = new HashSet<Integer>();
public HighlightTileRenderer(Map<String, Object> configuration) {
super(configuration);
Object highlightObj = configuration.get("highlight");
if (highlightObj instanceof List<?>) {
for(Object o : (List<?>)highlightObj) {
highlightBlocks.add((Integer)o);
}
} else if (highlightObj instanceof Integer) {
highlightBlocks.add((Integer)highlightObj);
}
}
@Override
protected Color scan(World world, int x, int y, int z, int seq) {
Color result = translucent;
for (;;) {
if (y < 0) {
break;
}
int id = world.getBlockTypeIdAt(x, y, z);
byte data = 0;
if(colorScheme.datacolors[id] != null) { /* If data colored */
data = world.getBlockAt(x, y, z).getData();
}
switch (seq) {
case 0:
x--;
break;
case 1:
y--;
break;
case 2:
z++;
break;
case 3:
y--;
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)) {
return c;
}
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) {
Color bg = c;
c = result;
int cr = c.getRed();
int cg = c.getGreen();
int cb = c.getBlue();
int ca = c.getAlpha();
cr *= ca;
cg *= ca;
cb *= ca;
int na = 255 - ca;
result = new Color((bg.getRed() * na + cr) >> 8, (bg.getGreen() * na + cg) >> 8, (bg.getBlue() * na + cb) >> 8,
Math.min(255, bg.getAlpha()+c.getAlpha()) // Not really correct, but gets the job done without recursion while still looking ok.
);
}
}
}
}
}
return result;
}
}
@@ -1,6 +1,7 @@
package org.dynmap.kzedmap;
import java.io.File;
import org.bukkit.World;
import org.dynmap.MapTile;

Some files were not shown because too many files have changed in this diff Show More