From 0fdd241976a072e6e7a3004664df22afb33f5998 Mon Sep 17 00:00:00 2001 From: Mark Fickett Date: Fri, 20 Mar 2015 23:43:40 -0400 Subject: [PATCH 01/40] Add option to only load entities from chunk and use it for genPOI, resulting in roughly 1/3 runtime reduction. --- overviewer_core/aux_files/genPOI.py | 2 +- overviewer_core/world.py | 126 +++++++++++++++------------- 2 files changed, 68 insertions(+), 60 deletions(-) diff --git a/overviewer_core/aux_files/genPOI.py b/overviewer_core/aux_files/genPOI.py index abb754431..54c0941b0 100755 --- a/overviewer_core/aux_files/genPOI.py +++ b/overviewer_core/aux_files/genPOI.py @@ -161,7 +161,7 @@ def handleEntities(rset, config, config_path, filters, markers): if numbuckets == 1: for (x, z, mtime) in rset.iterate_chunks(): try: - data = rset.get_chunk(x, z) + data = rset.get_chunk(x, z, entities_only=True) for poi in itertools.chain(data['TileEntities'], data['Entities']): if poi['id'] == 'Sign': # kill me poi = signWrangler(poi) diff --git a/overviewer_core/world.py b/overviewer_core/world.py index 910362f6a..be1f762f1 100644 --- a/overviewer_core/world.py +++ b/overviewer_core/world.py @@ -312,7 +312,7 @@ def _get_regionobj(self, regionfilename): return region #@log_other_exceptions - def get_chunk(self, x, z): + def get_chunk(self, x, z, entities_only=False): """Returns a dictionary object representing the "Level" NBT Compound structure for a chunk given its x, z coordinates. The coordinates given are chunk coordinates. Raises ChunkDoesntExist exception if the given @@ -395,66 +395,21 @@ def get_chunk(self, x, z): chunk_data['Biomes'] = biomes for section in chunk_data['Sections']: + if not entities_only: + section['Blocks'] = extract_blocks(section) + try: + section['SkyLight'] = extract_skylight(section) + section['BlockLight'] = extract_blocklight(section) + except ValueError: + # Iv'e seen at least 1 case where numpy raises a ValueError + # during the reshapes. I'm not sure what's going on here, + # but let's treat this as a corrupt chunk error. + logging.warning("There was a problem reading chunk %d,%d. It might be corrupt. I am giving up and will not render this particular chunk.", x, z) - # Turn the Blocks array into a 16x16x16 numpy matrix of shorts, - # adding in the additional block array if included. - blocks = numpy.frombuffer(section['Blocks'], dtype=numpy.uint8) - # Cast up to uint16, blocks can have up to 12 bits of data - blocks = blocks.astype(numpy.uint16) - blocks = blocks.reshape((16,16,16)) - if "Add" in section: - # This section has additional bits to tack on to the blocks - # array. Add is a packed array with 4 bits per slot, so - # it needs expanding - additional = numpy.frombuffer(section['Add'], dtype=numpy.uint8) - additional = additional.astype(numpy.uint16).reshape((16,16,8)) - additional_expanded = numpy.empty((16,16,16), dtype=numpy.uint16) - additional_expanded[:,:,::2] = (additional & 0x0F) << 8 - additional_expanded[:,:,1::2] = (additional & 0xF0) << 4 - blocks += additional_expanded - del additional - del additional_expanded - del section['Add'] # Save some memory - section['Blocks'] = blocks - - # Turn the skylight array into a 16x16x16 matrix. The array comes - # packed 2 elements per byte, so we need to expand it. - try: - skylight = numpy.frombuffer(section['SkyLight'], dtype=numpy.uint8) - skylight = skylight.reshape((16,16,8)) - skylight_expanded = numpy.empty((16,16,16), dtype=numpy.uint8) - skylight_expanded[:,:,::2] = skylight & 0x0F - skylight_expanded[:,:,1::2] = (skylight & 0xF0) >> 4 - del skylight - section['SkyLight'] = skylight_expanded - - # Turn the BlockLight array into a 16x16x16 matrix, same as SkyLight - blocklight = numpy.frombuffer(section['BlockLight'], dtype=numpy.uint8) - blocklight = blocklight.reshape((16,16,8)) - blocklight_expanded = numpy.empty((16,16,16), dtype=numpy.uint8) - blocklight_expanded[:,:,::2] = blocklight & 0x0F - blocklight_expanded[:,:,1::2] = (blocklight & 0xF0) >> 4 - del blocklight - section['BlockLight'] = blocklight_expanded - - # Turn the Data array into a 16x16x16 matrix, same as SkyLight - data = numpy.frombuffer(section['Data'], dtype=numpy.uint8) - data = data.reshape((16,16,8)) - data_expanded = numpy.empty((16,16,16), dtype=numpy.uint8) - data_expanded[:,:,::2] = data & 0x0F - data_expanded[:,:,1::2] = (data & 0xF0) >> 4 - del data - section['Data'] = data_expanded - except ValueError: - # iv'e seen at least 1 case where numpy raises a value error during the reshapes. i'm not - # sure what's going on here, but let's treat this as a corrupt chunk error - logging.warning("There was a problem reading chunk %d,%d. It might be corrupt. I am giving up and will not render this particular chunk.", x, z) - - logging.debug("Full traceback:", exc_info=1) - raise nbt.CorruptChunkError() - + logging.debug("Full traceback:", exc_info=1) + raise nbt.CorruptChunkError() + section['Data'] = extract_data(section) return chunk_data - def iterate_chunks(self): """Returns an iterator over all chunk metadata in this world. Iterates @@ -538,6 +493,59 @@ def _iterate_regionfiles(self): logging.warning("Holy shit what is up with region file %s !?" % f) yield (x, y, os.path.join(self.regiondir, f)) +def extract_blocks(section): + # Turn the Blocks array into a 16x16x16 numpy matrix of shorts, + # adding in the additional block array if included. + blocks = numpy.frombuffer(section['Blocks'], dtype=numpy.uint8) + # Cast up to uint16, blocks can have up to 12 bits of data + blocks = blocks.astype(numpy.uint16) + blocks = blocks.reshape((16,16,16)) + if 'Add' in section: + # This section has additional bits to tack on to the blocks + # array. Add is a packed array with 4 bits per slot, so + # it needs expanding + additional = numpy.frombuffer(section['Add'], dtype=numpy.uint8) + additional = additional.astype(numpy.uint16).reshape((16,16,8)) + additional_expanded = numpy.empty((16,16,16), dtype=numpy.uint16) + additional_expanded[:,:,::2] = (additional & 0x0F) << 8 + additional_expanded[:,:,1::2] = (additional & 0xF0) << 4 + blocks += additional_expanded + del additional + del additional_expanded + del section['Add'] # Save some memory + return blocks + +def extract_skylight(section): + # Turn the skylight array into a 16x16x16 matrix. The array comes + # packed 2 elements per byte, so we need to expand it. + skylight = numpy.frombuffer(section['SkyLight'], dtype=numpy.uint8) + skylight = skylight.reshape((16,16,8)) + skylight_expanded = numpy.empty((16,16,16), dtype=numpy.uint8) + skylight_expanded[:,:,::2] = skylight & 0x0F + skylight_expanded[:,:,1::2] = (skylight & 0xF0) >> 4 + del skylight + return skylight_expanded + +def extract_blocklight(section): + # Turn the BlockLight array into a 16x16x16 matrix, same as SkyLight + blocklight = numpy.frombuffer(section['BlockLight'], dtype=numpy.uint8) + blocklight = blocklight.reshape((16,16,8)) + blocklight_expanded = numpy.empty((16,16,16), dtype=numpy.uint8) + blocklight_expanded[:,:,::2] = blocklight & 0x0F + blocklight_expanded[:,:,1::2] = (blocklight & 0xF0) >> 4 + del blocklight + return blocklight_expanded + +def extract_data(section): + # Turn the Data array into a 16x16x16 matrix, same as SkyLight + data = numpy.frombuffer(section['Data'], dtype=numpy.uint8) + data = data.reshape((16,16,8)) + data_expanded = numpy.empty((16,16,16), dtype=numpy.uint8) + data_expanded[:,:,::2] = data & 0x0F + data_expanded[:,:,1::2] = (data & 0xF0) >> 4 + del data + return data_expanded + class RegionSetWrapper(object): """This is the base class for all "wrappers" of RegionSet objects. A wrapper is an object that acts similarly to a subclass: some methods are From 0aef9b436c2214e4eb329082108e22ad1338a7c4 Mon Sep 17 00:00:00 2001 From: Nicolas F Date: Mon, 4 May 2015 14:59:18 +0200 Subject: [PATCH 02/40] [webassets] Updated jQuery version --- overviewer_core/data/web_assets/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/overviewer_core/data/web_assets/index.html b/overviewer_core/data/web_assets/index.html index 1408efa03..3fd28127a 100644 --- a/overviewer_core/data/web_assets/index.html +++ b/overviewer_core/data/web_assets/index.html @@ -10,7 +10,7 @@ - + From ddfd88aad7c5244c6666ddf13fba3af0981f653a Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Fri, 5 Jun 2015 22:07:02 -0400 Subject: [PATCH 03/40] Update signs.rst Added small note about how to look for the Markers button on a successful genpoi --- docs/signs.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/signs.rst b/docs/signs.rst index 36d651e71..512cf2d84 100644 --- a/docs/signs.rst +++ b/docs/signs.rst @@ -220,6 +220,9 @@ POI markers. For example:: .. note:: A --genpoi run will NOT generate a map render, it will only generate markers. +If all went well, you will see a "Markers" button in the upper-right corner of +your map. + genPOI.py --------- From d6d488c3eadf50563beb8e484e4f947651d16499 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Wed, 24 Jun 2015 11:30:31 -0400 Subject: [PATCH 04/40] Add c_overveiwer_includes to the list of source files This seems to be needed to make "sdist" include these headerfiles. i have no idea how/if this worked in the past --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 1b4b30d72..891a1a380 100755 --- a/setup.py +++ b/setup.py @@ -183,7 +183,7 @@ def recursive_package_data(src, package_dir='overviewer_core'): c_overviewer_files = map(lambda s: 'overviewer_core/src/'+s, c_overviewer_files) c_overviewer_includes = map(lambda s: 'overviewer_core/src/'+s, c_overviewer_includes) -setup_kwargs['ext_modules'].append(Extension('overviewer_core.c_overviewer', c_overviewer_files, include_dirs=['.', numpy_include] + pil_include, depends=c_overviewer_includes, extra_link_args=[])) +setup_kwargs['ext_modules'].append(Extension('overviewer_core.c_overviewer', c_overviewer_files + c_overviewer_includes, include_dirs=['.', numpy_include] + pil_include, depends=c_overviewer_includes, extra_link_args=[])) # tell build_ext to build the extension in-place From 253f78c8d1e4e3132ccf91e7b05c98454bf9147c Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Wed, 24 Jun 2015 11:41:26 -0400 Subject: [PATCH 05/40] Revert "Add c_overveiwer_includes to the list of source files" This reverts commit d6d488c3eadf50563beb8e484e4f947651d16499. Because achin is a doofus --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 891a1a380..1b4b30d72 100755 --- a/setup.py +++ b/setup.py @@ -183,7 +183,7 @@ def recursive_package_data(src, package_dir='overviewer_core'): c_overviewer_files = map(lambda s: 'overviewer_core/src/'+s, c_overviewer_files) c_overviewer_includes = map(lambda s: 'overviewer_core/src/'+s, c_overviewer_includes) -setup_kwargs['ext_modules'].append(Extension('overviewer_core.c_overviewer', c_overviewer_files + c_overviewer_includes, include_dirs=['.', numpy_include] + pil_include, depends=c_overviewer_includes, extra_link_args=[])) +setup_kwargs['ext_modules'].append(Extension('overviewer_core.c_overviewer', c_overviewer_files, include_dirs=['.', numpy_include] + pil_include, depends=c_overviewer_includes, extra_link_args=[])) # tell build_ext to build the extension in-place From dec9aada01b34c5c4223ae2e4e3a810286369bce Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Wed, 24 Jun 2015 11:42:41 -0400 Subject: [PATCH 06/40] Hopefully a better fix for the sdist problem. Removing trailing slashes from MANIFEST.in file. Why is this needed? No idea, i hate distutils --- MANIFEST.in | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/MANIFEST.in b/MANIFEST.in index 5de8dd902..3e0ff040b 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -4,10 +4,10 @@ include CONTRIBUTORS.rst include overviewer.py include contribManager.py include sample_config.py -recursive-include overviewer_core/ *.py -recursive-include overviewer_core/src/ *.c *.h -recursive-include overviewer_core/src/primitives/ *.c *.h -recursive-include overviewer_core/data/ * -recursive-include contrib/ *.py -recursive-include docs/ * +recursive-include overviewer_core *.py +recursive-include overviewer_core/src *.c *.h +recursive-include overviewer_core/src/primitives *.c *.h +recursive-include overviewer_core/data * +recursive-include contrib *.py +recursive-include docs * prune docs/_build From 788d90bbf26be75ac128073c2347aeb18eaa4a17 Mon Sep 17 00:00:00 2001 From: Franz Dietrich Date: Fri, 3 Jul 2015 15:10:54 +0200 Subject: [PATCH 07/40] Small documentation bug for StructureOverlay. When adding documentation for the StructureOverlay I missed some copy and paste error. fixes #1229 --- docs/config.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/config.rst b/docs/config.rst index b56fc8f1d..14904a45a 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -1172,13 +1172,13 @@ StructureOverlay Example:: - MineralOverlay(minerals=[(((0, 0, 0, 66), (0, -1, 0, 4)), (255, 0, 0, 255)), - (((0, 0, 0, 27), (0, -1, 0, 4)), (0, 255, 0, 255))]) + StructureOverlay(structures=[(((0, 0, 0, 66), (0, -1, 0, 4)), (255, 0, 0, 255)), + (((0, 0, 0, 27), (0, -1, 0, 4)), (0, 255, 0, 255))]) In this example all rails(66) on top of cobblestone are rendered in pure red. And all powerrails(27) are rendered in green. - If ``minerals`` is not provided, a default rail coloring is used. + If ``structures`` is not provided, a default rail coloring is used. BiomeOverlay Color the map according to the biome at that point. Either use on From afc1c4f924c807d30477b05fda73a5dcbf89f384 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Fri, 14 Aug 2015 08:47:52 -0400 Subject: [PATCH 08/40] Don't call save_cache if running with --skip-players --- overviewer_core/aux_files/genPOI.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/overviewer_core/aux_files/genPOI.py b/overviewer_core/aux_files/genPOI.py index abb754431..21a07843b 100755 --- a/overviewer_core/aux_files/genPOI.py +++ b/overviewer_core/aux_files/genPOI.py @@ -513,7 +513,8 @@ def main(): logging.info("Done handling POIs") logging.info("Writing out javascript files") - PlayerDict.save_cache(destdir) + if not options.skipplayers: + PlayerDict.save_cache(destdir) with open(os.path.join(destdir, "markersDB.js"), "w") as output: output.write("var markersDB=") From a8c71d089d2faffdbc8d615f0908ee26b5cc00cf Mon Sep 17 00:00:00 2001 From: Nicolas F Date: Sat, 15 Aug 2015 23:50:40 +0200 Subject: [PATCH 09/40] Fix mingw-w64 build On Windows with mingw-w64, Pillow includes windows.h, and thus including Imaging.h would result in a name conflict of "TRANSPARENT", which windows.h #defines but overviewer.h wants to use as enum. For the record, this used to not be broken back when I initially fixed Pillow for mingw-w64, so the change got somewhere introduced between then and now. --- overviewer_core/src/overviewer.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/overviewer_core/src/overviewer.h b/overviewer_core/src/overviewer.h index 873dcaa2b..586024595 100644 --- a/overviewer_core/src/overviewer.h +++ b/overviewer_core/src/overviewer.h @@ -32,6 +32,8 @@ #include #include #include +/* Fix Pillow on mingw-w64 which includes windows.h in Imaging.h */ +#undef TRANSPARENT /* like (a * b + 127) / 255), but much faster on most platforms from PIL's _imaging.c */ From 9ae3ac2916c247348f89862b4e588b4239a32904 Mon Sep 17 00:00:00 2001 From: Nicolas F Date: Sun, 16 Aug 2015 00:17:19 +0200 Subject: [PATCH 10/40] Add mingw-w64 build documentation --- docs/building.rst | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/docs/building.rst b/docs/building.rst index bb264e9f8..833ce08ec 100644 --- a/docs/building.rst +++ b/docs/building.rst @@ -72,6 +72,36 @@ then try the following:: If the build was successful, there should be a c_overviewer.pyd file in your current working directory. +Building with mingw-w64 and msys2 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This is the recommended way to build on Windows without MSVC. + +1. Install msys2 by following **all** the instructions on + `the msys2 installation page `_. + +2. Install the dependencies:: + + pacman -S git mingw-w64-x86_64-python2-numpy mingw-w64-x86_64-python2-Pillow mingw-w64-x86_64-python2 mingw-w64-x86_64-toolchain + +3. Clone the Minecraft-Overviewer git repository:: + + git clone https://github.com/overviewer/Minecraft-Overviewer.git + + The source code will be downloaded to your msys2 home directory, e.g. + ``C:\msys2\home\Potato\Minecraft-Overviewer`` + +4. Close the msys2 shell. Instead, open the MinGW64 shell. + +5. Build the Overviewer by changing your current working directory into the source + directory and executing the build script:: + + cd Minecraft-Overviewer + python2 setup.py build + +After it finishes, you should now be able to execute ``overviewer.py`` from the MINGW64 +shell. + Building with mingw ~~~~~~~~~~~~~~~~~~~ From 48cd0c4aa7cc0ca6c07b9b40d9883fadbe647b6f Mon Sep 17 00:00:00 2001 From: Nicolas F Date: Sun, 16 Aug 2015 00:30:52 +0200 Subject: [PATCH 11/40] Let's whack travis with a wrench for a bit --- .travis.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index f58105e8e..a3d54e8e9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,9 +5,6 @@ python: # - "3.2" env: - MC_VERSION=1.8 -before_install: - - wget http://hg.effbot.org/pil-117/raw/f356a1f64271/libImaging/Imaging.h - - wget http://hg.effbot.org/pil-117/raw/f356a1f64271/libImaging/ImPlatform.h install: - pip install -q pillow - pip install -q numpy @@ -22,7 +19,7 @@ notifications: email: false irc: channels: - - "irc.freenode.org#overviewer" + - "chat.freenode.net#overviewer" skip_join: true template: - "\x0313Minecraft-Overviewer\x03/\x0306%{branch}\x03 \x0314%{commit}\x03 %{build_url} %{message}" From b8fb7652b2ce25f0fbb4cad21942ab585b2f5f93 Mon Sep 17 00:00:00 2001 From: Nicolas F Date: Sun, 16 Aug 2015 00:37:18 +0200 Subject: [PATCH 12/40] More Travis whacking --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a3d54e8e9..67d77b3cb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,9 @@ python: # - "3.2" env: - MC_VERSION=1.8 +before_install: + - wget https://raw.githubusercontent.com/python-pillow/Pillow/master/libImaging/Imaging.h + - wget https://raw.githubusercontent.com/python-pillow/Pillow/master/libImaging/ImPlatform.h install: - pip install -q pillow - pip install -q numpy @@ -20,7 +23,6 @@ notifications: irc: channels: - "chat.freenode.net#overviewer" - skip_join: true template: - "\x0313Minecraft-Overviewer\x03/\x0306%{branch}\x03 \x0314%{commit}\x03 %{build_url} %{message}" # matrix: From 0ba0c60ed210d3f256cbd369818cbbc5a6afbc57 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Tue, 6 Oct 2015 17:38:03 -0400 Subject: [PATCH 13/40] Catch TypeErrors as well when loading player dat files --- overviewer_core/aux_files/genPOI.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/overviewer_core/aux_files/genPOI.py b/overviewer_core/aux_files/genPOI.py index 21a07843b..7fadcc463 100755 --- a/overviewer_core/aux_files/genPOI.py +++ b/overviewer_core/aux_files/genPOI.py @@ -280,7 +280,7 @@ def handlePlayers(worldpath, filters, markers): data.use_uuid = useUUIDs if isSinglePlayer: data = data['Data']['Player'] - except IOError: + except (IOError, TypeError): logging.warning("Skipping bad player dat file %r", playerfile) continue From 270741eb8f229a9b95bdb37745f8310554f7701e Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Sun, 27 Dec 2015 14:59:03 -0500 Subject: [PATCH 14/40] genpoi UUID improvements * When reading the cache, catch some errors on load, instead of crashing * When writing to cache, write to tmp file, then move it into place. This should be more robust if a ctrl+c is recieved while writing the cache Addresses #1266 --- overviewer_core/aux_files/genPOI.py | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/overviewer_core/aux_files/genPOI.py b/overviewer_core/aux_files/genPOI.py index 7fadcc463..a237ad4ba 100755 --- a/overviewer_core/aux_files/genPOI.py +++ b/overviewer_core/aux_files/genPOI.py @@ -24,6 +24,7 @@ import sys import time import urllib2 +import datetime from collections import defaultdict from multiprocessing import Pool @@ -210,9 +211,21 @@ class PlayerDict(dict): def load_cache(cls, outputdir): cache_file = os.path.join(outputdir, "uuidcache.dat") if os.path.exists(cache_file): - gz = gzip.GzipFile(cache_file) - cls.uuid_cache = json.load(gz) - logging.info("Loaded UUID cache from %r with %d entries", cache_file, len(cls.uuid_cache.keys())) + try: + gz = gzip.GzipFile(cache_file) + cls.uuid_cache = json.load(gz) + logging.info("Loaded UUID cache from %r with %d entries", cache_file, len(cls.uuid_cache.keys())) + except (ValueError, IOError): + logging.warning("Failed to load UUID cache -- it might be corrupt") + cls.uuid_cache = {} + corrupted_cache = cache_file + ".corrupted." + datetime.datetime.now().isoformat() + try: + os.rename(cache_file, corrupted_cache) + logging.warning("If %s does not appear to contain meaningful data, you may safely delete it", corrupted_cache) + except OSError: + logging.warning("Failed to backup corrupted UUID cache") + + logging.info("Initialized an empty UUID cache") else: cls.uuid_cache = {} logging.info("Initialized an empty UUID cache") @@ -220,9 +233,13 @@ def load_cache(cls, outputdir): @classmethod def save_cache(cls, outputdir): cache_file = os.path.join(outputdir, "uuidcache.dat") - gz = gzip.GzipFile(cache_file, "wb") - json.dump(cls.uuid_cache, gz) - logging.info("Wrote UUID cache with %d entries", len(cls.uuid_cache.keys())) + try: + gz = gzip.GzipFile(cache_file + ".tmp", "wb") + json.dump(cls.uuid_cache, gz) + os.rename(cache_file + ".tmp", cache_file) + logging.info("Wrote UUID cache with %d entries", len(cls.uuid_cache.keys())) + except (IOError, OSError): + logging.warning("Failed to save UUID cache!") def __getitem__(self, item): if item == "EntityId": From 68430335c83e2f6ef6f590dd516c56caea3ae2fa Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Sun, 27 Dec 2015 15:04:32 -0500 Subject: [PATCH 15/40] JSObserver: Add missing string formatting param --- overviewer_core/observer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/overviewer_core/observer.py b/overviewer_core/observer.py index e068acbd2..0e9bcd9f3 100644 --- a/overviewer_core/observer.py +++ b/overviewer_core/observer.py @@ -234,7 +234,7 @@ def __init__(self, outputdir, minrefresh=5, messages=False): else: raise Exception("JSObserver: messages parameter must be a dictionary with three entries: totalTiles, renderCompleted and renderProgress") if not os.path.exists(outputdir): - raise Exception("JSObserver: Output directory specified (%s) doesn't appear to exist. This should be the same as the Overviewer output directory") + raise Exception("JSObserver: Output directory specified (%s) doesn't appear to exist. This should be the same as the Overviewer output directory" % outputdir) self.logfile = open(os.path.join(outputdir, "progress.json"), "w+", 0) self.json["message"]="Render starting..." From 2e3450756860c793b34f2ccbee780f14edd08132 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Mon, 1 Feb 2016 09:32:35 -0500 Subject: [PATCH 16/40] Use FileReplacer to manage the uuid cache file --- overviewer_core/aux_files/genPOI.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/overviewer_core/aux_files/genPOI.py b/overviewer_core/aux_files/genPOI.py index a237ad4ba..6178e2a41 100755 --- a/overviewer_core/aux_files/genPOI.py +++ b/overviewer_core/aux_files/genPOI.py @@ -33,6 +33,7 @@ from overviewer_core import logger from overviewer_core import nbt from overviewer_core import configParser, world +from overviewer_core.files import FileReplacer UUID_LOOKUP_URL = 'https://sessionserver.mojang.com/session/minecraft/profile/' @@ -233,13 +234,11 @@ def load_cache(cls, outputdir): @classmethod def save_cache(cls, outputdir): cache_file = os.path.join(outputdir, "uuidcache.dat") - try: - gz = gzip.GzipFile(cache_file + ".tmp", "wb") + + with FileReplacer(cache_file) as cache_file_name: + gz = gzip.GzipFile(cache_file_name, "wb") json.dump(cls.uuid_cache, gz) - os.rename(cache_file + ".tmp", cache_file) logging.info("Wrote UUID cache with %d entries", len(cls.uuid_cache.keys())) - except (IOError, OSError): - logging.warning("Failed to save UUID cache!") def __getitem__(self, item): if item == "EntityId": From bd1b3d073c93c8425a15aefae8608e563b1cd798 Mon Sep 17 00:00:00 2001 From: Timothy Cyrus Date: Fri, 15 Jan 2016 16:30:49 -0500 Subject: [PATCH 17/40] Update README.rst --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index f9adc1f20..763680d79 100644 --- a/README.rst +++ b/README.rst @@ -85,4 +85,4 @@ https://github.com/overviewer/Minecraft-Overviewer/issues Feel free to comment on issues, report new issues, and vote on issues that are important to you. -.. |Build Status| image:: https://secure.travis-ci.org/overviewer/Minecraft-Overviewer.png?branch=master +.. |Build Status| image:: https://secure.travis-ci.org/overviewer/Minecraft-Overviewer.svg?branch=master From c7f8cfee8cdeb5c6bc1e02705e092259550cb27d Mon Sep 17 00:00:00 2001 From: Nicolas F Date: Sat, 30 Jan 2016 13:58:36 +0100 Subject: [PATCH 18/40] rcon: Wait for buffer to fill We should wait for the buffer to fill up to 12 bytes instead of simply assuming it will. Possible fix for #1273. --- overviewer_core/rcon.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/overviewer_core/rcon.py b/overviewer_core/rcon.py index 52a14348f..cffe5460c 100644 --- a/overviewer_core/rcon.py +++ b/overviewer_core/rcon.py @@ -68,7 +68,8 @@ def send(self, t, payload): if not toread: raise RConException(self.rid, "Request timed out.") - res_len, res_id, res_type = struct.unpack(" Date: Sat, 30 Jan 2016 14:17:16 +0100 Subject: [PATCH 19/40] genPOI: Use "with" statement to close gzip files Previously, the files were not closed after reading or writing; by using a "with" statement, the file handles will be closed as soon as they go out of scope. Possible fix for #1271. --- overviewer_core/aux_files/genPOI.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/overviewer_core/aux_files/genPOI.py b/overviewer_core/aux_files/genPOI.py index 6178e2a41..20a6fd57e 100755 --- a/overviewer_core/aux_files/genPOI.py +++ b/overviewer_core/aux_files/genPOI.py @@ -213,9 +213,10 @@ def load_cache(cls, outputdir): cache_file = os.path.join(outputdir, "uuidcache.dat") if os.path.exists(cache_file): try: - gz = gzip.GzipFile(cache_file) - cls.uuid_cache = json.load(gz) - logging.info("Loaded UUID cache from %r with %d entries", cache_file, len(cls.uuid_cache.keys())) + with gzip.GzipFile(cache_file) as gz: + cls.uuid_cache = json.load(gz) + logging.info("Loaded UUID cache from %r with %d entries", + cache_file, len(cls.uuid_cache.keys())) except (ValueError, IOError): logging.warning("Failed to load UUID cache -- it might be corrupt") cls.uuid_cache = {} @@ -236,9 +237,10 @@ def save_cache(cls, outputdir): cache_file = os.path.join(outputdir, "uuidcache.dat") with FileReplacer(cache_file) as cache_file_name: - gz = gzip.GzipFile(cache_file_name, "wb") - json.dump(cls.uuid_cache, gz) - logging.info("Wrote UUID cache with %d entries", len(cls.uuid_cache.keys())) + with gzip.GzipFile(cache_file_name, "wb") as gz: + json.dump(cls.uuid_cache, gz) + logging.info("Wrote UUID cache with %d entries", + len(cls.uuid_cache.keys())) def __getitem__(self, item): if item == "EntityId": From 8f08b3b69f1c2d050992503ca488f2f257d45833 Mon Sep 17 00:00:00 2001 From: Nicolas F Date: Sat, 30 Jan 2016 15:25:45 +0100 Subject: [PATCH 20/40] rcon: Throw more helpful exception if proto error Addresses #1273. --- overviewer_core/rcon.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/overviewer_core/rcon.py b/overviewer_core/rcon.py index cffe5460c..d815b8e66 100644 --- a/overviewer_core/rcon.py +++ b/overviewer_core/rcon.py @@ -68,8 +68,13 @@ def send(self, t, payload): if not toread: raise RConException(self.rid, "Request timed out.") - res_len, res_id, res_type = \ - struct.unpack(" Date: Sat, 13 Feb 2016 14:41:09 +0100 Subject: [PATCH 21/40] genpoi: Fix GzipFile closing on python 2.6 Fixes #1275 --- overviewer_core/aux_files/genPOI.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/overviewer_core/aux_files/genPOI.py b/overviewer_core/aux_files/genPOI.py index 20a6fd57e..06fdd6961 100755 --- a/overviewer_core/aux_files/genPOI.py +++ b/overviewer_core/aux_files/genPOI.py @@ -27,6 +27,7 @@ import datetime from collections import defaultdict +from contextlib import closing from multiprocessing import Pool from optparse import OptionParser @@ -213,7 +214,7 @@ def load_cache(cls, outputdir): cache_file = os.path.join(outputdir, "uuidcache.dat") if os.path.exists(cache_file): try: - with gzip.GzipFile(cache_file) as gz: + with closing(gzip.GzipFile(cache_file)) as gz: cls.uuid_cache = json.load(gz) logging.info("Loaded UUID cache from %r with %d entries", cache_file, len(cls.uuid_cache.keys())) @@ -237,7 +238,7 @@ def save_cache(cls, outputdir): cache_file = os.path.join(outputdir, "uuidcache.dat") with FileReplacer(cache_file) as cache_file_name: - with gzip.GzipFile(cache_file_name, "wb") as gz: + with closing(gzip.GzipFile(cache_file_name, "wb")) as gz: json.dump(cls.uuid_cache, gz) logging.info("Wrote UUID cache with %d entries", len(cls.uuid_cache.keys())) From 3d3ef0c82e88ef610a3f065af593309f0155aa53 Mon Sep 17 00:00:00 2001 From: Stefan Floeren Date: Sat, 13 Feb 2016 15:46:04 +0100 Subject: [PATCH 22/40] Remove inline for estimate_blocklevel Inlining the function allows the compiler to optimize away the function completely. Clang 3.7.1 does exactly that. This leads to an error, if the library is used with python: % ./overviewer.py Traceback (most recent call last): File "/tmp/minecraft/Minecraft-Overviewer/overviewer_core/__init__.py", line 20, in check_c_overviewer import c_overviewer ImportError: /tmp/minecraft/Minecraft-Overviewer/overviewer_core/c_overviewer.so: undefined symbol: estimate_blocklevel Something has gone wrong importing the c_overviewer extension. Please make sure it is up-to-date (clean and rebuild) --- overviewer_core/src/primitives/lighting.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/overviewer_core/src/primitives/lighting.c b/overviewer_core/src/primitives/lighting.c index 199b79aa9..f7c1164f8 100644 --- a/overviewer_core/src/primitives/lighting.c +++ b/overviewer_core/src/primitives/lighting.c @@ -95,7 +95,7 @@ calculate_light_color_fancy_night(void *data, * may (and probably should) pass NULL. */ -inline unsigned char +unsigned char estimate_blocklevel(RenderPrimitiveLighting *self, RenderState *state, int x, int y, int z, int *authoratative) { From 68955c7b93f3d62522ca36c00535728e01a51aca Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Tue, 1 Mar 2016 20:46:02 -0500 Subject: [PATCH 23/40] Fix redstone dust for Minecraft 1.9 This breaks compatibily with Minecraft 1.8 See #1280 --- overviewer_core/textures.py | 44 ++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/overviewer_core/textures.py b/overviewer_core/textures.py index 144d762e3..99e4fad81 100644 --- a/overviewer_core/textures.py +++ b/overviewer_core/textures.py @@ -2063,18 +2063,18 @@ def chests(self, blockid, data): def wire(self, blockid, data): if data & 0b1000000 == 64: # powered redstone wire - redstone_wire_t = self.load_image_texture("assets/minecraft/textures/blocks/redstone_dust_line.png") + redstone_wire_t = self.load_image_texture("assets/minecraft/textures/blocks/redstone_dust_line0.png").rotate(90) redstone_wire_t = self.tint_texture(redstone_wire_t,(255,0,0)) - redstone_cross_t = self.load_image_texture("assets/minecraft/textures/blocks/redstone_dust_cross.png") + redstone_cross_t = self.load_image_texture("assets/minecraft/textures/blocks/redstone_dust_dot.png") redstone_cross_t = self.tint_texture(redstone_cross_t,(255,0,0)) else: # unpowered redstone wire - redstone_wire_t = self.load_image_texture("assets/minecraft/textures/blocks/redstone_dust_line.png") + redstone_wire_t = self.load_image_texture("assets/minecraft/textures/blocks/redstone_dust_line0.png").rotate(90) redstone_wire_t = self.tint_texture(redstone_wire_t,(48,0,0)) - redstone_cross_t = self.load_image_texture("assets/minecraft/textures/blocks/redstone_dust_cross.png") + redstone_cross_t = self.load_image_texture("assets/minecraft/textures/blocks/redstone_dust_dot.png") redstone_cross_t = self.tint_texture(redstone_cross_t,(48,0,0)) # generate an image per redstone direction @@ -2101,26 +2101,24 @@ def wire(self, blockid, data): # generate the bottom texture if data & 0b111111 == 0: bottom = redstone_cross_t.copy() - - elif data & 0b1111 == 10: #= 0b1010 redstone wire in the x direction - bottom = redstone_wire_t.copy() - - elif data & 0b1111 == 5: #= 0b0101 redstone wire in the y direction - bottom = redstone_wire_t.copy().rotate(90) - + + # see iterate.c for where these masks come from + has_x = (data & 0b1010) > 0 + has_z = (data & 0b0101) > 0 + if has_x and has_z: + bottom = redstone_cross_t.copy() + if has_x: + alpha_over(bottom, redstone_wire_t.copy()) + if has_z: + alpha_over(bottom, redstone_wire_t.copy().rotate(90)) + else: - bottom = Image.new("RGBA", (16,16), self.bgcolor) - if (data & 0b0001) == 1: - alpha_over(bottom,branch_top_left) - - if (data & 0b1000) == 8: - alpha_over(bottom,branch_top_right) - - if (data & 0b0010) == 2: - alpha_over(bottom,branch_bottom_left) - - if (data & 0b0100) == 4: - alpha_over(bottom,branch_bottom_right) + if has_x: + bottom = redstone_wire_t.copy() + elif has_z: + bottom = redstone_wire_t.copy().rotate(90) + elif data & 0b1111 == 0: + bottom = redstone_cross_t.copy() # check for going up redstone wire if data & 0b100000 == 32: From 8d3d8dc0ee16247b8bb881aa767215051556e9ad Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Tue, 1 Mar 2016 20:47:22 -0500 Subject: [PATCH 24/40] Fix command block for Minecraft 1.9 See #1280 --- overviewer_core/textures.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/overviewer_core/textures.py b/overviewer_core/textures.py index 99e4fad81..ed8b19a91 100644 --- a/overviewer_core/textures.py +++ b/overviewer_core/textures.py @@ -3998,7 +3998,12 @@ def cocoa_plant(self, blockid, data): return img # command block -block(blockid=137, top_image="assets/minecraft/textures/blocks/command_block.png") +@material(blockid=137, solid=True, nodata=True) +def command_block(self, blockid, data): + front = self.load_image_texture("assets/minecraft/textures/blocks/command_block_front.png") + side = self.load_image_texture("assets/minecraft/textures/blocks/command_block_side.png") + back = self.load_image_texture("assets/minecraft/textures/blocks/command_block_back.png") + return self.build_full_block(side, side, back, front, side) # beacon block # at the moment of writing this, it seems the beacon block doens't use From bc9a09795706b2e4c7d7cbb77113540d741d2389 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Tue, 1 Mar 2016 21:25:15 -0500 Subject: [PATCH 25/40] Add some new blocks for Minecraft 1.9 * Purpur blocks, pillars, stairs, and slabs * End brick --- overviewer_core/src/iterate.c | 1 + overviewer_core/src/primitives/lighting.c | 8 +++++--- overviewer_core/textures.py | 20 +++++++++++++++++--- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/overviewer_core/src/iterate.c b/overviewer_core/src/iterate.c index 8a2e3249c..89150648b 100644 --- a/overviewer_core/src/iterate.c +++ b/overviewer_core/src/iterate.c @@ -263,6 +263,7 @@ is_stairs(int block) { case 163: /* acacia wood stairs */ case 164: /* dark wood stairs */ case 180: /* red sandstone stairs */ + case 203: /* purpur stairs */ return 1; } return 0; diff --git a/overviewer_core/src/primitives/lighting.c b/overviewer_core/src/primitives/lighting.c index f7c1164f8..1fd818b7f 100644 --- a/overviewer_core/src/primitives/lighting.c +++ b/overviewer_core/src/primitives/lighting.c @@ -138,7 +138,7 @@ estimate_blocklevel(RenderPrimitiveLighting *self, RenderState *state, blocklevel = get_data(state, BLOCKLIGHT, x, y, z); /* no longer a guess */ - if (!(block == 44 || block == 53 || block == 67 || block == 108 || block == 109 || block == 180 || block == 182) && authoratative) { + if (!(block == 44 || block == 53 || block == 67 || block == 108 || block == 109 || block == 180 || block == 182 || block == 205) && authoratative) { *authoratative = 1; } @@ -160,7 +160,8 @@ get_lighting_color(RenderPrimitiveLighting *self, RenderState *state, /* special half-step handling, stairs handling */ /* Anvil also needs to be here, blockid 145 */ if (block == 44 || block == 53 || block == 67 || block == 108 || block == 109 || block == 114 || - block == 128 || block == 134 || block == 135 || block == 136 || block == 145 || block == 156 || block == 163 || block == 164 || block == 180 || block == 182) { + block == 128 || block == 134 || block == 135 || block == 136 || block == 145 || block == 156 || + block == 163 || block == 164 || block == 180 || block == 182 || block == 203 || block == 205) { unsigned int upper_block; /* stairs and half-blocks take the skylevel from the upper block if it's transparent */ @@ -171,7 +172,8 @@ get_lighting_color(RenderPrimitiveLighting *self, RenderState *state, upper_block = get_data(state, BLOCKS, x, y + upper_counter, z); } while (upper_block == 44 || upper_block == 53 || upper_block == 67 || upper_block == 108 || upper_block == 109 || upper_block == 114 || upper_block == 128 || upper_block == 134 || - upper_block == 135 || upper_block == 136 || upper_block == 156 || upper_block == 163 || upper_block == 164 || upper_block == 180 || upper_block == 182); + upper_block == 135 || upper_block == 136 || upper_block == 156 || upper_block == 163 || + upper_block == 164 || upper_block == 180 || upper_block == 182 || upper_block == 203 || upper_block == 205); if (is_transparent(upper_block)) { skylevel = get_data(state, SKYLIGHT, x, y + upper_counter, z); } else { diff --git a/overviewer_core/textures.py b/overviewer_core/textures.py index ed8b19a91..58c4b78bb 100644 --- a/overviewer_core/textures.py +++ b/overviewer_core/textures.py @@ -1557,7 +1557,7 @@ def flower(self, blockid, data): # double slabs and slabs # these wooden slabs are unobtainable without cheating, they are still # here because lots of pre-1.3 worlds use this blocks -@material(blockid=[43, 44, 181, 182], data=range(16), transparent=(44,182,), solid=True) +@material(blockid=[43, 44, 181, 182, 204, 205], data=range(16), transparent=(44,182,205), solid=True) def slabs(self, blockid, data): if blockid == 44 or blockid == 182: texture = data & 7 @@ -1605,8 +1605,11 @@ def slabs(self, blockid, data): top = side = self.load_image_texture("assets/minecraft/textures/blocks/red_sandstone_top.png"); else: return None + elif blockid == 204 or blockid == 205: # purpur slab (single=205 double=204) + top = side = self.load_image_texture("assets/minecraft/textures/blocks/purpur_block.png"); + - if blockid == 43 or blockid == 181: # double slab + if blockid == 43 or blockid == 181 or blockid == 204: # double slab return self.build_block(top, side) # cut the side texture in half @@ -1740,7 +1743,7 @@ def fire(self, blockid, data): block(blockid=52, top_image="assets/minecraft/textures/blocks/mob_spawner.png", transparent=True) # wooden, cobblestone, red brick, stone brick, netherbrick, sandstone, spruce, birch, jungle, quartz, and red sandstone stairs. -@material(blockid=[53,67,108,109,114,128,134,135,136,156,163,164,180], data=range(128), transparent=True, solid=True, nospawn=True) +@material(blockid=[53,67,108,109,114,128,134,135,136,156,163,164,180,203], data=range(128), transparent=True, solid=True, nospawn=True) def stairs(self, blockid, data): # preserve the upside-down bit upside_down = data & 0x4 @@ -1779,6 +1782,8 @@ def stairs(self, blockid, data): texture = self.load_image_texture("assets/minecraft/textures/blocks/planks_big_oak.png").copy() elif blockid == 180: # red sandstone stairs texture = self.load_image_texture("assets/minecraft/textures/blocks/red_sandstone_normal.png").copy() + elif blockid == 203: # purpur stairs + texture = self.load_image_texture("assets/minecraft/textures/blocks/purpur_block.png").copy() outside_l = texture.copy() outside_r = texture.copy() @@ -4408,3 +4413,12 @@ def flower(self, blockid, data): alpha_over(img, bloom_tex.resize((14, 11), Image.ANTIALIAS), (5,5)) return img + +# purpur block +block(blockid=201, top_image="assets/minecraft/textures/blocks/purpur_block.png") + +# purpur pilar +block(blockid=202, top_image="assets/minecraft/textures/blocks/purpur_pillar_top.png", side_image="assets/minecraft/textures/blocks/purpur_pillar.png") + +# end brick +block(blockid=206, top_image="assets/minecraft/textures/blocks/end_bricks.png") From 81be4bc6e85f2623b6e74412e29cfdd6238636af Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Tue, 1 Mar 2016 21:29:51 -0500 Subject: [PATCH 26/40] Bump mc version in travis and textures.py error msg. also force rebuild --- .travis.yml | 2 +- overviewer_core/src/overviewer.h | 2 +- overviewer_core/textures.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 67d77b3cb..7f3df8746 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ python: - "2.7" # - "3.2" env: - - MC_VERSION=1.8 + - MC_VERSION=1.9 before_install: - wget https://raw.githubusercontent.com/python-pillow/Pillow/master/libImaging/Imaging.h - wget https://raw.githubusercontent.com/python-pillow/Pillow/master/libImaging/ImPlatform.h diff --git a/overviewer_core/src/overviewer.h b/overviewer_core/src/overviewer.h index 586024595..d73f50a9a 100644 --- a/overviewer_core/src/overviewer.h +++ b/overviewer_core/src/overviewer.h @@ -26,7 +26,7 @@ // increment this value if you've made a change to the c extesion // and want to force users to rebuild -#define OVERVIEWER_EXTENSION_VERSION 49 +#define OVERVIEWER_EXTENSION_VERSION 50 /* Python PIL, and numpy headers */ #include diff --git a/overviewer_core/textures.py b/overviewer_core/textures.py index 58c4b78bb..a20511abc 100644 --- a/overviewer_core/textures.py +++ b/overviewer_core/textures.py @@ -310,7 +310,7 @@ def search_dir(base): if verbose: logging.info("Found %s in '%s'", filename, path) return open(path, mode) - raise TextureException("Could not find the textures while searching for '{0}'. Try specifying the 'texturepath' option in your config file.\nSet it to the path to a Minecraft Resource pack.\nAlternately, install the Minecraft client (which includes textures)\nAlso see \n(Remember, this version of Overviewer requires a 1.8-compatible resource pack)\n(Also note that I won't automatically use snapshots; you'll have to use the texturepath option to use a snapshot jar)".format(filename)) + raise TextureException("Could not find the textures while searching for '{0}'. Try specifying the 'texturepath' option in your config file.\nSet it to the path to a Minecraft Resource pack.\nAlternately, install the Minecraft client (which includes textures)\nAlso see \n(Remember, this version of Overviewer requires a 1.9-compatible resource pack)\n(Also note that I won't automatically use snapshots; you'll have to use the texturepath option to use a snapshot jar)".format(filename)) def load_image_texture(self, filename): # Textures may be animated or in a different resolution than 16x16. From 5f9276a24a8d64efe4b91cf29c565b4541a0cdf0 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Thu, 3 Mar 2016 21:22:09 -0500 Subject: [PATCH 27/40] Implement path blocks Farmland now shares a bit of code with pathblocks and are rendered at a 15/16th sized block --- overviewer_core/textures.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/overviewer_core/textures.py b/overviewer_core/textures.py index a20511abc..01b78d910 100644 --- a/overviewer_core/textures.py +++ b/overviewer_core/textures.py @@ -2170,13 +2170,25 @@ def crops(self, blockid, data): alpha_over(img, crop3, (6,3), crop3) return img -# farmland -@material(blockid=60, data=range(9), solid=True) +# farmland and grass path (15/16 blocks) +@material(blockid=[60,208], data=range(9), solid=True) def farmland(self, blockid, data): - top = self.load_image_texture("assets/minecraft/textures/blocks/farmland_wet.png") - if data == 0: - top = self.load_image_texture("assets/minecraft/textures/blocks/farmland_dry.png") - return self.build_block(top, self.load_image_texture("assets/minecraft/textures/blocks/dirt.png")) + if blockid == 60: + side = self.load_image_texture("assets/minecraft/textures/blocks/dirt.png") + top = self.load_image_texture("assets/minecraft/textures/blocks/farmland_wet.png") + if data == 0: + top = self.load_image_texture("assets/minecraft/textures/blocks/farmland_dry.png") + # dirt.png is 16 pixels tall, so we need to crop it before building full block + side = side.crop((0, 1, 16, 16)) + return self.build_full_block((top, 1), side, side, side, side) + + else: + top = self.load_image_texture("assets/minecraft/textures/blocks/grass_path_top.png") + side = self.load_image_texture("assets/minecraft/textures/blocks/grass_path_side.png") + # side already has 1 transparent pixel at the top, so it doesn't need to be modified + # just shift the top image down 1 pixel + return self.build_full_block((top, 1), side, side, side, side) + # signposts @material(blockid=63, data=range(16), transparent=True) From e4e2bae99e74fd815cf08f8f182bd17600c7eca4 Mon Sep 17 00:00:00 2001 From: lother Date: Fri, 4 Mar 2016 23:29:25 +0800 Subject: [PATCH 28/40] add end_gateway --- overviewer_core/textures.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/overviewer_core/textures.py b/overviewer_core/textures.py index 01b78d910..f174c02bb 100644 --- a/overviewer_core/textures.py +++ b/overviewer_core/textures.py @@ -3787,8 +3787,8 @@ def cauldron(self, blockid, data): return img -# end portal -@material(blockid=119, transparent=True, nodata=True) +# end portal and end_gateway +@material(blockid=[119,209], transparent=True, nodata=True) def end_portal(self, blockid, data): img = Image.new("RGBA", (24,24), self.bgcolor) # generate a black texure with white, blue and grey dots resembling stars @@ -3798,7 +3798,9 @@ def end_portal(self, blockid, data): x = randint(0,15) y = randint(0,15) t.putpixel((x,y),color) - + if blockid == 209: # end_gateway + return self.build_block(t, t) + t = self.transform_image_top(t) alpha_over(img, t, (0,0), t) From 75a3ee5650cddcb2bd5d5d2b73a62ca426d2a6b2 Mon Sep 17 00:00:00 2001 From: lother Date: Fri, 4 Mar 2016 23:30:25 +0800 Subject: [PATCH 29/40] fix command block --- overviewer_core/textures.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/overviewer_core/textures.py b/overviewer_core/textures.py index f174c02bb..9d2993729 100644 --- a/overviewer_core/textures.py +++ b/overviewer_core/textures.py @@ -4017,11 +4017,20 @@ def cocoa_plant(self, blockid, data): return img # command block -@material(blockid=137, solid=True, nodata=True) +@material(blockid=[137,210,211], solid=True, nodata=True) def command_block(self, blockid, data): - front = self.load_image_texture("assets/minecraft/textures/blocks/command_block_front.png") - side = self.load_image_texture("assets/minecraft/textures/blocks/command_block_side.png") - back = self.load_image_texture("assets/minecraft/textures/blocks/command_block_back.png") + if blockid == 210: + front = self.load_image_texture("assets/minecraft/textures/blocks/repeating_command_block_front.png") + side = self.load_image_texture("assets/minecraft/textures/blocks/repeating_command_block_side.png") + back = self.load_image_texture("assets/minecraft/textures/blocks/repeating_command_block_back.png") + elif blockid == 211: + front = self.load_image_texture("assets/minecraft/textures/blocks/chain_command_block_front.png") + side = self.load_image_texture("assets/minecraft/textures/blocks/chain_command_block_side.png") + back = self.load_image_texture("assets/minecraft/textures/blocks/chain_command_block_back.png") + else: + front = self.load_image_texture("assets/minecraft/textures/blocks/command_block_front.png") + side = self.load_image_texture("assets/minecraft/textures/blocks/command_block_side.png") + back = self.load_image_texture("assets/minecraft/textures/blocks/command_block_back.png") return self.build_full_block(side, side, back, front, side) # beacon block From 0f33b65a858ee4356e7c137f9cf26451e87adc7f Mon Sep 17 00:00:00 2001 From: lother Date: Fri, 4 Mar 2016 23:30:51 +0800 Subject: [PATCH 30/40] add beetroot --- overviewer_core/textures.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/overviewer_core/textures.py b/overviewer_core/textures.py index 9d2993729..aef8ece8b 100644 --- a/overviewer_core/textures.py +++ b/overviewer_core/textures.py @@ -4185,8 +4185,8 @@ def cobblestone_wall(self, blockid, data): return img -# carrots and potatoes -@material(blockid=[141,142], data=range(8), transparent=True, nospawn=True) +# carrots, potatoes, and beetroot +@material(blockid=[141,142,207], data=range(8), transparent=True, nospawn=True) def crops(self, blockid, data): if data != 7: # when growing they look the same # data = 7 -> fully grown, everything else is growing @@ -4194,6 +4194,8 @@ def crops(self, blockid, data): raw_crop = self.load_image_texture("assets/minecraft/textures/blocks/potatoes_stage_%d.png" % (data % 3)) elif blockid == 141: # carrots raw_crop = self.load_image_texture("assets/minecraft/textures/blocks/carrots_stage_3.png") + elif blockid == 207: # beetroot + raw_crop = self.load_image_texture("assets/minecraft/textures/blocks/beetroots_stage_3.png") else: # potatoes raw_crop = self.load_image_texture("assets/minecraft/textures/blocks/potatoes_stage_3.png") crop1 = self.transform_image_top(raw_crop) From 1ba8342ca1d61248fab4ec0efe87aefe3495ad1f Mon Sep 17 00:00:00 2001 From: lother Date: Fri, 4 Mar 2016 23:31:45 +0800 Subject: [PATCH 31/40] fix purpur pilar orientation --- overviewer_core/textures.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/overviewer_core/textures.py b/overviewer_core/textures.py index aef8ece8b..7b777521d 100644 --- a/overviewer_core/textures.py +++ b/overviewer_core/textures.py @@ -4443,7 +4443,17 @@ def flower(self, blockid, data): block(blockid=201, top_image="assets/minecraft/textures/blocks/purpur_block.png") # purpur pilar -block(blockid=202, top_image="assets/minecraft/textures/blocks/purpur_pillar_top.png", side_image="assets/minecraft/textures/blocks/purpur_pillar.png") +@material(blockid=202, data=range(12) , solid=True) +def purpur_pillar(self, blockid, data): + pillar_orientation = data & 12 + top=self.load_image_texture("assets/minecraft/textures/blocks/purpur_pillar_top.png") + side=self.load_image_texture("assets/minecraft/textures/blocks/purpur_pillar.png") + if pillar_orientation == 0: # east-west orientation + return self.build_block(top, side) + elif pillar_orientation == 4: # east-west orientation + return self.build_full_block(side.rotate(90), None, None, top, side.rotate(90)) + elif pillar_orientation == 8: # north-south orientation + return self.build_full_block(side, None, None, side.rotate(270), top) # end brick block(blockid=206, top_image="assets/minecraft/textures/blocks/end_bricks.png") From 404ef9f0ad07e6dac54e6aa4853bb4d7e87cbc27 Mon Sep 17 00:00:00 2001 From: lother Date: Fri, 4 Mar 2016 23:32:07 +0800 Subject: [PATCH 32/40] add frosted ice, structure_block --- overviewer_core/textures.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/overviewer_core/textures.py b/overviewer_core/textures.py index 7b777521d..4c16dd001 100644 --- a/overviewer_core/textures.py +++ b/overviewer_core/textures.py @@ -4457,3 +4457,22 @@ def purpur_pillar(self, blockid, data): # end brick block(blockid=206, top_image="assets/minecraft/textures/blocks/end_bricks.png") + +# frosted ice +@material(blockid=212, data=range(4), solid=True) +def frosted_ice(self, blockid, data): + img = self.load_image_texture("assets/minecraft/textures/blocks/frosted_ice_%d.png" % data) + return self.build_block(img, img) + +# structure_block +@material(blockid=255, data=range(4), solid=True) +def structure block(self, blockid, data): + if data == 0: + img = self.load_image_texture("assets/minecraft/textures/blocks/structure_block_save.png") + elif data == 1: + img = self.load_image_texture("assets/minecraft/textures/blocks/structure_block_load.png") + elif data == 2: + img = self.load_image_texture("assets/minecraft/textures/blocks/structure_block_corner.png") + elif data == 3: + img = self.load_image_texture("assets/minecraft/textures/blocks/structure_block_data.png") + return self.build_block(img, img) From 2c5971b5d80f46bf6ee49a3ec05a9679ec5945ad Mon Sep 17 00:00:00 2001 From: lother Date: Fri, 4 Mar 2016 23:48:30 +0800 Subject: [PATCH 33/40] fix typo --- overviewer_core/textures.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/overviewer_core/textures.py b/overviewer_core/textures.py index 4c16dd001..76e8a1b40 100644 --- a/overviewer_core/textures.py +++ b/overviewer_core/textures.py @@ -4464,9 +4464,9 @@ def frosted_ice(self, blockid, data): img = self.load_image_texture("assets/minecraft/textures/blocks/frosted_ice_%d.png" % data) return self.build_block(img, img) -# structure_block +# structure block @material(blockid=255, data=range(4), solid=True) -def structure block(self, blockid, data): +def structure_block(self, blockid, data): if data == 0: img = self.load_image_texture("assets/minecraft/textures/blocks/structure_block_save.png") elif data == 1: From 210f2b4a4fb9e8c7c9b2bfaeb1d51566fd8491ad Mon Sep 17 00:00:00 2001 From: Socolin Date: Sat, 5 Mar 2016 18:09:40 -0500 Subject: [PATCH 34/40] Add some missing pixel between blocks (Issue #992) Just copy/paste this piece of code from `build_block` to `build_full_block` --- overviewer_core/textures.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/overviewer_core/textures.py b/overviewer_core/textures.py index 01b78d910..b355dd13d 100644 --- a/overviewer_core/textures.py +++ b/overviewer_core/textures.py @@ -706,6 +706,15 @@ def build_full_block(self, top, side1, side2, side3, side4, bottom=None): top = self.transform_image_top(top) alpha_over(img, top, (0, increment), top) + # Manually touch up 6 pixels that leave a gap because of how the + # shearing works out. This makes the blocks perfectly tessellate-able + for x,y in [(13,23), (17,21), (21,19)]: + # Copy a pixel to x,y from x-1,y + img.putpixel((x,y), img.getpixel((x-1,y))) + for x,y in [(3,4), (7,2), (11,0)]: + # Copy a pixel to x,y from x+1,y + img.putpixel((x,y), img.getpixel((x+1,y))) + return img def build_sprite(self, side): From db3c79a46e86be25c5d13127f9e22c1a5638808f Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Sun, 6 Mar 2016 00:00:23 -0500 Subject: [PATCH 35/40] Tweak crop rendering Remote beetroot in preperation of bringing in patch --- overviewer_core/textures.py | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/overviewer_core/textures.py b/overviewer_core/textures.py index 76e8a1b40..4840ae9b3 100644 --- a/overviewer_core/textures.py +++ b/overviewer_core/textures.py @@ -2156,9 +2156,9 @@ def crafting_table(self, blockid, data): img = self.build_full_block(top, None, None, side3, side4, None) return img -# crops +# crops with 8 data values (like wheat) @material(blockid=59, data=range(8), transparent=True, nospawn=True) -def crops(self, blockid, data): +def crops8(self, blockid, data): raw_crop = self.load_image_texture("assets/minecraft/textures/blocks/wheat_stage_%d.png" % data) crop1 = self.transform_image_top(raw_crop) crop2 = self.transform_image_side(raw_crop) @@ -4185,19 +4185,22 @@ def cobblestone_wall(self, blockid, data): return img -# carrots, potatoes, and beetroot +# carrots, potatoes @material(blockid=[141,142,207], data=range(8), transparent=True, nospawn=True) -def crops(self, blockid, data): - if data != 7: # when growing they look the same - # data = 7 -> fully grown, everything else is growing - # this seems to work, but still not sure - raw_crop = self.load_image_texture("assets/minecraft/textures/blocks/potatoes_stage_%d.png" % (data % 3)) - elif blockid == 141: # carrots - raw_crop = self.load_image_texture("assets/minecraft/textures/blocks/carrots_stage_3.png") - elif blockid == 207: # beetroot - raw_crop = self.load_image_texture("assets/minecraft/textures/blocks/beetroots_stage_3.png") +def crops4(self, blockid, data): + # carrots and potatoes have 8 data, but only 4 visual stages + stage = {0:0, + 1:0, + 2:1, + 3:1, + 4:2, + 5:2, + 6:2, + 7:3}[data] + if blockid == 141: # carrots + raw_crop = self.load_image_texture("assets/minecraft/textures/blocks/carrots_stage_%d.png" % stage) else: # potatoes - raw_crop = self.load_image_texture("assets/minecraft/textures/blocks/potatoes_stage_3.png") + raw_crop = self.load_image_texture("assets/minecraft/textures/blocks/potatoes_stage_%d.png" % stage) crop1 = self.transform_image_top(raw_crop) crop2 = self.transform_image_side(raw_crop) crop3 = crop2.transpose(Image.FLIP_LEFT_RIGHT) From 9879bc96240de6e101e77c19ffe990166728294d Mon Sep 17 00:00:00 2001 From: tazo Date: Sat, 5 Mar 2016 12:38:06 +0100 Subject: [PATCH 36/40] Implement beetroot crops Conflicts: overviewer_core/textures.py --- overviewer_core/textures.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/overviewer_core/textures.py b/overviewer_core/textures.py index 4840ae9b3..4f0791850 100644 --- a/overviewer_core/textures.py +++ b/overviewer_core/textures.py @@ -4479,3 +4479,17 @@ def structure_block(self, blockid, data): elif data == 3: img = self.load_image_texture("assets/minecraft/textures/blocks/structure_block_data.png") return self.build_block(img, img) + +# beetroots +@material(blockid=[207], data=range(4), transparent=True, nospawn=True) +def crops(self, blockid, data): + raw_crop = self.load_image_texture("assets/minecraft/textures/blocks/beetroots_stage_%d.png" % data) + crop1 = self.transform_image_top(raw_crop) + crop2 = self.transform_image_side(raw_crop) + crop3 = crop2.transpose(Image.FLIP_LEFT_RIGHT) + + img = Image.new("RGBA", (24,24), self.bgcolor) + alpha_over(img, crop1, (0,12), crop1) + alpha_over(img, crop2, (6,3), crop2) + alpha_over(img, crop3, (6,3), crop3) + return img From a32582013f148798bfe32bbf4f8c617559c3e792 Mon Sep 17 00:00:00 2001 From: tazo Date: Sun, 6 Mar 2016 10:22:17 +0100 Subject: [PATCH 37/40] Fix beetroots duplication --- overviewer_core/textures.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/overviewer_core/textures.py b/overviewer_core/textures.py index 999be8f31..d98ab0ef5 100644 --- a/overviewer_core/textures.py +++ b/overviewer_core/textures.py @@ -4195,7 +4195,7 @@ def cobblestone_wall(self, blockid, data): return img # carrots, potatoes -@material(blockid=[141,142,207], data=range(8), transparent=True, nospawn=True) +@material(blockid=[141,142], data=range(8), transparent=True, nospawn=True) def crops4(self, blockid, data): # carrots and potatoes have 8 data, but only 4 visual stages stage = {0:0, @@ -4490,7 +4490,7 @@ def structure_block(self, blockid, data): return self.build_block(img, img) # beetroots -@material(blockid=[207], data=range(4), transparent=True, nospawn=True) +@material(blockid=207, data=range(4), transparent=True, nospawn=True) def crops(self, blockid, data): raw_crop = self.load_image_texture("assets/minecraft/textures/blocks/beetroots_stage_%d.png" % data) crop1 = self.transform_image_top(raw_crop) From fbede10d2e4eaa9ecaa89c478106eee0a90b5860 Mon Sep 17 00:00:00 2001 From: Mark Fickett Date: Fri, 20 Mar 2015 23:43:40 -0400 Subject: [PATCH 38/40] Add option to only load entities from chunk and use it for genPOI, resulting in roughly 1/3 runtime reduction. --- overviewer_core/aux_files/genPOI.py | 2 +- overviewer_core/world.py | 126 +++++++++++++++------------- 2 files changed, 68 insertions(+), 60 deletions(-) diff --git a/overviewer_core/aux_files/genPOI.py b/overviewer_core/aux_files/genPOI.py index 06fdd6961..70ecaa961 100755 --- a/overviewer_core/aux_files/genPOI.py +++ b/overviewer_core/aux_files/genPOI.py @@ -164,7 +164,7 @@ def handleEntities(rset, config, config_path, filters, markers): if numbuckets == 1: for (x, z, mtime) in rset.iterate_chunks(): try: - data = rset.get_chunk(x, z) + data = rset.get_chunk(x, z, entities_only=True) for poi in itertools.chain(data['TileEntities'], data['Entities']): if poi['id'] == 'Sign': # kill me poi = signWrangler(poi) diff --git a/overviewer_core/world.py b/overviewer_core/world.py index 910362f6a..be1f762f1 100644 --- a/overviewer_core/world.py +++ b/overviewer_core/world.py @@ -312,7 +312,7 @@ def _get_regionobj(self, regionfilename): return region #@log_other_exceptions - def get_chunk(self, x, z): + def get_chunk(self, x, z, entities_only=False): """Returns a dictionary object representing the "Level" NBT Compound structure for a chunk given its x, z coordinates. The coordinates given are chunk coordinates. Raises ChunkDoesntExist exception if the given @@ -395,66 +395,21 @@ def get_chunk(self, x, z): chunk_data['Biomes'] = biomes for section in chunk_data['Sections']: + if not entities_only: + section['Blocks'] = extract_blocks(section) + try: + section['SkyLight'] = extract_skylight(section) + section['BlockLight'] = extract_blocklight(section) + except ValueError: + # Iv'e seen at least 1 case where numpy raises a ValueError + # during the reshapes. I'm not sure what's going on here, + # but let's treat this as a corrupt chunk error. + logging.warning("There was a problem reading chunk %d,%d. It might be corrupt. I am giving up and will not render this particular chunk.", x, z) - # Turn the Blocks array into a 16x16x16 numpy matrix of shorts, - # adding in the additional block array if included. - blocks = numpy.frombuffer(section['Blocks'], dtype=numpy.uint8) - # Cast up to uint16, blocks can have up to 12 bits of data - blocks = blocks.astype(numpy.uint16) - blocks = blocks.reshape((16,16,16)) - if "Add" in section: - # This section has additional bits to tack on to the blocks - # array. Add is a packed array with 4 bits per slot, so - # it needs expanding - additional = numpy.frombuffer(section['Add'], dtype=numpy.uint8) - additional = additional.astype(numpy.uint16).reshape((16,16,8)) - additional_expanded = numpy.empty((16,16,16), dtype=numpy.uint16) - additional_expanded[:,:,::2] = (additional & 0x0F) << 8 - additional_expanded[:,:,1::2] = (additional & 0xF0) << 4 - blocks += additional_expanded - del additional - del additional_expanded - del section['Add'] # Save some memory - section['Blocks'] = blocks - - # Turn the skylight array into a 16x16x16 matrix. The array comes - # packed 2 elements per byte, so we need to expand it. - try: - skylight = numpy.frombuffer(section['SkyLight'], dtype=numpy.uint8) - skylight = skylight.reshape((16,16,8)) - skylight_expanded = numpy.empty((16,16,16), dtype=numpy.uint8) - skylight_expanded[:,:,::2] = skylight & 0x0F - skylight_expanded[:,:,1::2] = (skylight & 0xF0) >> 4 - del skylight - section['SkyLight'] = skylight_expanded - - # Turn the BlockLight array into a 16x16x16 matrix, same as SkyLight - blocklight = numpy.frombuffer(section['BlockLight'], dtype=numpy.uint8) - blocklight = blocklight.reshape((16,16,8)) - blocklight_expanded = numpy.empty((16,16,16), dtype=numpy.uint8) - blocklight_expanded[:,:,::2] = blocklight & 0x0F - blocklight_expanded[:,:,1::2] = (blocklight & 0xF0) >> 4 - del blocklight - section['BlockLight'] = blocklight_expanded - - # Turn the Data array into a 16x16x16 matrix, same as SkyLight - data = numpy.frombuffer(section['Data'], dtype=numpy.uint8) - data = data.reshape((16,16,8)) - data_expanded = numpy.empty((16,16,16), dtype=numpy.uint8) - data_expanded[:,:,::2] = data & 0x0F - data_expanded[:,:,1::2] = (data & 0xF0) >> 4 - del data - section['Data'] = data_expanded - except ValueError: - # iv'e seen at least 1 case where numpy raises a value error during the reshapes. i'm not - # sure what's going on here, but let's treat this as a corrupt chunk error - logging.warning("There was a problem reading chunk %d,%d. It might be corrupt. I am giving up and will not render this particular chunk.", x, z) - - logging.debug("Full traceback:", exc_info=1) - raise nbt.CorruptChunkError() - + logging.debug("Full traceback:", exc_info=1) + raise nbt.CorruptChunkError() + section['Data'] = extract_data(section) return chunk_data - def iterate_chunks(self): """Returns an iterator over all chunk metadata in this world. Iterates @@ -538,6 +493,59 @@ def _iterate_regionfiles(self): logging.warning("Holy shit what is up with region file %s !?" % f) yield (x, y, os.path.join(self.regiondir, f)) +def extract_blocks(section): + # Turn the Blocks array into a 16x16x16 numpy matrix of shorts, + # adding in the additional block array if included. + blocks = numpy.frombuffer(section['Blocks'], dtype=numpy.uint8) + # Cast up to uint16, blocks can have up to 12 bits of data + blocks = blocks.astype(numpy.uint16) + blocks = blocks.reshape((16,16,16)) + if 'Add' in section: + # This section has additional bits to tack on to the blocks + # array. Add is a packed array with 4 bits per slot, so + # it needs expanding + additional = numpy.frombuffer(section['Add'], dtype=numpy.uint8) + additional = additional.astype(numpy.uint16).reshape((16,16,8)) + additional_expanded = numpy.empty((16,16,16), dtype=numpy.uint16) + additional_expanded[:,:,::2] = (additional & 0x0F) << 8 + additional_expanded[:,:,1::2] = (additional & 0xF0) << 4 + blocks += additional_expanded + del additional + del additional_expanded + del section['Add'] # Save some memory + return blocks + +def extract_skylight(section): + # Turn the skylight array into a 16x16x16 matrix. The array comes + # packed 2 elements per byte, so we need to expand it. + skylight = numpy.frombuffer(section['SkyLight'], dtype=numpy.uint8) + skylight = skylight.reshape((16,16,8)) + skylight_expanded = numpy.empty((16,16,16), dtype=numpy.uint8) + skylight_expanded[:,:,::2] = skylight & 0x0F + skylight_expanded[:,:,1::2] = (skylight & 0xF0) >> 4 + del skylight + return skylight_expanded + +def extract_blocklight(section): + # Turn the BlockLight array into a 16x16x16 matrix, same as SkyLight + blocklight = numpy.frombuffer(section['BlockLight'], dtype=numpy.uint8) + blocklight = blocklight.reshape((16,16,8)) + blocklight_expanded = numpy.empty((16,16,16), dtype=numpy.uint8) + blocklight_expanded[:,:,::2] = blocklight & 0x0F + blocklight_expanded[:,:,1::2] = (blocklight & 0xF0) >> 4 + del blocklight + return blocklight_expanded + +def extract_data(section): + # Turn the Data array into a 16x16x16 matrix, same as SkyLight + data = numpy.frombuffer(section['Data'], dtype=numpy.uint8) + data = data.reshape((16,16,8)) + data_expanded = numpy.empty((16,16,16), dtype=numpy.uint8) + data_expanded[:,:,::2] = data & 0x0F + data_expanded[:,:,1::2] = (data & 0xF0) >> 4 + del data + return data_expanded + class RegionSetWrapper(object): """This is the base class for all "wrappers" of RegionSet objects. A wrapper is an object that acts similarly to a subclass: some methods are From 95f8c186f1aaabe92a98e9f203b7789835aa9fe8 Mon Sep 17 00:00:00 2001 From: tazo Date: Sun, 6 Mar 2016 15:32:20 +0100 Subject: [PATCH 39/40] Add chorus plants and chorus flowers --- overviewer_core/textures.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/overviewer_core/textures.py b/overviewer_core/textures.py index d98ab0ef5..4d391b399 100644 --- a/overviewer_core/textures.py +++ b/overviewer_core/textures.py @@ -4065,10 +4065,13 @@ def beacon(self, blockid, data): return img -# cobblestone and mossy cobblestone walls +# cobblestone and mossy cobblestone walls, chorus plants # one additional bit of data value added for mossy and cobblestone -@material(blockid=139, data=range(32), transparent=True, nospawn=True) +@material(blockid=[139, 199], data=range(32), transparent=True, nospawn=True) def cobblestone_wall(self, blockid, data): + # chorus plants + if blockid == 199: + t = self.load_image_texture("assets/minecraft/textures/blocks/chorus_plant.png").copy() # no rotation, uses pseudo data if data & 0b10000 == 0: # cobblestone @@ -4451,6 +4454,17 @@ def flower(self, blockid, data): return img +# chorus flower +@material(blockid=200, data=range(6), solid=True) +def chorus_flower(self, blockid, data): + # aged 5, dead + if data == 5: + texture = self.load_image_texture("assets/minecraft/textures/blocks/chorus_flower_dead.png") + else: + texture = self.load_image_texture("assets/minecraft/textures/blocks/chorus_flower.png") + + return self.build_block(texture,texture) + # purpur block block(blockid=201, top_image="assets/minecraft/textures/blocks/purpur_block.png") From 4814837a0fa8cea4164f237a043b0304749f3297 Mon Sep 17 00:00:00 2001 From: tazo Date: Sun, 6 Mar 2016 15:33:49 +0100 Subject: [PATCH 40/40] Fix chorus plants --- overviewer_core/textures.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/overviewer_core/textures.py b/overviewer_core/textures.py index 4d391b399..655e02e19 100644 --- a/overviewer_core/textures.py +++ b/overviewer_core/textures.py @@ -4073,7 +4073,7 @@ def cobblestone_wall(self, blockid, data): if blockid == 199: t = self.load_image_texture("assets/minecraft/textures/blocks/chorus_plant.png").copy() # no rotation, uses pseudo data - if data & 0b10000 == 0: + elif data & 0b10000 == 0: # cobblestone t = self.load_image_texture("assets/minecraft/textures/blocks/cobblestone.png").copy() else: