From 992a905b0a05896109775697f31540515f366169 Mon Sep 17 00:00:00 2001 From: Mike Primm Date: Fri, 20 May 2011 20:52:34 -0500 Subject: [PATCH] Add shadowstrength attribute for surface renderer - enables shadows based on top-down chunk sky light data --- configuration.txt | 392 +++++++++--------- src/main/java/org/dynmap/MapChunkCache.java | 19 +- .../dynmap/kzedmap/DefaultTileRenderer.java | 45 +- 3 files changed, 257 insertions(+), 199 deletions(-) diff --git a/configuration.txt b/configuration.txt index c765f162..b02ad709 100644 --- a/configuration.txt +++ b/configuration.txt @@ -1,195 +1,197 @@ -# 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: -# - chunkloaded -# - playermove -# - playerjoin - - blockplaced - - blockbreak - -# The path where the tile-files are placed. -tilespath: web/tiles - -# The path where the web-files are located. -webpath: web - -# The network-interface the webserver will bind to (0.0.0.0 for all interfaces, 127.0.0.1 for only local access). -webserver-bindaddress: 0.0.0.0 - -# The TCP-port the webserver will listen on. -webserver-port: 8123 - -# Disables Webserver portion of Dynmap (Advanced users only) -disable-webserver: false - -# Writes JSON to file in the webpath -jsonfile: false - -# How often the json file gets written to(in seconds) -jsonfile-interval: 1 - -# Output player health for web usage -health-in-json: false - -# 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 - maps: - - class: org.dynmap.flat.FlatMap - prefix: flat - colorscheme: default - - class: org.dynmap.kzedmap.KzedMap - renderers: - - class: org.dynmap.kzedmap.DefaultTileRenderer - 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 - - name: nether - maps: - - class: org.dynmap.flat.FlatMap - prefix: flat - colorscheme: default - - class: org.dynmap.kzedmap.KzedMap - renderers: - - class: org.dynmap.kzedmap.DefaultTileRenderer - prefix: nt - maximumheight: 127 - colorscheme: default - -web: - # Handles the clientside updates differently only enable if using jsonfile - jsonfile: false - - # Interval the browser should poll for updates. - updaterate: 2000 - - allowchat: true - allowwebchat: true - webchat-interval: 5 - # Set to true to enable HeroChat support - enableherochat: false - # Control which HeroChat channel messages from web are directed to - herochatwebchannel: Global - # Control which channels are monitored and reported to the web - herochatchannels: - - Global - #- Trade - #- Haggle - - showplayerfacesinmenu: true - - joinmessage: "%playername% joined" - quitmessage: "%playername% quit" - spammessage: "You may only chat once every %interval% seconds." - - components: - - type: chat - - type: chatballoon - focuschatballoons: false - - type: chatbox - showplayerfaces: true - messagettl: 5 - - type: playermarkers - showplayerfaces: true - showplayerhealth: false - #- type: digitalclock - - type: timeofdayclock - showdigitalclock: true - #showweather: true - #- type: regions - # name: WorldGuard - # useworldpath: true - # filename: regions.yml - # basenode: regions - # use3dregions: true - # infowindow: '
%regionname% - %priority% (%parent%)
Owners %playerowners% %groupowners%
Members %playermembers% %groupmembers%
Flags
%flags%
' - # regionstyle: - # strokeColor: "#FF0000" - # strokeOpacity: 0.8 - # strokeWeight: 3 - # fillColor: "#FF0000" - # fillOpacity: 0.35 - - defaultzoom: 0 - defaultworld: world - worlds: - - title: World - name: world - center: - x: 0 - y: 64 - z: 0 - maps: - - type: FlatMapType - title: Flat - name: flat - prefix: flat - - type: KzedMapType - title: Surface - name: surface - prefix: t - #- type: KzedMapType - # title: Highlighted Map - # name: highlight - # prefix: ht - - type: KzedMapType - title: Cave - name: cave - prefix: ct - - title: Nether - name: nether - center: - x: 0 - y: 64 - z: 0 - maps: - - type: FlatMapType - title: Flat - name: flat - prefix: flat - - type: KzedMapType - title: Surface - name: nether - prefix: nt - # Example: - #- title: Other World # With what name the world is displayed. - # name: world_other # The actual name of the world (equal to your directory-name). - # maps: - # - type: KzedMapType # The type (or perspective) of the map. At the moment, there are no others than KzedMapType. - # title: Surface # The name of the map that will be displayed. - # name: surface # The actual name of the map (should be unique for this world). - # prefix: t # The prefix of the tile-files that are generated. - # icon: images/block_other.png # Sets a custom icon for the map. (optional) - # - type: KzedMapType - # title: Cave - # name: cave - # prefix: ct -# Enables debugging. -#debuggers: -# - class: org.dynmap.debug.LogDebugger +# 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: +# - chunkloaded +# - playermove +# - playerjoin + - blockplaced + - blockbreak + +# The path where the tile-files are placed. +tilespath: web/tiles + +# The path where the web-files are located. +webpath: web + +# The network-interface the webserver will bind to (0.0.0.0 for all interfaces, 127.0.0.1 for only local access). +webserver-bindaddress: 0.0.0.0 + +# The TCP-port the webserver will listen on. +webserver-port: 8123 + +# Disables Webserver portion of Dynmap (Advanced users only) +disable-webserver: false + +# Writes JSON to file in the webpath +jsonfile: false + +# How often the json file gets written to(in seconds) +jsonfile-interval: 1 + +# Output player health for web usage +health-in-json: false + +# 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 + maps: + - class: org.dynmap.flat.FlatMap + prefix: flat + colorscheme: default + - class: org.dynmap.kzedmap.KzedMap + renderers: + - class: org.dynmap.kzedmap.DefaultTileRenderer + prefix: t + maximumheight: 127 + colorscheme: default + # Add shadows to world (based on top-down shadows from chunk data) + # shadowstrength: 1.0 + #- 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 + - name: nether + maps: + - class: org.dynmap.flat.FlatMap + prefix: flat + colorscheme: default + - class: org.dynmap.kzedmap.KzedMap + renderers: + - class: org.dynmap.kzedmap.DefaultTileRenderer + prefix: nt + maximumheight: 127 + colorscheme: default + +web: + # Handles the clientside updates differently only enable if using jsonfile + jsonfile: false + + # Interval the browser should poll for updates. + updaterate: 2000 + + allowchat: true + allowwebchat: true + webchat-interval: 5 + # Set to true to enable HeroChat support + enableherochat: false + # Control which HeroChat channel messages from web are directed to + herochatwebchannel: Global + # Control which channels are monitored and reported to the web + herochatchannels: + - Global + #- Trade + #- Haggle + + showplayerfacesinmenu: true + + joinmessage: "%playername% joined" + quitmessage: "%playername% quit" + spammessage: "You may only chat once every %interval% seconds." + + components: + - type: chat + - type: chatballoon + focuschatballoons: false + - type: chatbox + showplayerfaces: true + messagettl: 5 + - type: playermarkers + showplayerfaces: true + showplayerhealth: false + #- type: digitalclock + - type: timeofdayclock + showdigitalclock: true + #showweather: true + #- type: regions + # name: WorldGuard + # useworldpath: true + # filename: regions.yml + # basenode: regions + # use3dregions: true + # infowindow: '
%regionname% - %priority% (%parent%)
Owners %playerowners% %groupowners%
Members %playermembers% %groupmembers%
Flags
%flags%
' + # regionstyle: + # strokeColor: "#FF0000" + # strokeOpacity: 0.8 + # strokeWeight: 3 + # fillColor: "#FF0000" + # fillOpacity: 0.35 + + defaultzoom: 0 + defaultworld: world + worlds: + - title: World + name: world + center: + x: 0 + y: 64 + z: 0 + maps: + - type: FlatMapType + title: Flat + name: flat + prefix: flat + - type: KzedMapType + title: Surface + name: surface + prefix: t + #- type: KzedMapType + # title: Highlighted Map + # name: highlight + # prefix: ht + - type: KzedMapType + title: Cave + name: cave + prefix: ct + - title: Nether + name: nether + center: + x: 0 + y: 64 + z: 0 + maps: + - type: FlatMapType + title: Flat + name: flat + prefix: flat + - type: KzedMapType + title: Surface + name: nether + prefix: nt + # Example: + #- title: Other World # With what name the world is displayed. + # name: world_other # The actual name of the world (equal to your directory-name). + # maps: + # - type: KzedMapType # The type (or perspective) of the map. At the moment, there are no others than KzedMapType. + # title: Surface # The name of the map that will be displayed. + # name: surface # The actual name of the map (should be unique for this world). + # prefix: t # The prefix of the tile-files that are generated. + # icon: images/block_other.png # Sets a custom icon for the map. (optional) + # - type: KzedMapType + # title: Cave + # name: cave + # prefix: ct +# Enables debugging. +#debuggers: +# - class: org.dynmap.debug.LogDebugger diff --git a/src/main/java/org/dynmap/MapChunkCache.java b/src/main/java/org/dynmap/MapChunkCache.java index 1649e457..bd4efb10 100644 --- a/src/main/java/org/dynmap/MapChunkCache.java +++ b/src/main/java/org/dynmap/MapChunkCache.java @@ -89,8 +89,8 @@ public class MapChunkCache { Object cc = gethandle.invoke(c); byte[] buf = new byte[32768 + 16384 + 16384 + 16384]; /* Get big enough buffer for whole chunk */ getchunkdata.invoke(cc, buf, 0, 0, 0, 16, 128, 16, 0); - snaparray[(chunk.x-x_min) + (chunk.z - z_min)*x_dim] = - new CraftChunkSnapshot(chunk.x, chunk.z, buf); + CraftChunkSnapshot ss = new CraftChunkSnapshot(chunk.x, chunk.z, buf); + snaparray[(chunk.x-x_min) + (chunk.z - z_min)*x_dim] = ss; } catch (Exception x) { } } @@ -195,4 +195,19 @@ public class MapChunkCache { return w.getHighestBlockYAt(x, z); } } + /* Get sky light level + */ + public int getBlockSkyLight(int x, int y, int z) { + if(snaparray != null) { + CraftChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim]; + if(ss == null) { + return 15; + } + else + return ss.getBlockSkyLight(x & 0xF, y, z & 0xF); + } + else { + return 15; + } + } } diff --git a/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java b/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java index f7d1efae..4c10b118 100644 --- a/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java +++ b/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java @@ -29,6 +29,7 @@ public class DefaultTileRenderer implements MapTileRenderer { protected HashSet highlightBlocks = new HashSet(); protected Color highlightColor = new Color(255, 0, 0); + protected int shadowscale[]; /* index=skylight level, value = 256 * scaling value */ @Override public String getName() { return name; @@ -42,6 +43,19 @@ public class DefaultTileRenderer implements MapTileRenderer { if (maximumHeight > 127) maximumHeight = 127; } + o = configuration.get("shadowstrength"); + if(o != null) { + double shadowweight = Double.parseDouble(String.valueOf(o)); + if(shadowweight > 0.0) { + shadowscale = new int[16]; + for(int i = 0; i < 16; i++) { + double v = 256.0 * (1.0 - (shadowweight * (15-i) / 15.0)); + shadowscale[i] = (int)v; + if(shadowscale[i] > 256) shadowscale[i] = 256; + if(shadowscale[i] < 0) shadowscale[i] = 0; + } + } + } colorScheme = ColorScheme.getScheme((String)configuration.get("colorscheme")); } @@ -210,9 +224,14 @@ public class DefaultTileRenderer implements MapTileRenderer { new Client.Tile(zmtile.getFilename())); } - protected void scan(World world, int x, int y, int z, int seq, boolean isnether, final Color result, MapChunkCache cache) { + scan(world, x, y, z, seq, isnether, result, cache, 15); + } + + private void scan(World world, int x, int y, int z, int seq, boolean isnether, final Color result, + MapChunkCache cache, int lightlevel) { + int newlightlevel = 15; result.setTransparent(); for (;;) { if (y < 0) { @@ -234,6 +253,10 @@ public class DefaultTileRenderer implements MapTileRenderer { if(colorScheme.datacolors[id] != null) { /* If data colored */ data = cache.getBlockData(x, y, z); } + if(shadowscale != null) { + newlightlevel = cache.getBlockSkyLight(x, y, z); /* Remember this - light path for next block */ + } + switch (seq) { case 0: x--; @@ -268,16 +291,25 @@ public class DefaultTileRenderer implements MapTileRenderer { if (c.getAlpha() == 255) { /* it's opaque - the ray ends here */ result.setColor(c); + if(lightlevel < 15) { /* Not full light? */ + shadowColor(result, lightlevel); + } return; } /* this block is transparent, so recurse */ - scan(world, x, y, z, seq, isnether, result, cache); + scan(world, x, y, z, seq, isnether, result, cache, newlightlevel); int cr = c.getRed(); int cg = c.getGreen(); int cb = c.getBlue(); int ca = c.getAlpha(); + if(lightlevel < 15) { + int scale = shadowscale[lightlevel]; + cr = (cr * scale) >> 8; + cg = (cg * scale) >> 8; + cb = (cb * scale) >> 8; + } cr *= ca; cg *= ca; cb *= ca; @@ -287,6 +319,15 @@ public class DefaultTileRenderer implements MapTileRenderer { } } } + lightlevel = newlightlevel; /* Advance - next block uses last block's light */ } } + private final void shadowColor(Color c, int lightlevel) { + int scale = shadowscale[lightlevel]; + if(scale == 0) + c.setRGBA(0, 0, 0, c.getAlpha()); + else if(scale < 256) + c.setRGBA((c.getRed() * scale) >> 8, (c.getGreen() * scale) >> 8, + (c.getBlue() * scale) >> 8, c.getAlpha()); + } }