mirror of
https://github.com/encounter/dynmap.git
synced 2026-03-30 11:08:39 -07:00
Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1e3ceed5d7 | |||
| 88ff70ac48 | |||
| 84d01c530a | |||
| daa2d0f186 | |||
| 17644a5778 | |||
| 0a8f2a182a | |||
| 619485212d | |||
| 7f5d3ab23d | |||
| bb45cc10cb | |||
| c0479bff05 | |||
| cf1d6c414d | |||
| 9eab216525 | |||
| b8fe65bc99 | |||
| 1a5ddeeda5 | |||
| 5f23afe608 | |||
| 0a1de1b18e | |||
| 88db6445f9 | |||
| 6c708d1b3a | |||
| dcdfb3da5d | |||
| 95cc3ae869 | |||
| 106f95d8b6 | |||
| be60623719 | |||
| ff026e91b6 | |||
| b66be7a47c | |||
| 92e3ec5f08 | |||
| c4e1362274 | |||
| 63b9579fa5 | |||
| 5f32f8fb99 | |||
| ca9aa0727f | |||
| b3ccd203c8 | |||
| 8e59f37995 | |||
| 91b60be572 | |||
| 69fcc1706e | |||
| ab6352a17d | |||
| 631f06d091 | |||
| 8d5f081cdf | |||
| 553a956949 | |||
| d53b3bc340 | |||
| eb276dd59d | |||
| ad33ef79d9 | |||
| b47bbee4e8 | |||
| e1e13df4b2 | |||
| d4a2d2d32f |
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -2,7 +2,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.dynmap</groupId>
|
||||
<artifactId>dynmap</artifactId>
|
||||
<version>0.15</version>
|
||||
<version>0.16</version>
|
||||
<name>dynmap</name>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
<id>bin</id>
|
||||
<includeBaseDirectory>false</includeBaseDirectory>
|
||||
<formats>
|
||||
<format>tar.bz2</format>
|
||||
<format>zip</format>
|
||||
</formats>
|
||||
<fileSets>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user