diff --git a/.travis.yml b/.travis.yml index 382f1dc..f58105e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ python: - "2.7" # - "3.2" env: - - MC_VERSION=1.7.4 + - 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 diff --git a/contrib/png-it.py b/contrib/png-it.py index eb1776f..1466fdc 100644 --- a/contrib/png-it.py +++ b/contrib/png-it.py @@ -34,7 +34,7 @@ def main(): metavar = '', type = str, dest = 'output', default = "output.png") (options, args) = parser.parse_args() - tileset = args[0] + # arg is overviewer tile set folder if len(args) > 1: @@ -42,6 +42,7 @@ def main(): if not args: parser.error("Error! Need an overviewer tile set folder. Use --help for a complete list of options.") + tileset = args[0] #set the tileset dir after ensuring it's been provided, not before. if not options.zoom_level: parser.error("Error! The option zoom-level is mandatory.") @@ -126,7 +127,7 @@ def main(): print "The image size will be {0}x{1}".format(final_cropped_img_size[0],final_cropped_img_size[1]) print "A total of {0} MB of memory will be used.".format(mem/1024**2) if mem/1024.**2. > options.memory_limit: - print "Warning! The expected RAM usage exceeds the spicifyed limit. Exiting." + print "Warning! The expected RAM usage exceeds the specified limit. Exiting." sys.exit(1) # Create a new huge image diff --git a/docs/config.rst b/docs/config.rst index fe90c6a..c617f52 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -625,7 +625,7 @@ Rendering 'crop': (-500, -500, 500, 500), } - Example that renders two 500 by 500 squares of land: + Example that renders two 500 by 500 squares of land:: renders['myrender'] = { 'world': 'myworld', diff --git a/docs/running.rst b/docs/running.rst index 6ccfb96..340f1e5 100644 --- a/docs/running.rst +++ b/docs/running.rst @@ -261,13 +261,13 @@ If you want or need to provide your own textures, you have several options: :: - VERSION=1.7.2 + VERSION=1.8 wget https://s3.amazonaws.com/Minecraft.Download/versions/${VERSION}/${VERSION}.jar -P ~/.minecraft/versions/${VERSION}/ If that's too confusing for you, then just take this single line and paste it into - a terminal to get 1.7.2 textures:: + a terminal to get 1.8 textures:: - wget https://s3.amazonaws.com/Minecraft.Download/versions/1.7.2/1.7.2.jar -P ~/.minecraft/versions/1.7.2/ + wget https://s3.amazonaws.com/Minecraft.Download/versions/1.8/1.8.jar -P ~/.minecraft/versions/1.8/ * You can also just run the launcher to install the client. diff --git a/overviewer_core/aux_files/genPOI.py b/overviewer_core/aux_files/genPOI.py index 15a8532..f6bce5f 100755 --- a/overviewer_core/aux_files/genPOI.py +++ b/overviewer_core/aux_files/genPOI.py @@ -15,6 +15,7 @@ markers.js holds a list of which markerSets are attached to each tileSet ''' import os +import time import logging import json import sys @@ -22,6 +23,7 @@ import re import urllib2 import multiprocessing import itertools +import gzip from collections import defaultdict from multiprocessing import Pool @@ -134,6 +136,26 @@ def handleEntities(rset, config, filters, markers): class PlayerDict(dict): use_uuid = False _name = '' + uuid_cache = None # A cache for the UUID->profile lookups + + @classmethod + 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())) + else: + cls.uuid_cache = {} + logging.info("Initialized an empty UUID cache") + + @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())) + def __getitem__(self, item): if item == "EntityId": if not super(PlayerDict, self).has_key("EntityId"): @@ -145,9 +167,17 @@ class PlayerDict(dict): return super(PlayerDict, self).__getitem__(item) def get_name_from_uuid(self): + sname = self._name.replace('-','') try: - profile = json.loads(urllib2.urlopen(UUID_LOOKUP_URL + self._name.replace('-','')).read()) + profile = PlayerDict.uuid_cache[sname] + return profile['name'] + except (KeyError,): + pass + + try: + profile = json.loads(urllib2.urlopen(UUID_LOOKUP_URL + sname).read()) if 'name' in profile: + PlayerDict.uuid_cache[sname] = profile return profile['name'] except (ValueError, urllib2.URLError): logging.warning("Unable to get player name for UUID %s", self._name) @@ -196,9 +226,12 @@ def handlePlayers(worldpath, filters, markers): data['x'] = int(data['Pos'][0]) data['y'] = int(data['Pos'][1]) data['z'] = int(data['Pos'][2]) + # Time at last logout, calculated from last time the player's file was modified + data['time'] = time.localtime(os.path.getmtime(os.path.join(playerdir, playerfile))) # Spawn position (bed or main spawn) if "SpawnX" in data: + # Spawn position (bed or main spawn) spawn = PlayerDict() spawn._name = playername spawn["id"] = "PlayerSpawn" @@ -395,6 +428,7 @@ def main(): # apply filters to players if not options.skipplayers: + PlayerDict.load_cache(destdir) # group filters by worldpath, so we only search for players once per # world keyfunc = lambda x: x[4] @@ -414,6 +448,8 @@ def main(): logging.info("Done handling POIs") logging.info("Writing out javascript files") + PlayerDict.save_cache(destdir) + with open(os.path.join(destdir, "markersDB.js"), "w") as output: output.write("var markersDB=") json.dump(markers, output, indent=2) diff --git a/overviewer_core/observer.py b/overviewer_core/observer.py index 32a472c..e17c8f5 100644 --- a/overviewer_core/observer.py +++ b/overviewer_core/observer.py @@ -92,17 +92,50 @@ class LoggingObserver(Observer): #this is an easy way to make the first update() call print a line self.last_update = -101 + # a fake ProgressBar, for the sake of ETA + class FakePBar(object): + def __init__(self): + self.maxval = None + self.currval = 0 + self.finished = False + self.start_time = None + self.seconds_elapsed = 0 + def finish(self): + self.update(self.maxval) + def update(self, value): + assert 0 <= value <= self.maxval + self.currval = value + if self.finished: + return False + if not self.start_time: + self.start_time = time.time() + self.seconds_elapsed = time.time() - self.start_time + + if value == self.maxval: + self.finished = True + + self.fake = FakePBar(); + self.eta = progressbar.ETA() + + def start(self, max_value): + self.fake.maxval = max_value + super(LoggingObserver, self).start(max_value) + + def finish(self): - logging.info("Rendered %d of %d. %d%% complete", self.get_max_value(), - self.get_max_value(), 100.0) + self.fake.finish() + logging.info("Rendered %d of %d. %d%% complete. %s", self.get_max_value(), + self.get_max_value(), 100.0, self.eta.update(self.fake)) super(LoggingObserver, self).finish() def update(self, current_value): super(LoggingObserver, self).update(current_value) + self.fake.update(current_value) + if self._need_update(): - logging.info("Rendered %d of %d. %d%% complete", + logging.info("Rendered %d of %d. %d%% complete. %s", self.get_current_value(), self.get_max_value(), - self.get_percentage()) + self.get_percentage(), self.eta.update(self.fake)) self.last_update = current_value return True return False diff --git a/overviewer_core/src/iterate.c b/overviewer_core/src/iterate.c index fc52b78..8a2e324 100644 --- a/overviewer_core/src/iterate.c +++ b/overviewer_core/src/iterate.c @@ -262,6 +262,7 @@ is_stairs(int block) { case 156: /* quartz stairs */ case 163: /* acacia wood stairs */ case 164: /* dark wood stairs */ + case 180: /* red sandstone stairs */ return 1; } return 0; @@ -309,9 +310,12 @@ generate_pseudo_data(RenderState *state, unsigned short ancilData) { } data = (check_adjacent_blocks(state, x, y, z, state->block) ^ 0x0f) | data; return (data << 4) | (ancilData & 0x0f); - } else if (state->block == 85) { /* fences */ + } else if ((state->block == 85) || (state->block == 188) || (state->block == 189) || + (state->block == 190) || (state->block == 191) || (state->block == 192)) { /* fences */ /* check for fences AND fence gates */ - return check_adjacent_blocks(state, x, y, z, state->block) | check_adjacent_blocks(state, x, y, z, 107); + return check_adjacent_blocks(state, x, y, z, state->block) | check_adjacent_blocks(state, x, y, z, 107) | + check_adjacent_blocks(state, x, y, z, 183) | check_adjacent_blocks(state, x, y, z, 184) | check_adjacent_blocks(state, x, y, z, 185) | + check_adjacent_blocks(state, x, y, z, 186) | check_adjacent_blocks(state, x, y, z, 187); } else if (state->block == 55) { /* redstone */ /* three addiotional bit are added, one for on/off state, and @@ -397,7 +401,9 @@ generate_pseudo_data(RenderState *state, unsigned short ancilData) { /* portal and nether brick fences */ return check_adjacent_blocks(state, x, y, z, state->block); - } else if ((state->block == 64) || (state->block == 71)) { + } else if ((state->block == 64) || (state->block == 71) || (state->block == 193) || + (state->block == 194) || (state->block == 195) || (state->block == 196) || + (state->block ==197)) { /* use bottom block data format plus one bit for top/down * block (0x8) and one bit for hinge position (0x10) */ @@ -703,14 +709,21 @@ chunk_render(PyObject *self, PyObject *args) { * trapped chests, stairs */ if ((state.block == 2) || (state.block == 9) || (state.block == 20) || (state.block == 54) || - (state.block == 55) || (state.block == 64) || - (state.block == 71) || (state.block == 79) || + (state.block == 55) || + /* doors */ + (state.block == 64) || (state.block == 193) || + (state.block == 194) || (state.block == 195) || + (state.block == 196) || (state.block == 197) || + (state.block == 71) || /* end doors */ + (state.block == 79) || (state.block == 85) || (state.block == 90) || (state.block == 101) || (state.block == 102) || (state.block == 111) || (state.block == 113) || (state.block == 139) || (state.block == 175) || (state.block == 160) || (state.block == 95) || - (state.block == 146) || + (state.block == 146) || (state.block == 188) || + (state.block == 189) || (state.block == 190) || + (state.block == 191) || (state.block == 192) || is_stairs(state.block)) { ancilData = generate_pseudo_data(&state, ancilData); state.block_pdata = ancilData; diff --git a/overviewer_core/src/overviewer.h b/overviewer_core/src/overviewer.h index af5b418..873dcaa 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 46 +#define OVERVIEWER_EXTENSION_VERSION 49 /* Python PIL, and numpy headers */ #include diff --git a/overviewer_core/src/primitives/lighting.c b/overviewer_core/src/primitives/lighting.c index c891249..8978c06 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) && authoratative) { + if (!(block == 44 || block == 53 || block == 67 || block == 108 || block == 109 || block == 180 || block == 182) && authoratative) { *authoratative = 1; } @@ -160,7 +160,7 @@ 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 == 128 || block == 134 || block == 135 || block == 136 || block == 145 || block == 156 || block == 163 || block == 164 || block == 180 || block == 182) { unsigned int upper_block; /* stairs and half-blocks take the skylevel from the upper block if it's transparent */ @@ -171,7 +171,7 @@ 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 == 135 || upper_block == 136 || upper_block == 156 || upper_block == 163 || upper_block == 164 || upper_block == 180 || upper_block == 182); 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 73ecaf5..36ce0fd 100644 --- a/overviewer_core/textures.py +++ b/overviewer_core/textures.py @@ -252,12 +252,12 @@ class Textures(object): most_recent_version = [0,0,0] for version in versions: - # Look for the latest non-snapshot that is at least 1.6. This - # version is only compatible with >=1.6, and we cannot in general + # Look for the latest non-snapshot that is at least 1.8. This + # version is only compatible with >=1.8, and we cannot in general # tell if a snapshot is more or less recent than a release. - # Allow two component names such as "1.6" and three component names - # such as "1.6.1" + # Allow two component names such as "1.8" and three component names + # such as "1.8.1" if version.count(".") not in (1,2): continue try: @@ -265,14 +265,14 @@ class Textures(object): except ValueError: continue - if versionparts < [1,7]: + if versionparts < [1,8]: continue if versionparts > most_recent_version: most_recent_version = versionparts if most_recent_version != [0,0,0]: - if verbose: logging.info("Most recent version >=1.7.0: {0}. Searching it for the file...".format(most_recent_version)) + if verbose: logging.info("Most recent version >=1.8.0: {0}. Searching it for the file...".format(most_recent_version)) jarname = ".".join(str(x) for x in most_recent_version) jarpath = os.path.join(versiondir, jarname, jarname + ".jar") @@ -290,7 +290,7 @@ class Textures(object): if verbose: logging.info("Did not find file {0} in jar {1}".format(filename, jarpath)) else: - if verbose: logging.info("Did not find any non-snapshot minecraft jars >=1.7.0") + if verbose: logging.info("Did not find any non-snapshot minecraft jars >=1.8.0") # Last ditch effort: look for the file is stored in with the overviewer # installation. We include a few files that aren't included with Minecraft @@ -310,7 +310,7 @@ class Textures(object): 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.7-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.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)) def load_image_texture(self, filename): # Textures may be animated or in a different resolution than 16x16. @@ -430,7 +430,7 @@ class Textures(object): self.foliagecolor = list(self.load_image("foliage.png").getdata()) return self.foliagecolor - #I guess "watercolor" is wrong. But I can't correct as my texture pack don't define water color. + #I guess "watercolor" is wrong. But I can't correct as my texture pack don't define water color. def load_water_color(self): """Helper function to load the water color texture.""" if not hasattr(self, "watercolor"): @@ -864,7 +864,23 @@ def billboard(blockid=[], imagename=None, **kwargs): ## # stone -block(blockid=1, top_image="assets/minecraft/textures/blocks/stone.png") +@material(blockid=1, data=range(7), solid=True) +def stone(self, blockid, data): + if data == 0: # regular old-school stone + img = self.load_image_texture("assets/minecraft/textures/blocks/stone.png") + elif data == 1: # granite + img = self.load_image_texture("assets/minecraft/textures/blocks/stone_granite.png") + elif data == 2: # polished granite + img = self.load_image_texture("assets/minecraft/textures/blocks/stone_granite_smooth.png") + elif data == 3: # diorite + img = self.load_image_texture("assets/minecraft/textures/blocks/stone_diorite.png") + elif data == 4: # polished diorite + img = self.load_image_texture("assets/minecraft/textures/blocks/stone_diorite_smooth.png") + elif data == 5: # andesite + img = self.load_image_texture("assets/minecraft/textures/blocks/stone_andesite.png") + elif data == 6: # polished andesite + img = self.load_image_texture("assets/minecraft/textures/blocks/stone_andesite_smooth.png") + return self.build_block(img, img) @material(blockid=2, data=range(11)+[0x10,], solid=True) def grass(self, blockid, data): @@ -1135,6 +1151,18 @@ def sandstone(self, blockid, data): return self.build_block(top, self.load_image_texture("assets/minecraft/textures/blocks/sandstone_carved.png")) if data == 2: # soft return self.build_block(top, self.load_image_texture("assets/minecraft/textures/blocks/sandstone_smooth.png")) + +# red sandstone +@material(blockid=179, data=range(3), solid=True) +def sandstone(self, blockid, data): + top = self.load_image_texture("assets/minecraft/textures/blocks/red_sandstone_top.png") + if data == 0: # normal + side = self.load_image_texture("assets/minecraft/textures/blocks/red_sandstone_normal.png") + return self.build_full_block(top, None, None, side, side, self.load_image_texture("assets/minecraft/textures/blocks/red_sandstone_bottom.png") ) + if data == 1: # hieroglyphic + return self.build_block(top, self.load_image_texture("assets/minecraft/textures/blocks/red_sandstone_carved.png")) + if data == 2: # soft + return self.build_block(top, self.load_image_texture("assets/minecraft/textures/blocks/red_sandstone_smooth.png")) # note block block(blockid=25, top_image="assets/minecraft/textures/blocks/noteblock.png") @@ -1529,38 +1557,56 @@ block(blockid=42, top_image="assets/minecraft/textures/blocks/iron_block.png") # 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], data=range(16), transparent=(44,), solid=True) +@material(blockid=[43, 44, 181, 182], data=range(16), transparent=(44,182,), solid=True) def slabs(self, blockid, data): - if blockid == 44: + if blockid == 44 or blockid == 182: texture = data & 7 else: # data > 8 are special double slabs texture = data - if texture== 0: # stone slab - top = self.load_image_texture("assets/minecraft/textures/blocks/stone_slab_top.png") - side = self.load_image_texture("assets/minecraft/textures/blocks/stone_slab_side.png") - elif texture== 1: # smooth stone - top = self.load_image_texture("assets/minecraft/textures/blocks/sandstone_top.png") - side = self.load_image_texture("assets/minecraft/textures/blocks/sandstone_normal.png") - elif texture== 2: # wooden slab - top = side = self.load_image_texture("assets/minecraft/textures/blocks/planks_oak.png") - elif texture== 3: # cobblestone slab - top = side = self.load_image_texture("assets/minecraft/textures/blocks/cobblestone.png") - elif texture== 4: # brick - top = side = self.load_image_texture("assets/minecraft/textures/blocks/brick.png") - elif texture== 5: # stone brick - top = side = self.load_image_texture("assets/minecraft/textures/blocks/stonebrick.png") - elif texture== 6: # nether brick slab - top = side = self.load_image_texture("assets/minecraft/textures/blocks/nether_brick.png") - elif texture== 7: #quartz - top = side = self.load_image_texture("assets/minecraft/textures/blocks/quartz_block_side.png") - elif texture== 8: # special stone double slab with top texture only - top = side = self.load_image_texture("assets/minecraft/textures/blocks/stone_slab_top.png") - elif texture== 9: # special sandstone double slab with top texture only - top = side = self.load_image_texture("assets/minecraft/textures/blocks/sandstone_top.png") - else: - return None + + if blockid == 44 or blockid == 43: + if texture== 0: # stone slab + top = self.load_image_texture("assets/minecraft/textures/blocks/stone_slab_top.png") + side = self.load_image_texture("assets/minecraft/textures/blocks/stone_slab_side.png") + elif texture== 1: # sandstone slab + top = self.load_image_texture("assets/minecraft/textures/blocks/sandstone_top.png") + side = self.load_image_texture("assets/minecraft/textures/blocks/sandstone_normal.png") + elif texture== 2: # wooden slab + top = side = self.load_image_texture("assets/minecraft/textures/blocks/planks_oak.png") + elif texture== 3: # cobblestone slab + top = side = self.load_image_texture("assets/minecraft/textures/blocks/cobblestone.png") + elif texture== 4: # brick + top = side = self.load_image_texture("assets/minecraft/textures/blocks/brick.png") + elif texture== 5: # stone brick + top = side = self.load_image_texture("assets/minecraft/textures/blocks/stonebrick.png") + elif texture== 6: # nether brick slab + top = side = self.load_image_texture("assets/minecraft/textures/blocks/nether_brick.png") + elif texture== 7: #quartz + top = side = self.load_image_texture("assets/minecraft/textures/blocks/quartz_block_side.png") + elif texture== 8: # special stone double slab with top texture only + top = side = self.load_image_texture("assets/minecraft/textures/blocks/stone_slab_top.png") + elif texture== 9: # special sandstone double slab with top texture only + top = side = self.load_image_texture("assets/minecraft/textures/blocks/sandstone_top.png") + else: + return None + + elif blockid == 182: # single red sandstone slab + if texture == 0: + top = self.load_image_texture("assets/minecraft/textures/blocks/red_sandstone_top.png") + side = self.load_image_texture("assets/minecraft/textures/blocks/red_sandstone_normal.png") + else: + return None + + elif blockid == 181: # double red sandstone slab + if texture == 0: # red sandstone + top = self.load_image_texture("assets/minecraft/textures/blocks/red_sandstone_top.png") + side = self.load_image_texture("assets/minecraft/textures/blocks/red_sandstone_normal.png") + elif texture == 8: # 'full' red sandstone (smooth) + top = side = self.load_image_texture("assets/minecraft/textures/blocks/red_sandstone_top.png"); + else: + return None - if blockid == 43: # double slab + if blockid == 43 or blockid == 181: # double slab return self.build_block(top, side) # cut the side texture in half @@ -1693,8 +1739,8 @@ def fire(self, blockid, data): # monster spawner 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 and quartz stairs. -@material(blockid=[53,67,108,109,114,128,134,135,136,156,163,164], data=range(128), transparent=True, solid=True, nospawn=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) def stairs(self, blockid, data): # preserve the upside-down bit upside_down = data & 0x4 @@ -1731,17 +1777,22 @@ def stairs(self, blockid, data): texture = self.load_image_texture("assets/minecraft/textures/blocks/planks_acacia.png").copy() elif blockid == 164: # dark oak stairs 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() outside_l = texture.copy() outside_r = texture.copy() inside_l = texture.copy() inside_r = texture.copy() - # sandstone & quartz stairs have special top texture + # sandstone, red sandstone, and quartz stairs have special top texture if blockid == 128: texture = self.load_image_texture("assets/minecraft/textures/blocks/sandstone_top.png").copy() elif blockid == 156: texture = self.load_image_texture("assets/minecraft/textures/blocks/quartz_block_top.png").copy() + elif blockid == 180: + texture = self.load_image_texture("assets/minecraft/textures/blocks/red_sandstone_top.png").copy() + slab_top = texture.copy() @@ -2179,7 +2230,7 @@ def signpost(self, blockid, data): # wooden and iron door # uses pseudo-ancildata found in iterate.c -@material(blockid=[64,71], data=range(32), transparent=True) +@material(blockid=[64,71,193,194,195,196,197], data=range(32), transparent=True) def door(self, blockid, data): #Masked to not clobber block top/bottom & swung info if self.rotation == 1: @@ -2199,9 +2250,35 @@ def door(self, blockid, data): elif (data & 0b00011) == 3: data = data & 0b11100 | 2 if data & 0x8 == 0x8: # top of the door - raw_door = self.load_image_texture("assets/minecraft/textures/blocks/%s.png" % ("door_wood_upper" if blockid == 64 else "door_iron_upper")) + if blockid == 64: # classic wood door + raw_door = self.load_image_texture("assets/minecraft/textures/blocks/door_wood_upper.png") + elif blockid == 71: # iron door + raw_door = self.load_image_texture("assets/minecraft/textures/blocks/door_iron_upper.png") + elif blockid == 193: # spruce door + raw_door = self.load_image_texture("assets/minecraft/textures/blocks/door_spruce_upper.png") + elif blockid == 194: # birch door + raw_door = self.load_image_texture("assets/minecraft/textures/blocks/door_birch_upper.png") + elif blockid == 195: # jungle door + raw_door = self.load_image_texture("assets/minecraft/textures/blocks/door_jungle_upper.png") + elif blockid == 196: # acacia door + raw_door = self.load_image_texture("assets/minecraft/textures/blocks/door_acacia_upper.png") + elif blockid == 197: # dark_oak door + raw_door = self.load_image_texture("assets/minecraft/textures/blocks/door_dark_oak_upper.png") else: # bottom of the door - raw_door = self.load_image_texture("assets/minecraft/textures/blocks/%s.png" % ("door_wood_lower" if blockid == 64 else "door_iron_lower")) + if blockid == 64: + raw_door = self.load_image_texture("assets/minecraft/textures/blocks/door_wood_lower.png") + elif blockid == 71: # iron door + raw_door = self.load_image_texture("assets/minecraft/textures/blocks/door_iron_lower.png") + elif blockid == 193: # spruce door + raw_door = self.load_image_texture("assets/minecraft/textures/blocks/door_spruce_lower.png") + elif blockid == 194: # birch door + raw_door = self.load_image_texture("assets/minecraft/textures/blocks/door_birch_lower.png") + elif blockid == 195: # jungle door + raw_door = self.load_image_texture("assets/minecraft/textures/blocks/door_jungle_lower.png") + elif blockid == 196: # acacia door + raw_door = self.load_image_texture("assets/minecraft/textures/blocks/door_acacia_lower.png") + elif blockid == 197: # dark_oak door + raw_door = self.load_image_texture("assets/minecraft/textures/blocks/door_dark_oak_lower.png") # if you want to render all doors as closed, then force # force closed to be True @@ -2722,7 +2799,7 @@ def jukebox(self, blockid, data): # nether and normal fences # uses pseudo-ancildata found in iterate.c -@material(blockid=[85, 113], data=range(16), transparent=True, nospawn=True) +@material(blockid=[85, 188, 189, 190, 191, 192, 113], data=range(16), transparent=True, nospawn=True) def fence(self, blockid, data): # no need for rotations, it uses pseudo data. # create needed images for Big stick fence @@ -2730,6 +2807,26 @@ def fence(self, blockid, data): fence_top = self.load_image_texture("assets/minecraft/textures/blocks/planks_oak.png").copy() fence_side = self.load_image_texture("assets/minecraft/textures/blocks/planks_oak.png").copy() fence_small_side = self.load_image_texture("assets/minecraft/textures/blocks/planks_oak.png").copy() + elif blockid == 188: # spruce fence + fence_top = self.load_image_texture("assets/minecraft/textures/blocks/planks_spruce.png").copy() + fence_side = self.load_image_texture("assets/minecraft/textures/blocks/planks_spruce.png").copy() + fence_small_side = self.load_image_texture("assets/minecraft/textures/blocks/planks_spruce.png").copy() + elif blockid == 189: # birch fence + fence_top = self.load_image_texture("assets/minecraft/textures/blocks/planks_birch.png").copy() + fence_side = self.load_image_texture("assets/minecraft/textures/blocks/planks_birch.png").copy() + fence_small_side = self.load_image_texture("assets/minecraft/textures/blocks/planks_birch.png").copy() + elif blockid == 190: # jungle fence + fence_top = self.load_image_texture("assets/minecraft/textures/blocks/planks_jungle.png").copy() + fence_side = self.load_image_texture("assets/minecraft/textures/blocks/planks_jungle.png").copy() + fence_small_side = self.load_image_texture("assets/minecraft/textures/blocks/planks_jungle.png").copy() + elif blockid == 191: # big/dark oak fence + fence_top = self.load_image_texture("assets/minecraft/textures/blocks/planks_big_oak.png").copy() + fence_side = self.load_image_texture("assets/minecraft/textures/blocks/planks_big_oak.png").copy() + fence_small_side = self.load_image_texture("assets/minecraft/textures/blocks/planks_big_oak.png").copy() + elif blockid == 192: # acacia oak fence + fence_top = self.load_image_texture("assets/minecraft/textures/blocks/planks_acacia.png").copy() + fence_side = self.load_image_texture("assets/minecraft/textures/blocks/planks_acacia.png").copy() + fence_small_side = self.load_image_texture("assets/minecraft/textures/blocks/planks_acacia.png").copy() else: # netherbrick fence fence_top = self.load_image_texture("assets/minecraft/textures/blocks/nether_brick.png").copy() fence_side = self.load_image_texture("assets/minecraft/textures/blocks/nether_brick.png").copy() @@ -3216,7 +3313,7 @@ def comparator(self, blockid, data): # trapdoor # the trapdoor is looks like a sprite when opened, that's not good -@material(blockid=96, data=range(16), transparent=True, nospawn=True) +@material(blockid=[96,167], data=range(16), transparent=True, nospawn=True) def trapdoor(self, blockid, data): # rotation @@ -3238,7 +3335,10 @@ def trapdoor(self, blockid, data): elif (data & 0b0011) == 3: data = data & 0b1100 | 0 # texture generation - texture = self.load_image_texture("assets/minecraft/textures/blocks/trapdoor.png") + if blockid == 96: + texture = self.load_image_texture("assets/minecraft/textures/blocks/trapdoor.png") + else: + texture = self.load_image_texture("assets/minecraft/textures/blocks/iron_trapdoor.png") if data & 0x4 == 0x4: # opened trapdoor if data & 0x3 == 0: # west img = self.build_full_block(None, None, None, None, texture) @@ -3487,7 +3587,7 @@ def vines(self, blockid, data): return img # fence gates -@material(blockid=107, data=range(8), transparent=True, nospawn=True) +@material(blockid=[107, 183, 184, 185, 186, 187], data=range(8), transparent=True, nospawn=True) def fence_gate(self, blockid, data): # rotation @@ -3514,7 +3614,21 @@ def fence_gate(self, blockid, data): data = data | 0x4 # create the closed gate side - gate_side = self.load_image_texture("assets/minecraft/textures/blocks/planks_oak.png").copy() + if blockid == 107: # Oak + gate_side = self.load_image_texture("assets/minecraft/textures/blocks/planks_oak.png").copy() + elif blockid == 183: # Spruce + gate_side = self.load_image_texture("assets/minecraft/textures/blocks/planks_spruce.png").copy() + elif blockid == 184: # Birch + gate_side = self.load_image_texture("assets/minecraft/textures/blocks/planks_birch.png").copy() + elif blockid == 185: # Jungle + gate_side = self.load_image_texture("assets/minecraft/textures/blocks/planks_jungle.png").copy() + elif blockid == 186: # Dark Oak + gate_side = self.load_image_texture("assets/minecraft/textures/blocks/planks_big_oak.png").copy() + elif blockid == 187: # Acacia + gate_side = self.load_image_texture("assets/minecraft/textures/blocks/planks_acacia.png").copy() + else: + return None + gate_side_draw = ImageDraw.Draw(gate_side) gate_side_draw.rectangle((7,0,15,0),outline=(0,0,0,0),fill=(0,0,0,0)) gate_side_draw.rectangle((7,4,9,6),outline=(0,0,0,0),fill=(0,0,0,0)) @@ -4205,6 +4319,27 @@ def hopper(self, blockid, data): return img +# slime block +block(blockid=165, top_image="assets/minecraft/textures/blocks/slime.png") + +# prismarine block +@material(blockid=168, data=range(3), solid=True) +def prismarine_block(self, blockid, data): + + if data == 0: # prismarine + t = self.load_image_texture("assets/minecraft/textures/blocks/prismarine_rough.png") + elif data == 1: # prismarine bricks + t = self.load_image_texture("assets/minecraft/textures/blocks/prismarine_bricks.png") + elif data == 2: # dark prismarine + t = self.load_image_texture("assets/minecraft/textures/blocks/prismarine_dark.png") + + img = self.build_block(t, t) + + return img + +# sea lantern +block(blockid=169, top_image="assets/minecraft/textures/blocks/sea_lantern.png") + # hay block @material(blockid=170, data=range(9), solid=True) def hayblock(self, blockid, data):