From c428fcbd70709afead2cfa1d1eafc8bfeb65ec6c Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Mon, 4 Apr 2011 02:03:38 -0400 Subject: [PATCH 1/8] changed testRender.py to work with ./overviewer.py and ./gmap.py (sorta) --- contrib/testRender.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/contrib/testRender.py b/contrib/testRender.py index 2ea0e87..c4de264 100644 --- a/contrib/testRender.py +++ b/contrib/testRender.py @@ -4,6 +4,8 @@ import os, shutil, tempfile, time, sys, math, re from subprocess import Popen, PIPE, STDOUT, CalledProcessError from optparse import OptionParser +overviewer_scripts = ['./overviewer.py', './gmap.py'] + def check_call(*args, **kwargs): quiet = False if "quiet" in kwargs.keys(): @@ -35,12 +37,21 @@ def check_output(*args, **kwargs): def clean_render(overviewerargs, quiet): tempdir = tempfile.mkdtemp('mc-overviewer-test') + overviewer_script = None + for script in overviewer_scripts: + if os.path.exists(script): + overviewer_script = script + break + if overviewer_script is None: + sys.stderr.write("could not find main overviewer script\n") + sys.exit(1) + try: # check_call raises CalledProcessError when overviewer.py exits badly check_call(['python', 'setup.py', 'clean', 'build'], quiet=quiet) - check_call(['./overviewer.py', '-d'] + overviewerargs, quiet=quiet) + check_call([overviewer_script, '-d'] + overviewerargs, quiet=quiet) starttime = time.time() - check_call(['./overviewer.py',] + overviewerargs + [tempdir,], quiet=quiet) + check_call([overviewer_script,] + overviewerargs + [tempdir,], quiet=quiet) endtime = time.time() return endtime - starttime From be62a0b4648491b7a208b97370f92aa6449bf706 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Wed, 6 Apr 2011 22:31:00 -0400 Subject: [PATCH 2/8] Added new sample settings file --- sample.settings.py | 150 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 149 insertions(+), 1 deletion(-) diff --git a/sample.settings.py b/sample.settings.py index 7ee5011..ee0d050 100644 --- a/sample.settings.py +++ b/sample.settings.py @@ -1 +1,149 @@ -# TODO: put something useful in this file! +################################################################################ +# Please see the README or https://github.com/brownan/Minecraft-Overviewer/wiki/DTT-Upgrade-Guide +# for more details. + +# To use this file, simply copy it to settings.py and make any necessary changes +# to suite your needs. + +# This file is a python script, so you can import and python module you wish or +# use any built-in python function, though this is not normally necessary + +# Lines that start with a hash mark are comments + +# Some variables come with defaults (like procs or rendermode) +# If you specify a configuration option in both a settings.py file and on the +# command line, the value from the command line will take precedence + +################################################################################ +### procs +## Specify the number of processors to use for rendering +## Default: The number of CPU cores on your machine +## Type: integer +## Example: set the number of processors to use to be 1 less than the number of +## CPU cpus in your machine + +import multiprocessing +procs = multiprocessing.cpu_count() - 1 +if procs < 1: procs = 1 + + +################################################################################ +### zoom +## Sets the zoom level manually instead of calculating it. This can be useful +## if you have outlier chunks that make your world too big. This value will +## make the highest zoom level contain (2**ZOOM)^2 tiles +## Normally you should not need to set this variable. +## Default: Automatically calculated from your world +## Type: integer +## Example: + +zoom = 9 + +################################################################################ +### regionlist +## A file containing, on each line, a path to a chunkfile to update. Instead +## of scanning the world directory for chunks, it will just use this list. +## Normal caching rules still apply. +## Default: not yet +## Type: string +## Example: Dynamically create regionlist of only regions older than 2 days + +import os, time +regionDir = os.path.join(args[0], "region") +regionFiles = filter(lambda x: x.endswith(".mcr"), os.listdir(regionDir)) +def olderThanTwoDays(f): + return time.time() - os.stat(f).st_mtime > (60*60*24*2) +oldRegionFiles = filter(olderThanTwoDays, regionFiles) +with open("regionlist.txt", "w") as f: + f.write("\n".join(oldRegionFiles)) + + +################################################################################ +### rendermode +## Specifies the render types +## Default: "normal" +## Type: Either a list of strings, or a single string containing modes separated +## by commas +## Example: Render the using the 'lighting' mode, but if today is Sunday, then +## also render the 'night' mode + +import time +rendermode=["lighting"] +if time.localtime().tm_wday == 6: + rendermode.append("night") + + +################################################################################ +### imgformat +## The image output format to use. Currently supported: png(default), jpg. +## NOTE: png will always be used as the intermediate image format. +## Default: not yet +## Type: string +## Example: + +imgformat = "jpg" + + + +################################################################################ +### optimizeimg +## If using png, perform image file size optimizations on the output. Specify 1 +## for pngcrush, 2 for pngcrush+optipng+advdef. This may double (or more) +## render times, but will produce up to 30% smaller images. NOTE: requires +## corresponding programs in $PATH or %PATH% +## Default: not set +## Type: integer +## Example: + +if imgformat != "jpg": + optimizeimg = 2 + + + +################################################################################ +### web_assets_hook +## If provided, run this function after the web assets have been copied, but +## before actual tile rendering beings. It should accept a QuadtreeGen +## object as its only argument. Note: this is only called if skipjs is True +## Default: not yet +## Type: function +## Example: Call an external program to generate something useful + +def web_assets_hook(o): + import subprocess + p = subprocess.Popen(["/path/to/my/script.pl", "--output_dir", args[1]]) + p.wait() + if p.returncode != 0: + raise Exception("web_assets_hook failed") + + + +################################################################################ +### quiet +## Print less output. You can specify higher values to suppress additional output +## Default: 0 +## Type: integer +## Example: +quiet = 1 + + +################################################################################ +### verbose +## Print more output. You can specify higher values to print additional output +## Default: 0 +## Type: integer +## Example: +verbose = 1 + + +################################################################################ +### skipjs +## Don't output marker.js or region.js +## Default: False +## Type: boolean +## Example: Set skipjs if web_assets_hook is defined + +if "web_assets_hook" in locals(): + skipjs = True + + From cb8a17c448f8e514a1b635fd7899f3e866f165ed Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Sun, 10 Apr 2011 03:21:55 -0400 Subject: [PATCH 3/8] fixed bug in sign groups js, for checked: true related to issue #321 --- web_assets/functions.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/web_assets/functions.js b/web_assets/functions.js index 9b42fda..96742af 100644 --- a/web_assets/functions.js +++ b/web_assets/functions.js @@ -153,7 +153,12 @@ function initMarkers() { if (markersInit) { return; } markersInit = true; - + + // first, give all collections an empty array to work with + for (i in signGroups) { + markerCollection[signGroups[i].label] = []; + } + for (i in markerData) { var item = markerData[i]; @@ -195,11 +200,8 @@ function initMarkers() { icon: iconURL, visible: false }); - if (markerCollection[label]) { - markerCollection[label].push(marker); - } else { - markerCollection[label] = [marker]; - } + + markerCollection[label].push(marker); if (item.type == 'sign') { prepareSignMarker(marker, item); From 22fc77308e3f2010f91a32b3e7b4a9f0e55ce3a8 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Sun, 10 Apr 2011 03:44:06 -0400 Subject: [PATCH 4/8] fixed minor inlining error in commit d547727 fixes regression in issue #320 --- chunk.py | 32 -------------------------------- quadtree.py | 12 +++++++----- 2 files changed, 7 insertions(+), 37 deletions(-) diff --git a/chunk.py b/chunk.py index a59d90e..977fdfa 100644 --- a/chunk.py +++ b/chunk.py @@ -129,38 +129,6 @@ fluid_blocks = set([8,9,10,11]) # (glass, half blocks) nospawn_blocks = set([20,44]) -# chunkcoords should be the coordinates of a possible chunk. it may not exist -def render_to_image(chunkcoords, img, imgcoords, quadtreeobj, cave=False, queue=None): - """Used to render a chunk to a tile in quadtree.py. - - chunkcoords is a tuple: (chunkX, chunkY) - - imgcoords is as well: (imgX, imgY), which represents the "origin" - to use for drawing. - - If the chunk doesn't exist, return False. - Else, returns True.""" - a = ChunkRenderer(chunkcoords, quadtreeobj.world, quadtreeobj.rendermode, queue) - try: - a.chunk_render(img, imgcoords[0], imgcoords[1], cave) - return True - except ChunkCorrupt: - # This should be non-fatal, but should print a warning - pass - except Exception, e: - import traceback - traceback.print_exc() - raise - except KeyboardInterrupt: - print - print "You pressed Ctrl-C. Exiting..." - # Raise an exception that is an instance of Exception. Unlike - # KeyboardInterrupt, this will re-raise in the parent, killing the - # entire program, instead of this process dying and the parent waiting - # forever for it to finish. - raise Exception() - return False - class ChunkCorrupt(Exception): pass diff --git a/quadtree.py b/quadtree.py index ac1c26c..d4018f6 100644 --- a/quadtree.py +++ b/quadtree.py @@ -453,11 +453,13 @@ class QuadtreeGen(object): ypos = -96 + (row-rowstart)*96 # draw the chunk! - a = chunk.ChunkRenderer((chunkx, chunky), world, rendermode, poi_queue) - a.chunk_render(tileimg, xpos, ypos, None) -# chunk.render_to_image((chunkx, chunky), tileimg, (xpos, ypos), self, False, None) - - + try: + a = chunk.ChunkRenderer((chunkx, chunky), world, rendermode, poi_queue) + a.chunk_render(tileimg, xpos, ypos, None) + except chunk.ChunkCorrupt: + # an error was already printed + pass + # Save them tileimg.save(imgpath) From dfe30a0d0f036ed563765b5f7f34457a02f3f151 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Sun, 10 Apr 2011 04:01:14 -0400 Subject: [PATCH 5/8] now checks for optimize-img programs with '.exe' as well as no suffix fix for issue #314 --- optimizeimages.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/optimizeimages.py b/optimizeimages.py index 6fe8b78..b3daff7 100644 --- a/optimizeimages.py +++ b/optimizeimages.py @@ -23,11 +23,14 @@ advdef = "advdef" def check_programs(level): path = os.environ.get("PATH").split(os.pathsep) - + + def exists_in_path(prog): + result = filter(lambda x: os.path.exists(os.path.join(x, prog)), path) + return len(result) != 0 + for prog,l in [(pngcrush,1), (optipng,2), (advdef,2)]: if l <= level: - result = filter(lambda x: os.path.exists(os.path.join(x, prog)), path) - if len(result) == 0: + if (not exists_in_path(prog)) or (not exists_in_path(prog + ".exe")): raise Exception("Optimization prog %s for level %d not found!" % (prog, l)) def optimize_image(imgpath, imgformat, optimizeimg): From a2b1f238d9c72f3a8506f9f901a87af7731101b3 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Sun, 10 Apr 2011 04:38:42 -0400 Subject: [PATCH 6/8] changed markers.js to output one marker per line this has been requested *many* times, because it makes it easier to (1) learn what format markers.js uses, and (2) write shell scripts that process markers.js. It shouldn't break existing processors that use json loaders, and does not drastically increase file size (just one extra byte per ~70). --- googlemap.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/googlemap.py b/googlemap.py index 2321049..f6f271e 100644 --- a/googlemap.py +++ b/googlemap.py @@ -144,7 +144,13 @@ class MapGen(object): # write out the default marker table with open(os.path.join(self.destdir, "markers.js"), 'w') as output: - output.write("var markerData=%s" % json.dumps(self.world.POI)) + output.write("var markerData=[\n") + for marker in self.world.POI: + output.write(json.dumps(marker)) + if marker != self.world.POI[-1]: + output.write(",") + output.write("\n") + output.write("]\n") # save persistent data self.world.persistentData['POI'] = self.world.POI From b9a21b98e00caecbf4a47158cd86c0c583973824 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Sun, 10 Apr 2011 05:57:15 -0400 Subject: [PATCH 7/8] fixed dumb boolean logic in optimizeimg check --- optimizeimages.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/optimizeimages.py b/optimizeimages.py index b3daff7..e1699b0 100644 --- a/optimizeimages.py +++ b/optimizeimages.py @@ -30,7 +30,7 @@ def check_programs(level): for prog,l in [(pngcrush,1), (optipng,2), (advdef,2)]: if l <= level: - if (not exists_in_path(prog)) or (not exists_in_path(prog + ".exe")): + if (not exists_in_path(prog)) and (not exists_in_path(prog + ".exe")): raise Exception("Optimization prog %s for level %d not found!" % (prog, l)) def optimize_image(imgpath, imgformat, optimizeimg): From dd19e88f15c701ae8af8c68285a3246de8844f5a Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Mon, 11 Apr 2011 00:15:20 +0200 Subject: [PATCH 8/8] Add special case for wooden and cobblestone stairs in textures.py. Fix a wrong comment in ladder. Add more comments in _buil_full_block. --- textures.py | 93 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 82 insertions(+), 11 deletions(-) diff --git a/textures.py b/textures.py index a94030c..e3e714c 100644 --- a/textures.py +++ b/textures.py @@ -272,10 +272,10 @@ def _build_full_block(top, side1, side2, side3, side4, bottom=None, blockID=None build a full block with four differnts faces. All images should be 16x16 image objects. Returns a 24x24 image. Can be used to render any block. - side1 is in the -y face of the cube (top left) - side2 is in the +x (top right) - side3 is in the -x (bottom left) - side4 is in the +y (bottom right) + side1 is in the -y face of the cube (top left, east) + side2 is in the +x (top right, south) + side3 is in the -x (bottom left, north) + side4 is in the +y (bottom right, west) A non transparent block uses top, side 3 and side 4 @@ -354,9 +354,9 @@ def _build_blockimages(): # 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 -1, -1, -1, -1, -1, 13, 12, 29, 28, 23, 22, -1, -1, 7, 8, 35, # Gold/iron blocks? Doublestep? TNT from above? # 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 - 36, 37, -1, -1, 65, 4, 25, -1, 98, 24, -1, -1, 86, -1, -1, -1, # Torch from above? leaving out fire. Redstone wire? Crops/furnaces handled elsewhere. sign post + 36, 37, -1, -1, 65, -1, 25, -1, 98, 24, -1, -1, 86, -1, -1, -1, # Torch from above? leaving out fire. Redstone wire? Crops/furnaces handled elsewhere. sign post # 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 - -1, -1, -1, 16, -1, -1, -1, -1, -1, 51, 51, -1, -1, -1, 66, 67, # door,ladder left out. Minecart rail orientation, redstone torches + -1, -1, -1, -1, -1, -1, -1, -1, -1, 51, 51, -1, -1, -1, 66, 67, # door,ladder left out. Minecart rail orientation, redstone torches # 80 81 82 83 84 85 86 87 88 89 90 91 66, 69, 72, 73, 74, -1,102,103,104,105,-1, 102 # clay? ] @@ -371,9 +371,9 @@ def _build_blockimages(): # 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 -1, -1, -1, -1, -1, 13, 12, 29, 28, 23, 22, -1, -1, 7, 8, 35, # 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 - 36, 37, -1, -1, 65, 4, 25,101, 98, 24, -1, -1, 86, -1, -1, -1, + 36, 37, -1, -1, 65, -1, 25,101, 98, 24, -1, -1, 86, -1, -1, -1, # 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 - -1, -1, -1, 16, -1, -1, -1, -1, -1, 51, 51, -1, -1, -1, 66, 67, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 51, 51, -1, -1, -1, 66, 67, # 80 81 82 83 84 85 86 87 88 89 90 91 66, 69, 72, 73, 74,-1 ,118,103,104,105, -1, 118 ] @@ -663,6 +663,75 @@ def generate_special_texture(blockID, data): return (img.convert("RGB"), img.split()[3]) + if blockID in (53,67): # wooden and cobblestone stairs. + + if blockID == 53: # wooden + texture = terrain_images[4] + + elif blockID == 67: # cobblestone + texture = terrain_images[16] + + side = texture.copy() + half_block_u = texture.copy() # up, down, left, right + half_block_d = texture.copy() + half_block_l = texture.copy() + half_block_r = texture.copy() + + # generate needed geometries + ImageDraw.Draw(side).rectangle((0,0,7,6),outline=(0,0,0,0),fill=(0,0,0,0)) + ImageDraw.Draw(half_block_u).rectangle((0,8,15,15),outline=(0,0,0,0),fill=(0,0,0,0)) + ImageDraw.Draw(half_block_d).rectangle((0,0,15,6),outline=(0,0,0,0),fill=(0,0,0,0)) + ImageDraw.Draw(half_block_l).rectangle((8,0,15,15),outline=(0,0,0,0),fill=(0,0,0,0)) + ImageDraw.Draw(half_block_r).rectangle((0,0,7,15),outline=(0,0,0,0),fill=(0,0,0,0)) + + if data == 0: # ascending south + img = _build_full_block(half_block_r, None, None, half_block_d, side.transpose(Image.FLIP_LEFT_RIGHT)) + tmp1 = transform_image_side(half_block_u) + + # Darken the vertical part of the second step + sidealpha = tmp1.split()[3] + # darken it a bit more than usual, looks better + tmp1 = ImageEnhance.Brightness(tmp1).enhance(0.8) + tmp1.putalpha(sidealpha) + + composite.alpha_over(img, tmp1, (6,3)) + tmp2 = transform_image(half_block_l) + composite.alpha_over(img, tmp2, (0,6)) + + elif data == 1: # ascending north + img = Image.new("RGBA", (24,24), (38,92,255,0)) # first paste the texture in the back + tmp1 = transform_image(half_block_r) + composite.alpha_over(img, tmp1, (0,6)) + tmp2 = _build_full_block(half_block_l, None, None, texture, side) + composite.alpha_over(img, tmp2) + + elif data == 2: # ascending west + img = Image.new("RGBA", (24,24), (38,92,255,0)) # first paste the texture in the back + tmp1 = transform_image(half_block_u) + composite.alpha_over(img, tmp1, (0,6)) + tmp2 = _build_full_block(half_block_d, None, None, side, texture) + composite.alpha_over(img, tmp2) + + elif data == 3: # ascending east + img = _build_full_block(half_block_u, None, None, side.transpose(Image.FLIP_LEFT_RIGHT), half_block_d) + tmp1 = transform_image_side(half_block_u).transpose(Image.FLIP_LEFT_RIGHT) + + # Darken the vertical part of the second step + sidealpha = tmp1.split()[3] + # darken it a bit more than usual, looks better + tmp1 = ImageEnhance.Brightness(tmp1).enhance(0.7) + tmp1.putalpha(sidealpha) + + composite.alpha_over(img, tmp1, (6,3)) + tmp2 = transform_image(half_block_d) + composite.alpha_over(img, tmp2, (0,6)) + + # touch up a (horrible) pixel + img.putpixel((18,3),(0,0,0,0)) + + return (img.convert("RGB"), img.split()[3]) + + if blockID == 55: # redstone wire if data & 0b1000000 == 64: # powered redstone wire @@ -1146,8 +1215,8 @@ def getBiomeData(worlddir, chunkX, chunkY): # (when adding new blocks here and in generate_special_textures, # please, if possible, keep the ascending order of blockid value) -special_blocks = set([2, 9, 17, 18, 23, 35, 43, 44, 50, 51, 55, 58, 59, \ - 61, 62, 64, 65, 66, 71, 75, 76, 85, 86, 91, 92]) +special_blocks = set([2, 9, 17, 18, 23, 35, 43, 44, 50, 51, 53, 55, 58, 59, \ + 61, 62, 64, 65, 66, 67, 71, 75, 76, 85, 86, 91, 92]) # this is a map of special blockIDs to a list of all # possible values for ancillary data that it might have. @@ -1162,14 +1231,16 @@ special_map[43] = range(4) # stone, sandstone, wooden and cobblestone double-sl special_map[44] = range(4) # stone, sandstone, wooden and cobblestone slab special_map[50] = (1,2,3,4,5) # torch, position in the block special_map[51] = range(16) # fire, position in the block (not implemented) +special_map[53] = range(4) # wooden stairs, orientation special_map[55] = range(128) # redstone wire, all the possible combinations special_map[58] = (0,) # crafting table special_map[59] = range(8) # crops, grow from 0 to 7 special_map[61] = range(6) # furnace, orientation (not implemented) special_map[62] = range(6) # burning furnace, orientation (not implemented) special_map[64] = range(16) # wooden door, open/close and orientation -special_map[65] = (2,3,4,5) # ladder, orientation (not implemented) +special_map[65] = (2,3,4,5) # ladder, orientation special_map[66] = range(10) # minecrart tracks, orientation, slope +special_map[67] = range(4) # cobblestone stairs, orientation special_map[71] = range(16) # iron door, open/close and orientation special_map[75] = (1,2,3,4,5) # off redstone torch, orientation special_map[76] = (1,2,3,4,5) # on redstone torch, orientation