diff --git a/src/main/java/org/dynmap/ClientComponent.java b/src/main/java/org/dynmap/ClientComponent.java index 8d006976..7e4e1db8 100644 --- a/src/main/java/org/dynmap/ClientComponent.java +++ b/src/main/java/org/dynmap/ClientComponent.java @@ -9,17 +9,23 @@ import java.util.Map; import org.json.simple.JSONArray; import org.json.simple.JSONObject; public class ClientComponent extends Component { - + private boolean disabled; + public ClientComponent(final DynmapPlugin plugin, final ConfigurationNode configuration) { super(plugin, configuration); plugin.events.addListener("buildclientconfiguration", new Event.Listener() { @Override public void triggered(JSONObject root) { - buildClientConfiguration(root); + if(!disabled) + buildClientConfiguration(root); } }); } + protected void disableComponent() { + disabled = true; + } + protected void buildClientConfiguration(JSONObject root) { JSONObject o = createClientConfiguration(); a(root, "components", o); diff --git a/src/main/java/org/dynmap/ClientUpdateComponent.java b/src/main/java/org/dynmap/ClientUpdateComponent.java index b96d0e9c..6cb702f9 100644 --- a/src/main/java/org/dynmap/ClientUpdateComponent.java +++ b/src/main/java/org/dynmap/ClientUpdateComponent.java @@ -11,10 +11,13 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Player; +import org.dynmap.utils.BlockLightLevel; import org.json.simple.JSONArray; import org.json.simple.JSONObject; public class ClientUpdateComponent extends Component { + private BlockLightLevel bll = new BlockLightLevel(); + public ClientUpdateComponent(final DynmapPlugin plugin, ConfigurationNode configuration) { super(plugin, configuration); plugin.events.addListener("buildclientupdate", new Event.Listener() { @@ -53,9 +56,14 @@ public class ClientUpdateComponent extends Component { hide = true; } if(hideifunder < 15) { - /*TODO: when pull accepted for getSkyLightLevel(), switch to that */ - if(pl.getWorld().getHighestBlockYAt(pl) > pl.getBlockY()) - hide = true; + if(bll.isReady()) { /* If we can get real sky level */ + if(bll.getSkyLightLevel(pl.getBlock()) <= hideifunder) + hide = true; + } + else { + if(pl.getWorld().getHighestBlockYAt(pl) > pl.getBlockY()) + hide = true; + } } /* Don't leak player location for world not visible on maps, or if sendposition disbaled */ diff --git a/src/main/java/org/dynmap/DynmapPlugin.java b/src/main/java/org/dynmap/DynmapPlugin.java index 7d62ba77..52ffc5e5 100644 --- a/src/main/java/org/dynmap/DynmapPlugin.java +++ b/src/main/java/org/dynmap/DynmapPlugin.java @@ -222,6 +222,8 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI { permissions = new OpPermissions(new String[] { "fullrender", "cancelrender", "radiusrender", "resetstats", "reload", "purgequeue" }); dataDirectory = this.getDataFolder(); + if(dataDirectory.exists() == false) + dataDirectory.mkdirs(); /* Initialize confguration.txt if needed */ File f = new File(this.getDataFolder(), "configuration.txt"); @@ -432,7 +434,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI { Location loc = event.getBlock().getLocation(); mapManager.sscache.invalidateSnapshot(loc); if(onplace) { - mapManager.touch(loc); + mapManager.touch(loc, "blockplace"); } } @@ -443,7 +445,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI { Location loc = event.getBlock().getLocation(); mapManager.sscache.invalidateSnapshot(loc); if(onbreak) { - mapManager.touch(loc); + mapManager.touch(loc, "blockbreak"); } } @@ -454,7 +456,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI { Location loc = event.getBlock().getLocation(); mapManager.sscache.invalidateSnapshot(loc); if(onleaves) { - mapManager.touch(loc); + mapManager.touch(loc, "leavesdecay"); } } @@ -465,7 +467,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI { Location loc = event.getBlock().getLocation(); mapManager.sscache.invalidateSnapshot(loc); if(onburn) { - mapManager.touch(loc); + mapManager.touch(loc, "blockburn"); } } @@ -476,7 +478,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI { Location loc = event.getBlock().getLocation(); mapManager.sscache.invalidateSnapshot(loc); if(onblockform) { - mapManager.touch(loc); + mapManager.touch(loc, "blockform"); } } @@ -487,7 +489,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI { Location loc = event.getBlock().getLocation(); mapManager.sscache.invalidateSnapshot(loc); if(onblockfade) { - mapManager.touch(loc); + mapManager.touch(loc, "blockfade"); } } @@ -498,7 +500,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI { Location loc = event.getBlock().getLocation(); mapManager.sscache.invalidateSnapshot(loc); if(onblockspread) { - mapManager.touch(loc); + mapManager.touch(loc, "blockspread"); } } @@ -516,7 +518,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI { dir = BlockFace.NORTH; } if(onpiston) { - mapManager.touchVolume(loc, b.getRelative(dir, 2).getLocation()); + mapManager.touchVolume(loc, b.getRelative(dir, 2).getLocation(), "pistonretract"); } for(int i = 0; i < 2; i++) { b = b.getRelative(dir, 1); @@ -537,7 +539,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI { dir = BlockFace.NORTH; } if(onpiston) { - mapManager.touchVolume(loc, b.getRelative(dir, 1+event.getLength()).getLocation()); + mapManager.touchVolume(loc, b.getRelative(dir, 1+event.getLength()).getLocation(), "pistonextend"); } for(int i = 0; i < 1+event.getLength(); i++) { b = b.getRelative(dir, 1); @@ -577,12 +579,12 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI { PlayerListener playerTrigger = new PlayerListener() { @Override public void onPlayerJoin(PlayerJoinEvent event) { - mapManager.touch(event.getPlayer().getLocation()); + mapManager.touch(event.getPlayer().getLocation(), "playerjoin"); } @Override public void onPlayerMove(PlayerMoveEvent event) { - mapManager.touch(event.getPlayer().getLocation()); + mapManager.touch(event.getPlayer().getLocation(), "playermove"); } }; @@ -602,7 +604,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI { Location loc = b.getLocation(); mapManager.sscache.invalidateSnapshot(loc); if(onexplosion) { - mapManager.touch(loc); + mapManager.touch(loc, "entityexplode"); } } } @@ -620,13 +622,13 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI { /* Touch extreme corners */ int x = event.getChunk().getX() << 4; int z = event.getChunk().getZ() << 4; - mapManager.touchVolume(new Location(event.getWorld(), x, 0, z), new Location(event.getWorld(), x+16, 128, z+16)); + mapManager.touchVolume(new Location(event.getWorld(), x, 0, z), new Location(event.getWorld(), x+16, 128, z+16), "chunkload"); } @Override public void onChunkPopulate(ChunkPopulateEvent event) { int x = event.getChunk().getX() << 4; int z = event.getChunk().getZ() << 4; - mapManager.touchVolume(new Location(event.getWorld(), x, 0, z), new Location(event.getWorld(), x+16, 128, z+16)); + mapManager.touchVolume(new Location(event.getWorld(), x, 0, z), new Location(event.getWorld(), x+16, 128, z+16), "chunkgenerate"); } @Override public void onWorldLoad(WorldLoadEvent event) { @@ -725,6 +727,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI { "radiusrender", "reload", "stats", + "triggerstats", "resetstats", "sendtoweb", "purgequeue" })); @@ -753,7 +756,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI { if (c.equals("render") && checkPlayerPermission(sender,"render")) { if (player != null) { - int invalidates = mapManager.touch(player.getLocation()); + int invalidates = mapManager.touch(player.getLocation(), "render"); sender.sendMessage("Queued " + invalidates + " tiles" + (invalidates == 0 ? " (world is not loaded?)" : "...")); @@ -860,6 +863,8 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI { mapManager.printStats(sender, null); else mapManager.printStats(sender, args[1]); + } else if (c.equals("triggerstats") && checkPlayerPermission(sender, "stats")) { + mapManager.printTriggerStats(sender); } else if (c.equals("resetstats") && checkPlayerPermission(sender, "resetstats")) { if(args.length == 1) mapManager.resetStats(sender, null); @@ -1322,9 +1327,9 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI { public int triggerRenderOfVolume(Location l0, Location l1) { if(mapManager != null) { if(l1 == null) - return mapManager.touch(l0); + return mapManager.touch(l0, "api"); else - return mapManager.touchVolume(l0, l1); + return mapManager.touchVolume(l0, l1, "api"); } return 0; } diff --git a/src/main/java/org/dynmap/MapManager.java b/src/main/java/org/dynmap/MapManager.java index 6ece378f..754ab86b 100644 --- a/src/main/java/org/dynmap/MapManager.java +++ b/src/main/java/org/dynmap/MapManager.java @@ -80,6 +80,14 @@ public class MapManager { int updatedcnt; int transparentcnt; } + + private HashMap trigstats = new HashMap(); + + private static class TriggerStats { + long callsmade; + long callswithtiles; + long tilesqueued; + } public DynmapWorld getWorld(String name) { DynmapWorld world = worldsLookup.get(name); @@ -862,8 +870,8 @@ public class MapManager { for(ConfigurationNode tile : tiles) { MapTile mt = MapTile.restoreTile(w, tile); /* Restore tile, if possible */ if(mt != null) { - invalidateTile(mt); - cnt++; + if(invalidateTile(mt)) + cnt++; } } if(cnt > 0) @@ -916,7 +924,7 @@ public class MapManager { } } - public int touch(Location l) { + public int touch(Location l, String reason) { DynmapWorld world = getWorld(l.getWorld().getName()); if (world == null) return 0; @@ -924,14 +932,26 @@ public class MapManager { for (int i = 0; i < world.maps.size(); i++) { MapTile[] tiles = world.maps.get(i).getTiles(l); for (int j = 0; j < tiles.length; j++) { - invalidateTile(tiles[j]); - invalidates++; + if(invalidateTile(tiles[j])) + invalidates++; + } + } + if(reason != null) { + TriggerStats ts = trigstats.get(reason); + if(ts == null) { + ts = new TriggerStats(); + trigstats.put(reason, ts); + } + ts.callsmade++; + if(invalidates > 0) { + ts.callswithtiles++; + ts.tilesqueued += invalidates; } } return invalidates; } - public int touchVolume(Location l0, Location l1) { + public int touchVolume(Location l0, Location l1, String reason) { DynmapWorld world = getWorld(l0.getWorld().getName()); if (world == null) return 0; @@ -939,16 +959,27 @@ public class MapManager { for (int i = 0; i < world.maps.size(); i++) { MapTile[] tiles = world.maps.get(i).getTiles(l0, l1); for (int j = 0; j < tiles.length; j++) { - invalidateTile(tiles[j]); - invalidates++; + if(invalidateTile(tiles[j])) + invalidates++; + } + } + if(reason != null) { + TriggerStats ts = trigstats.get(reason); + if(ts == null) { + ts = new TriggerStats(); + trigstats.put(reason, ts); + } + ts.callsmade++; + if(invalidates > 0) { + ts.callswithtiles++; + ts.tilesqueued += invalidates; } } return invalidates; } - public void invalidateTile(MapTile tile) { - if(tileQueue.push(tile)) - Debug.debug("Invalidating tile " + tile.getFilename()); + public boolean invalidateTile(MapTile tile) { + return tileQueue.push(tile); } public static boolean scheduleDelayedJob(Runnable job, long delay_in_msec) { @@ -1149,6 +1180,19 @@ public class MapManager { act += wn + " "; sender.sendMessage(" Active render jobs: " + act); } + /** + * Print trigger statistics command + */ + public void printTriggerStats(CommandSender sender) { + sender.sendMessage("Render Trigger Statistics:"); + synchronized(lock) { + for(String k: new TreeSet(trigstats.keySet())) { + TriggerStats ts = trigstats.get(k); + sender.sendMessage(" " + k + ": calls=" + ts.callsmade + ", calls-adding-tiles=" + ts.callswithtiles + ", tiles-added=" + ts.tilesqueued); + } + } + } + /** * Reset statistics */ @@ -1163,6 +1207,12 @@ public class MapManager { ms.updatedcnt = 0; ms.transparentcnt = 0; } + for(String k : trigstats.keySet()) { + TriggerStats ts = trigstats.get(k); + ts.callsmade = 0; + ts.callswithtiles = 0; + ts.tilesqueued = 0; + } } sscache.resetStats(); sender.sendMessage("Tile Render Statistics reset"); diff --git a/src/main/java/org/dynmap/MapTile.java b/src/main/java/org/dynmap/MapTile.java index 30f9df25..1d67ae40 100644 --- a/src/main/java/org/dynmap/MapTile.java +++ b/src/main/java/org/dynmap/MapTile.java @@ -38,13 +38,7 @@ public abstract class MapTile { } @Override - public boolean equals(Object obj) { - if (obj instanceof MapTile) { - MapTile t = (MapTile)obj; - return getFilename().equals(t.getFilename()) && getWorld().equals(t.getWorld()); - } - return super.equals(obj); - } + public abstract boolean equals(Object obj); public abstract String getKey(); diff --git a/src/main/java/org/dynmap/kzedmap/KzedZoomedMapTile.java b/src/main/java/org/dynmap/kzedmap/KzedZoomedMapTile.java index 9e92f663..63b401a0 100644 --- a/src/main/java/org/dynmap/kzedmap/KzedZoomedMapTile.java +++ b/src/main/java/org/dynmap/kzedmap/KzedZoomedMapTile.java @@ -81,7 +81,7 @@ public class KzedZoomedMapTile extends MapTile { if (obj instanceof KzedZoomedMapTile) { return ((KzedZoomedMapTile) obj).originalTile.equals(originalTile); } - return super.equals(obj); + return false; } diff --git a/src/main/java/org/dynmap/markers/impl/MarkerAPIImpl.java b/src/main/java/org/dynmap/markers/impl/MarkerAPIImpl.java index 3453835a..22069050 100644 --- a/src/main/java/org/dynmap/markers/impl/MarkerAPIImpl.java +++ b/src/main/java/org/dynmap/markers/impl/MarkerAPIImpl.java @@ -23,6 +23,7 @@ import org.bukkit.World; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; import org.bukkit.util.config.Configuration; import org.bukkit.util.config.ConfigurationNode; import org.dynmap.Client; @@ -52,6 +53,7 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener { private HashMap markersets = new HashMap(); private HashMap> pointaccum = new HashMap>(); private Server server; + private Plugin dynmap; static MarkerAPIImpl api; /* Built-in icons */ @@ -153,6 +155,30 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener { msg = "setupdated"; } } + + private boolean stop = false; + private Set dirty_worlds = new HashSet(); + private boolean dirty_markers = false; + + private class DoFileWrites implements Runnable { + public void run() { + if(stop) + return; + /* Write markers first - drives JSON updates too */ + if(dirty_markers) { + doSaveMarkers(); + dirty_markers = false; + } + /* Process any dirty worlds */ + if(!dirty_worlds.isEmpty()) { + for(String world : dirty_worlds) { + writeMarkersFile(world); + } + dirty_worlds.clear(); + } + server.getScheduler().scheduleSyncDelayedTask(dynmap, this, 20); + } + } /** * Singleton initializer @@ -162,6 +188,7 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener { api.cleanup(plugin); } api = new MarkerAPIImpl(); + api.dynmap = plugin; api.server = plugin.getServer(); /* Initialize persistence file name */ api.markerpersist = new File(plugin.getDataFolder(), "markers.yml"); @@ -200,16 +227,28 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener { api.freshenMarkerFiles(); /* Add listener so we update marker files for other worlds as they become active */ plugin.events.addListener("worldactivated", api); + + api.scheduleWriteJob(); /* Start write job */ return api; } + private void scheduleWriteJob() { + server.getScheduler().scheduleSyncDelayedTask(dynmap, new DoFileWrites(), 20); + } + /** * Cleanup */ public void cleanup(DynmapPlugin plugin) { plugin.events.removeListener("worldactivated", api); + stop = true; + if(dirty_markers) { + doSaveMarkers(); + dirty_markers = false; + } + for(MarkerIconImpl icn : markericons.values()) icn.cleanup(); markericons.clear(); @@ -348,6 +387,11 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener { * Save persistence for markers */ static void saveMarkers() { + if(api != null) { + api.dirty_markers = true; + } + } + private void doSaveMarkers() { if(api != null) { Configuration conf = new Configuration(api.markerpersist); /* Make configuration object */ /* First, save icon definitions */ @@ -386,7 +430,7 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener { private void freshenMarkerFiles() { if(MapManager.mapman != null) { for(DynmapWorld w : MapManager.mapman.worlds) { - writeMarkersFile(w.world.getName()); + dirty_worlds.add(w.world.getName()); } } } @@ -430,7 +474,7 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener { static void markerUpdated(MarkerImpl marker, MarkerUpdate update) { /* Freshen marker file for the world for this marker */ if(api != null) - api.writeMarkersFile(marker.getWorld()); + api.dirty_worlds.add(marker.getWorld()); /* Enqueue client update */ if(MapManager.mapman != null) MapManager.mapman.pushUpdate(marker.getWorld(), new MarkerUpdated(marker, update == MarkerUpdate.DELETED)); @@ -443,7 +487,7 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener { static void areaMarkerUpdated(AreaMarkerImpl marker, MarkerUpdate update) { /* Freshen marker file for the world for this marker */ if(api != null) - api.writeMarkersFile(marker.getWorld()); + api.dirty_worlds.add(marker.getWorld()); /* Enqueue client update */ if(MapManager.mapman != null) MapManager.mapman.pushUpdate(marker.getWorld(), new AreaMarkerUpdated(marker, update == MarkerUpdate.DELETED)); @@ -1381,7 +1425,7 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener { /** * Write markers file for given world */ - public void writeMarkersFile(String wname) { + private void writeMarkersFile(String wname) { Map markerdata = new HashMap(); File f = new File(markertiledir, "marker_" + wname + ".json"); @@ -1465,7 +1509,7 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener { @Override public void triggered(DynmapWorld t) { /* Update markers for now-active world */ - writeMarkersFile(t.world.getName()); + dirty_worlds.add(t.world.getName()); } /* Remove icon */ diff --git a/src/main/java/org/dynmap/markers/impl/MarkerSignManager.java b/src/main/java/org/dynmap/markers/impl/MarkerSignManager.java index 101950ba..ac43bfa9 100644 --- a/src/main/java/org/dynmap/markers/impl/MarkerSignManager.java +++ b/src/main/java/org/dynmap/markers/impl/MarkerSignManager.java @@ -52,11 +52,11 @@ public class MarkerSignManager { set = v.substring(4); evt.setLine(i, ""); } - else if(label.length() == 0) { - label = escapeMarkup(v); - } - else { - label = label + "
" + escapeMarkup(v); + else if(v.length() > 0) { + if(label.length() > 0) { + label = label + "
"; + } + label = label + escapeMarkup(v); } } /* Get the set and see if the marker is already defined */ diff --git a/src/main/java/org/dynmap/regions/RegionsComponent.java b/src/main/java/org/dynmap/regions/RegionsComponent.java index 5f5b4754..0456b0d1 100644 --- a/src/main/java/org/dynmap/regions/RegionsComponent.java +++ b/src/main/java/org/dynmap/regions/RegionsComponent.java @@ -24,16 +24,32 @@ public class RegionsComponent extends ClientComponent { private TownyConfigHandler towny; private FactionsConfigHandler factions; private String regiontype; + + private static String deprecated_ids[] = { "Residence", "Factions", "Towny", "WorldGuard" }; + private static String deprecated_new_plugins[] = { "dynmap-residence", "Dynmap-Factions", "Dynmap-Towny", "Dynmap-WorldGuard" }; public RegionsComponent(final DynmapPlugin plugin, final ConfigurationNode configuration) { super(plugin, configuration); + + regiontype = configuration.getString("name", "WorldGuard"); + /* Check if a deprecated component */ + for(int i = 0; i < deprecated_ids.length; i++) { + if(regiontype.equals(deprecated_ids[i])) { /* If match */ + /* See if new plugin is installed - disable if it is */ + if(plugin.getServer().getPluginManager().getPlugin(deprecated_new_plugins[i]) != null) { + Log.info("Region component for '" + regiontype + "' disabled, replaced by '" + deprecated_new_plugins[i] + "' plugin, which is installed"); + disableComponent(); + return; + } + else { + Log.info("Region component for '" + regiontype + "' has been DEPRECATED - migrate to '" + deprecated_new_plugins[i] + "' plugin"); + } + } + } // For internal webserver. String fname = configuration.getString("filename", "regions.yml"); - regiontype = configuration.getString("name", "WorldGuard"); - - /* Load special handler for Towny */ if(regiontype.equals("Towny")) { towny = new TownyConfigHandler(configuration); diff --git a/src/main/java/org/dynmap/utils/BlockLightLevel.java b/src/main/java/org/dynmap/utils/BlockLightLevel.java new file mode 100644 index 00000000..4054147f --- /dev/null +++ b/src/main/java/org/dynmap/utils/BlockLightLevel.java @@ -0,0 +1,80 @@ +package org.dynmap.utils; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.bukkit.block.Block; +import org.dynmap.Log; + +/** + * Wrapper for accessing raw light levels for given block + */ +public class BlockLightLevel { + private Method gethandle; + private Method getrawlight; + private Object enum_sky; + private Object enum_block; + private boolean ready; + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public BlockLightLevel() { + /* Get CraftChunk.getChunkSnapshot(boolean,boolean,boolean) and CraftChunk.getHandle() */ + try { + Class c = Class.forName("org.bukkit.craftbukkit.CraftChunk"); + gethandle = c.getDeclaredMethod("getHandle", new Class[0]); + Class enumskyblock = Class.forName("net.minecraft.server.EnumSkyBlock"); + Object[] enumvals = enumskyblock.getEnumConstants(); + for(int i = 0; i < enumvals.length; i++) { + String ev = enumvals[i].toString(); + if(ev.equals("Sky")) { + enum_sky = enumvals[i]; + } + else if(ev.equals("Block")) { + enum_block = enumvals[i]; + } + } + Class cc = Class.forName("net.minecraft.server.Chunk"); + getrawlight = cc.getDeclaredMethod("a", new Class[] { enumskyblock, int.class, int.class, int.class }); + } catch (ClassNotFoundException cnfx) { + } catch (NoSuchMethodException nsmx) { + } + if((gethandle != null) && (enum_sky != null) && (enum_block != null) && (getrawlight != null)) { + ready = true; + } + else { + Log.warning("Block raw light level API not available"); + } + } + + public boolean isReady() { + return ready; + } + + public int getSkyLightLevel(Block b) { + try { + Object hand = gethandle.invoke(b.getChunk()); + if(hand != null) { + Integer v = (Integer)getrawlight.invoke(hand, enum_sky, b.getX() & 0xF, b.getY() & 0x7F, b.getZ() & 0xF); + return v; + } + } catch (InvocationTargetException itx) { + } catch (IllegalArgumentException e) { + } catch (IllegalAccessException e) { + } + return -1; + } + + public int getBlockLightLevel(Block b) { + try { + Object hand = gethandle.invoke(b.getChunk()); + if(hand != null) { + Integer v = (Integer)getrawlight.invoke(hand, enum_block, b.getX() & 0xF, b.getY() & 0x7F, b.getZ() & 0xF); + return v; + } + } catch (InvocationTargetException itx) { + } catch (IllegalArgumentException e) { + } catch (IllegalAccessException e) { + } + return -1; + } +} diff --git a/src/main/resources/configuration.txt b/src/main/resources/configuration.txt index 999879c0..799126b7 100644 --- a/src/main/resources/configuration.txt +++ b/src/main/resources/configuration.txt @@ -113,129 +113,6 @@ components: # timeout: 1800 # in seconds (1800 seconds = 30 minutes) # redirecturl: inactive.html # #showmessage: 'You were inactive for too long.' - - #- class: org.dynmap.regions.RegionsComponent - # type: regions - # name: WorldGuard - # useworldpath: true - # filename: regions.yml - # basenode: regions - # use3dregions: true - # regionstyle: - # strokeColor: "#FF0000" - # strokeOpacity: 0.8 - # strokeWeight: 3 - # fillColor: "#FF0000" - # fillOpacity: 0.35 - # # Optional setting to limit which regions to show, by name - if commented out, all regions are shown - # visibleregions: - # - homebase - # - miningsite - # # Optional setting to hide specific regions, by name - # hiddenregions: - # - hiddenplace - # - secretsite - # # Optional per-region overrides for regionstyle (any defined replace those in regionstyle) - # customstyle: - # homebase: - # strokeColor: "#00FF00" - # # Optional - make layer hidden by default - # hidebydefault: true - # # Optional - ordering priority in layer menu (low goes before high - default is 0) - # layerprio: 1 - - #- class: org.dynmap.regions.RegionsComponent - # type: regions - # name: Residence - # useworldpath: false - # filename: res.yml - # basenode: Residences - # use3dregions: false - # infowindow: '
%regionname%
Owner %playerowners%
Flags
%flags%
' - # regionstyle: - # strokeColor: "#FF0000" - # strokeOpacity: 0.8 - # strokeWeight: 3 - # fillColor: "#FF0000" - # fillOpacity: 0.35 - # # Optional setting to limit which regions to show, by name - if commented out, all regions are shown - # visibleregions: - # - homebase - # - miningsite - # - area.subzone1 - # # Optional setting to hide specific regions, by name - # hiddenregions: - # - hiddenplace - # - secretsite - # # Optional per-region overrides for regionstyle (any defined replace those in regionstyle) - # customstyle: - # homebase: - # strokeColor: "#00FF00" - # # Optional groups (subareas under a residence) overrides for regionstyle (any defined replace those in regionstyle) - # groupstyle: - # homebase: - # strokeColor: "#007F00" - # # Optional - make layer hidden by default - # hidebydefault: true - # # Optional - ordering priority in layer menu (low goes before high - default is 0) - # layerprio: 1 - - #- class: org.dynmap.regions.RegionsComponent - # type: regions - # name: Towny - # use3dregions: false - # infowindow: '
%regionname% (%nation%)
Mayor %playerowners%
Associates %playermanagers%
Flags
%flags%
' - # regionstyle: - # strokeColor: "#FF0000" - # strokeOpacity: 0.8 - # strokeWeight: 3 - # fillColor: "#FF0000" - # fillOpacity: 0.35 - # # Optional setting to limit which regions to show, by name - if commented out, all regions are shown - # visibleregions: - # - homebase - # - miningsite - # # Optional setting to hide specific regions, by name - # hiddenregions: - # - hiddenplace - # - secretsite - # # Optional per-town overrides for regionstyle (any defined replace those in regionstyle) - # customstyle: - # homebase: - # strokeColor: "#00FF00" - # # Optional per-nation overrides for regionstyle (any defined replace those in regionstyle) - # groupstyle: - # MyNation: - # strokeColor: "#007F00" - # # Optional - make layer hidden by default - # hidebydefault: true - - #- class: org.dynmap.regions.RegionsComponent - # type: regions - # name: Factions - # use3dregions: false - # infowindow: '
%regionname%
Flags
%flags%
' - # regionstyle: - # strokeColor: "#FF0000" - # strokeOpacity: 0.8 - # strokeWeight: 3 - # fillColor: "#FF0000" - # fillOpacity: 0.35 - # # Optional setting to limit which regions to show, by name - if commented out, all regions are shown - # visibleregions: - # - faction1 - # - faction2 - # # Optional setting to hide specific regions, by name - # hiddenregions: - # - hiddenfaction - # # Optional per-faction overrides for regionstyle (any defined replace those in regionstyle) - # customstyle: - # faction1: - # strokeColor: "#00FF00" - # # Optional - make layer hidden by default - # hidebydefault: true - # # Optional - ordering priority in layer menu (low goes before high - default is 0) - # layerprio: 1 #- class: org.dynmap.TestComponent # stuff: "This is some configuration-value" @@ -281,7 +158,7 @@ enabletilehash: true # Control behavior for new (1.9+) compass orientation (sunrise moved 90 degrees: east is now what used to be south) # default is 'pre19' for 1.8 server (existing orientation), 'newrose' for 1.9+ (preserve maps, rotate rose) # 'newnorth' is used to rotate maps and rose (requires fullrender of any HDMap map - same as 'newrose' for FlatMap or KzedMap) -#compass-mode: newnorth +compass-mode: newnorth # Enable Industrial Craft 2 block rendering support #ic2-support: true diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index d87ada6c..261816e7 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -8,7 +8,7 @@ commands: description: Controls Dynmap. usage: | / hide - hides the player from the map. - / hide TheDude - hides the player 'TheDude' from the map. + / hide TheDude - hides the player 'TheDude' on the map. / show - shows the player on the map. / show TheDude - shows the player 'TheDude' on the map. / render - Renders the tile at your location. @@ -21,6 +21,7 @@ commands: / cancelrender world - Cancels any active renders of world 'world' / stats - Show render statistics. / stats world - Show render statistics for maps on world 'world'. + / triggerstats - Show render trigger statistics / resetstats - Reset render statistics. / resetstats world - Reset render statistics for maps on world 'world'. / sendtoweb msg - Send message to web users @@ -125,7 +126,7 @@ permissions: description: Allows /dynmap reload default: op dynmap.stats: - description: Allows /dynmap stats or /dynmap stats + description: Allows /dynmap stats, /dynmap stats , or /dynmap triggerstats default: true dynmap.resetstats: description: Allows /dynmap resetstats or /dynmap resetstats diff --git a/src/main/resources/texture.txt b/src/main/resources/texture.txt index 49a43952..e4ed4ed8 100644 --- a/src/main/resources/texture.txt +++ b/src/main/resources/texture.txt @@ -92,29 +92,35 @@ block:id=26,data=11,top=6135,bottom=6135,south=152,east=7151,west=151,transparen # Bed - foot - pointing south block:id=26,data=3,top=6134,bottom=6134,north=149,east=7150,west=150,transparency=TRANSPARENT # Powered rail - heading east-west - unpowered +block:id=27,data=0,top=4163,bottom=4163,transparency=TRANSPARENT # Powered rail - incline to east - unpowered # Powered rail - incline to west - unpowered -block:id=27,data=0,data=4,data=5,top=4163,bottom=4163,allsides=4,transparency=TRANSPARENT +block:id=27,data=4,data=5,top=4163,bottom=4163,east=163,west=163,transparency=TRANSPARENT # Powered rail - heading east-west - powered +block:id=27,data=8,top=4179,bottom=4179,transparency=TRANSPARENT # Powered rail - incline to east - powered # Powered rail - incline to west - powered -block:id=27,data=8,data=12,data=13,top=4179,bottom=4179,allsides=4,transparency=TRANSPARENT +block:id=27,data=12,data=13,top=4179,bottom=4179,east=179,west=179,transparency=TRANSPARENT # Powered rail - heading north-south - unpowered +block:id=27,data=1,top=163,bottom=163,transparency=TRANSPARENT # Powered rail - inclined to north - unpowered # Powered rail - inclined to south - unpowered -block:id=27,data=1,data=2,data=3,top=163,bottom=163,allsides=4,transparency=TRANSPARENT -# Powered rail - heading north-sout - powered +block:id=27,data=2,data=3,top=163,bottom=163,north=163,south=163,transparency=TRANSPARENT +# Powered rail - heading north-south - powered +block:id=27,data=9,top=179,bottom=179,transparency=TRANSPARENT # Powered rail - inclined to north - powered # Powered rail - inclined to south - powered -block:id=27,data=9,data=10,data=11,top=179,bottom=179,allsides=4,transparency=TRANSPARENT +block:id=27,data=10,data=11,top=179,bottom=179,north=179,south=179,transparency=TRANSPARENT # Detector rail - heading east-west +block:id=28,data=0,top=4195,bottom=4195,transparency=TRANSPARENT # Detector rail - incline to east # Detector rail - incline to west -block:id=28,data=0,data=4,data=5,top=4195,bottom=4195,allsides=4,transparency=TRANSPARENT +block:id=28,data=4,data=5,top=4195,bottom=4195,east=195,west=195,transparency=TRANSPARENT # Detector rail - heading north-south +block:id=28,data=1,top=195,bottom=195,transparency=TRANSPARENT # Detector rail - incline to north # Detector rail - incline to south -block:id=28,data=1,data=2,data=3,top=195,bottom=195,allsides=4,transparency=TRANSPARENT +block:id=28,data=2,data=3,top=195,bottom=195,north=195,south=195,transparency=TRANSPARENT # Sticky piston - facing down block:id=29,data=0,top=109,bottom=106,allsides=5108 # Sticky piston - facing up @@ -377,7 +383,7 @@ block:id=66,data=0,top=4128,bottom=4128,transparency=TRANSPARENT # Rail - incline to west block:id=66,data=4,data=5,top=4128,bottom=4128,east=128,west=128,transparency=TRANSPARENT # Rail - heading north-south -block:id=66,data=1,top=128,bottom=128,allsides=4,transparency=TRANSPARENT +block:id=66,data=1,top=128,bottom=128,transparency=TRANSPARENT # Rail - incline to north # Rail - incline to south block:id=66,data=2,data=3,top=128,bottom=128,north=128,south=128,transparency=TRANSPARENT