0

Initial Python 3 port

Many things work, some don't. Notably, genPOI doesn't work, and
there's some signedness comparison stuff going on in the C extension.

This also completely drops support for Python 2, as maintaining a C
extension for both Python 2 and 3 is a pain and not worth it for the
9 months that Python 2 is still going to be supported upstream.

The documentation needs to be adjusted as well.

All of the few tests we have pass, and rendering a map works, both
with a configuration file and without. We can also use optimizeimages.

Concerns #1528.
This commit is contained in:
Nicolas F
2019-03-16 20:43:25 +01:00
parent 99eebd5b69
commit e348a548b6
33 changed files with 369 additions and 625 deletions

View File

@@ -18,7 +18,7 @@ import imp
import os
import os.path
import zipfile
from cStringIO import StringIO
from io import BytesIO
import math
from random import randint
import numpy
@@ -26,8 +26,32 @@ from PIL import Image, ImageEnhance, ImageOps, ImageDraw
import logging
import functools
import util
from c_overviewer import alpha_over
from . import util
# global variables to collate information in @material decorators
blockmap_generators = {}
known_blocks = set()
used_datas = set()
max_blockid = 0
max_data = 0
transparent_blocks = set()
solid_blocks = set()
fluid_blocks = set()
nospawn_blocks = set()
nodata_blocks = set()
# This is here for circular import reasons.
# Please don't ask, I choose to repress these memories.
# ... okay fine I'll tell you.
# Initialising the C extension requires access to the globals above.
# Due to the circular import, this wouldn't work, unless we reload the
# module in the C extension or just move the import below its dependencies.
from .c_overviewer import alpha_over
class TextureException(Exception):
"To be thrown when a texture is not found."
@@ -37,6 +61,7 @@ class TextureException(Exception):
color_map = ["white", "orange", "magenta", "light_blue", "yellow", "lime", "pink", "gray",
"light_gray", "cyan", "purple", "blue", "brown", "green", "red", "black"]
##
## Textures object
##
@@ -76,10 +101,11 @@ class Textures(object):
del attributes[attr]
except KeyError:
pass
attributes['jar'] = None
return attributes
def __setstate__(self, attrs):
# regenerate textures, if needed
for attr, val in attrs.iteritems():
for attr, val in list(attrs.items()):
setattr(self, attr, val)
self.texture_cache = {}
if self.generated:
@@ -99,7 +125,7 @@ class Textures(object):
global known_blocks, used_datas
self.blockmap = [None] * max_blockid * max_data
for (blockid, data), texgen in blockmap_generators.iteritems():
for (blockid, data), texgen in list(blockmap_generators.items()):
tex = texgen(self, blockid, data)
self.blockmap[blockid * max_data + data] = self.generate_texture_tuple(tex)
@@ -224,7 +250,7 @@ class Textures(object):
self.jar.getinfo(jarfilename)
if verbose: logging.info("Found (cached) %s in '%s'", jarfilename, self.jarpath)
return self.jar.open(jarfilename)
except (KeyError, IOError), e:
except (KeyError, IOError) as e:
pass
# Find an installed minecraft client jar and look in it for the texture
@@ -285,7 +311,7 @@ class Textures(object):
if verbose: logging.info("Found %s in '%s'", jarfilename, jarpath)
self.jar, self.jarpath = jar, jarpath
return jar.open(jarfilename)
except (KeyError, IOError), e:
except (KeyError, IOError) as e:
pass
if verbose: logging.info("Did not find file {0} in jar {1}".format(filename, jarpath))
@@ -334,7 +360,7 @@ class Textures(object):
return self.texture_cache[filename]
fileobj = self.find_file(filename)
buffer = StringIO(fileobj.read())
buffer = BytesIO(fileobj.read())
img = Image.open(buffer).convert("RGBA")
self.texture_cache[filename] = img
return img
@@ -444,8 +470,8 @@ class Textures(object):
textures = []
(terrain_width, terrain_height) = terrain.size
texture_resolution = terrain_width / 16
for y in xrange(16):
for x in xrange(16):
for y in range(16):
for x in range(16):
left = x*texture_resolution
upper = y*texture_resolution
right = left+texture_resolution
@@ -815,19 +841,6 @@ class Textures(object):
## The other big one: @material and associated framework
##
# global variables to collate information in @material decorators
blockmap_generators = {}
known_blocks = set()
used_datas = set()
max_blockid = 0
max_data = 0
transparent_blocks = set()
solid_blocks = set()
fluid_blocks = set()
nospawn_blocks = set()
nodata_blocks = set()
# the material registration decorator
def material(blockid=[], data=[0], **kwargs):
@@ -837,11 +850,11 @@ def material(blockid=[], data=[0], **kwargs):
# make sure blockid and data are iterable
try:
iter(blockid)
except:
except Exception:
blockid = [blockid,]
try:
iter(data)
except:
except Exception:
data = [data,]
def inner_material(func):
@@ -924,7 +937,7 @@ def billboard(blockid=[], imagename=None, **kwargs):
##
# stone
@material(blockid=1, data=range(7), solid=True)
@material(blockid=1, data=list(range(7)), solid=True)
def stone(self, blockid, data):
if data == 0: # regular old-school stone
img = self.load_image_texture("assets/minecraft/textures/block/stone.png")
@@ -942,7 +955,7 @@ def stone(self, blockid, data):
img = self.load_image_texture("assets/minecraft/textures/block/polished_andesite.png")
return self.build_block(img, img)
@material(blockid=2, data=range(11)+[0x10,], solid=True)
@material(blockid=2, data=list(range(11))+[0x10,], solid=True)
def grass(self, blockid, data):
# 0x10 bit means SNOW
side_img = self.load_image_texture("assets/minecraft/textures/block/grass_block_side.png")
@@ -954,7 +967,7 @@ def grass(self, blockid, data):
return img
# dirt
@material(blockid=3, data=range(3), solid=True)
@material(blockid=3, data=list(range(3)), solid=True)
def dirt_blocks(self, blockid, data):
side_img = self.load_image_texture("assets/minecraft/textures/block/dirt.png")
if data == 0: # normal
@@ -970,7 +983,7 @@ def dirt_blocks(self, blockid, data):
block(blockid=4, top_image="assets/minecraft/textures/block/cobblestone.png")
# wooden planks
@material(blockid=5, data=range(6), solid=True)
@material(blockid=5, data=list(range(6)), solid=True)
def wooden_planks(self, blockid, data):
if data == 0: # normal
return self.build_block(self.load_image_texture("assets/minecraft/textures/block/oak_planks.png"), self.load_image_texture("assets/minecraft/textures/block/oak_planks.png"))
@@ -985,7 +998,7 @@ def wooden_planks(self, blockid, data):
if data == 5: # dark oak
return self.build_block(self.load_image_texture("assets/minecraft/textures/block/dark_oak_planks.png"),self.load_image_texture("assets/minecraft/textures/block/dark_oak_planks.png"))
@material(blockid=6, data=range(16), transparent=True)
@material(blockid=6, data=list(range(16)), transparent=True)
def saplings(self, blockid, data):
# usual saplings
tex = self.load_image_texture("assets/minecraft/textures/block/oak_sapling.png")
@@ -1007,7 +1020,7 @@ block(blockid=7, top_image="assets/minecraft/textures/block/bedrock.png")
# water, glass, and ice (no inner surfaces)
# uses pseudo-ancildata found in iterate.c
@material(blockid=[8, 9, 20, 79, 95], data=range(512), fluid=(8, 9), transparent=True, nospawn=True, solid=(79, 20, 95))
@material(blockid=[8, 9, 20, 79, 95], data=list(range(512)), fluid=(8, 9), transparent=True, nospawn=True, solid=(79, 20, 95))
def no_inner_surfaces(self, blockid, data):
if blockid == 8 or blockid == 9:
texture = self.load_water()
@@ -1054,13 +1067,13 @@ def no_inner_surfaces(self, blockid, data):
img = self.build_full_block(top,None,None,side3,side4)
return img
@material(blockid=[10, 11], data=range(16), fluid=True, transparent=False, nospawn=True)
@material(blockid=[10, 11], data=list(range(16)), fluid=True, transparent=False, nospawn=True)
def lava(self, blockid, data):
lavatex = self.load_lava()
return self.build_block(lavatex, lavatex)
# sand
@material(blockid=12, data=range(2), solid=True)
@material(blockid=12, data=list(range(2)), solid=True)
def sand_blocks(self, blockid, data):
if data == 0: # normal
img = self.build_block(self.load_image_texture("assets/minecraft/textures/block/sand.png"), self.load_image_texture("assets/minecraft/textures/block/sand.png"))
@@ -1077,7 +1090,7 @@ block(blockid=15, top_image="assets/minecraft/textures/block/iron_ore.png")
# coal ore
block(blockid=16, top_image="assets/minecraft/textures/block/coal_ore.png")
@material(blockid=[17,162,11306,11307,11308,11309,11310,11311], data=range(12), solid=True)
@material(blockid=[17,162,11306,11307,11308,11309,11310,11311], data=list(range(12)), solid=True)
def wood(self, blockid, data):
# extract orientation and wood type frorm data bits
wood_type = data & 3
@@ -1191,7 +1204,7 @@ def wood(self, blockid, data):
elif wood_orientation == 8: # north-south orientation
return self.build_full_block(side, None, None, side.rotate(270), top)
@material(blockid=[18, 161], data=range(16), transparent=True, solid=True)
@material(blockid=[18, 161], data=list(range(16)), transparent=True, solid=True)
def leaves(self, blockid, data):
# mask out the bits 4 and 8
# they are used for player placed and check-for-decay blocks
@@ -1217,7 +1230,7 @@ block(blockid=21, top_image="assets/minecraft/textures/block/lapis_ore.png")
block(blockid=22, top_image="assets/minecraft/textures/block/lapis_block.png")
# dispensers, dropper, furnaces, and burning furnaces
@material(blockid=[23, 61, 62, 158], data=range(6), solid=True)
@material(blockid=[23, 61, 62, 158], data=list(range(6)), solid=True)
def furnaces(self, blockid, data):
# first, do the rotation if needed
if self.rotation == 1:
@@ -1266,7 +1279,7 @@ def furnaces(self, blockid, data):
return self.build_full_block(top, None, None, side, side)
# sandstone
@material(blockid=24, data=range(3), solid=True)
@material(blockid=24, data=list(range(3)), solid=True)
def sandstone(self, blockid, data):
top = self.load_image_texture("assets/minecraft/textures/block/sandstone_top.png")
if data == 0: # normal
@@ -1277,7 +1290,7 @@ def sandstone(self, blockid, data):
return self.build_block(top, self.load_image_texture("assets/minecraft/textures/block/cut_sandstone.png"))
# red sandstone
@material(blockid=179, data=range(3), solid=True)
@material(blockid=179, data=list(range(3)), solid=True)
def sandstone(self, blockid, data):
top = self.load_image_texture("assets/minecraft/textures/block/red_sandstone_top.png")
if data == 0: # normal
@@ -1291,7 +1304,7 @@ def sandstone(self, blockid, data):
# note block
block(blockid=25, top_image="assets/minecraft/textures/block/note_block.png")
@material(blockid=26, data=range(12), transparent=True, nospawn=True)
@material(blockid=26, data=list(range(12)), transparent=True, nospawn=True)
def bed(self, blockid, data):
# first get rotation done
# Masked to not clobber block head/foot info
@@ -1381,7 +1394,7 @@ def bed(self, blockid, data):
return self.build_full_block(top_face, None, None, left_face, right_face)
# powered, detector, activator and normal rails
@material(blockid=[27, 28, 66, 157], data=range(14), transparent=True)
@material(blockid=[27, 28, 66, 157], data=list(range(14)), transparent=True)
def rails(self, blockid, data):
# first, do rotation
# Masked to not clobber powered rail on/off info
@@ -1664,7 +1677,7 @@ def piston_extension(self, blockid, data):
# cobweb
sprite(blockid=30, imagename="assets/minecraft/textures/block/cobweb.png", nospawn=True)
@material(blockid=31, data=range(3), transparent=True)
@material(blockid=31, data=list(range(3)), transparent=True)
def tall_grass(self, blockid, data):
if data == 0: # dead shrub
texture = self.load_image_texture("assets/minecraft/textures/block/dead_bush.png")
@@ -1678,7 +1691,7 @@ def tall_grass(self, blockid, data):
# dead bush
billboard(blockid=32, imagename="assets/minecraft/textures/block/dead_bush.png")
@material(blockid=35, data=range(16), solid=True)
@material(blockid=35, data=list(range(16)), solid=True)
def wool(self, blockid, data):
texture = self.load_image_texture("assets/minecraft/textures/block/%s_wool.png" % color_map[data])
@@ -1688,7 +1701,7 @@ def wool(self, blockid, data):
sprite(blockid=37, imagename="assets/minecraft/textures/block/dandelion.png")
# flowers
@material(blockid=38, data=range(10), transparent=True)
@material(blockid=38, data=list(range(10)), transparent=True)
def flower(self, blockid, data):
flower_map = ["poppy", "blue_orchid", "allium", "azure_bluet", "red_tulip", "orange_tulip",
"white_tulip", "pink_tulip", "oxeye_daisy", "dandelion"]
@@ -1708,7 +1721,7 @@ block(blockid=42, top_image="assets/minecraft/textures/block/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, 181, 182, 204, 205], data=range(16), transparent=(44,182,205), solid=True)
@material(blockid=[43, 44, 181, 182, 204, 205], data=list(range(16)), transparent=(44,182,205), solid=True)
def slabs(self, blockid, data):
if blockid == 44 or blockid == 182:
texture = data & 7
@@ -1847,7 +1860,7 @@ def torches(self, blockid, data):
return img
# fire
@material(blockid=51, data=range(16), transparent=True)
@material(blockid=51, data=list(range(16)), transparent=True)
def fire(self, blockid, data):
firetextures = self.load_fire()
side1 = self.transform_image_side(firetextures[0])
@@ -1867,7 +1880,7 @@ def fire(self, blockid, data):
block(blockid=52, top_image="assets/minecraft/textures/block/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,203], 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=list(range(128)), transparent=True, solid=True, nospawn=True)
def stairs(self, blockid, data):
# preserve the upside-down bit
upside_down = data & 0x4
@@ -1991,7 +2004,7 @@ def stairs(self, blockid, data):
# normal, locked (used in april's fool day), ender and trapped chest
# NOTE: locked chest used to be id95 (which is now stained glass)
@material(blockid=[54,130,146], data=range(30), transparent = True)
@material(blockid=[54,130,146], data=list(range(30)), transparent = True)
def chests(self, blockid, data):
# the first 3 bits are the orientation as stored in minecraft,
# bits 0x8 and 0x10 indicate which half of the double chest is it.
@@ -2188,7 +2201,7 @@ def chests(self, blockid, data):
# redstone wire
# uses pseudo-ancildata found in iterate.c
@material(blockid=55, data=range(128), transparent=True)
@material(blockid=55, data=list(range(128)), transparent=True)
def wire(self, blockid, data):
if data & 0b1000000 == 64: # powered redstone wire
@@ -2281,7 +2294,7 @@ def crafting_table(self, blockid, data):
return img
# crops with 8 data values (like wheat)
@material(blockid=59, data=range(8), transparent=True, nospawn=True)
@material(blockid=59, data=list(range(8)), transparent=True, nospawn=True)
def crops8(self, blockid, data):
raw_crop = self.load_image_texture("assets/minecraft/textures/block/wheat_stage%d.png" % data)
crop1 = self.transform_image_top(raw_crop)
@@ -2295,7 +2308,7 @@ def crops8(self, blockid, data):
return img
# farmland and grass path (15/16 blocks)
@material(blockid=[60,208], data=range(9), solid=True)
@material(blockid=[60,208], data=list(range(9)), solid=True)
def farmland(self, blockid, data):
if blockid == 60:
side = self.load_image_texture("assets/minecraft/textures/block/dirt.png")
@@ -2315,7 +2328,7 @@ def farmland(self, blockid, data):
# signposts
@material(blockid=63, data=range(16), transparent=True)
@material(blockid=63, data=list(range(16)), transparent=True)
def signpost(self, blockid, data):
# first rotations
@@ -2369,7 +2382,7 @@ def signpost(self, blockid, data):
# wooden and iron door
# uses pseudo-ancildata found in iterate.c
@material(blockid=[64,71,193,194,195,196,197], data=range(32), transparent=True)
@material(blockid=[64,71,193,194,195,196,197], data=list(range(32)), transparent=True)
def door(self, blockid, data):
#Masked to not clobber block top/bottom & swung info
if self.rotation == 1:
@@ -2618,7 +2631,7 @@ def wall_sign(self, blockid, data): # wall sign
return img
# levers
@material(blockid=69, data=range(16), transparent=True)
@material(blockid=69, data=list(range(16)), transparent=True)
def levers(self, blockid, data):
if data & 8 == 8: powered = True
else: powered = False
@@ -2802,7 +2815,7 @@ def pressure_plate(self, blockid, data):
block(blockid=[73, 74], top_image="assets/minecraft/textures/block/redstone_ore.png")
# stone a wood buttons
@material(blockid=(77,143,11326,11327,11328,11329,11330), data=range(16), transparent=True)
@material(blockid=(77,143,11326,11327,11328,11329,11330), data=list(range(16)), transparent=True)
def buttons(self, blockid, data):
# 0x8 is set if the button is pressed mask this info and render
@@ -2899,7 +2912,7 @@ def buttons(self, blockid, data):
return img
# snow
@material(blockid=78, data=range(16), transparent=True, solid=True)
@material(blockid=78, data=list(range(16)), transparent=True, solid=True)
def snow(self, blockid, data):
# still not rendered correctly: data other than 0
@@ -2926,7 +2939,7 @@ def snow(self, blockid, data):
block(blockid=80, top_image="assets/minecraft/textures/block/snow.png")
# cactus
@material(blockid=81, data=range(15), transparent=True, solid=True, nospawn=True)
@material(blockid=81, data=list(range(15)), transparent=True, solid=True, nospawn=True)
def cactus(self, blockid, data):
top = self.load_image_texture("assets/minecraft/textures/block/cactus_top.png")
side = self.load_image_texture("assets/minecraft/textures/block/cactus_side.png")
@@ -2954,19 +2967,19 @@ def cactus(self, blockid, data):
block(blockid=82, top_image="assets/minecraft/textures/block/clay.png")
# sugar cane
@material(blockid=83, data=range(16), transparent=True)
@material(blockid=83, data=list(range(16)), transparent=True)
def sugar_cane(self, blockid, data):
tex = self.load_image_texture("assets/minecraft/textures/block/sugar_cane.png")
return self.build_sprite(tex)
# jukebox
@material(blockid=84, data=range(16), solid=True)
@material(blockid=84, data=list(range(16)), solid=True)
def jukebox(self, blockid, data):
return self.build_block(self.load_image_texture("assets/minecraft/textures/block/jukebox_top.png"), self.load_image_texture("assets/minecraft/textures/block/note_block.png"))
# nether and normal fences
# uses pseudo-ancildata found in iterate.c
@material(blockid=[85, 188, 189, 190, 191, 192, 113], data=range(16), transparent=True, nospawn=True)
@material(blockid=[85, 188, 189, 190, 191, 192, 113], data=list(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
@@ -3082,7 +3095,7 @@ def fence(self, blockid, data):
return img
# pumpkin
@material(blockid=[86, 91,11300], data=range(4), solid=True)
@material(blockid=[86, 91,11300], data=list(range(4)), solid=True)
def pumpkin(self, blockid, data): # pumpkins, jack-o-lantern
# rotation
if self.rotation == 1:
@@ -3149,7 +3162,7 @@ def portal(self, blockid, data):
return img
# cake!
@material(blockid=92, data=range(6), transparent=True, nospawn=True)
@material(blockid=92, data=list(range(6)), transparent=True, nospawn=True)
def cake(self, blockid, data):
# cake textures
@@ -3273,7 +3286,7 @@ def cake(self, blockid, data):
return img
# redstone repeaters ON and OFF
@material(blockid=[93,94], data=range(16), transparent=True, nospawn=True)
@material(blockid=[93,94], data=list(range(16)), transparent=True, nospawn=True)
def repeater(self, blockid, data):
# rotation
# Masked to not clobber delay info
@@ -3418,7 +3431,7 @@ def repeater(self, blockid, data):
return img
# redstone comparator (149 is inactive, 150 is active)
@material(blockid=[149,150], data=range(16), transparent=True, nospawn=True)
@material(blockid=[149,150], data=list(range(16)), transparent=True, nospawn=True)
def comparator(self, blockid, data):
# rotation
@@ -3483,7 +3496,7 @@ def comparator(self, blockid, data):
# trapdoor
# the trapdoor is looks like a sprite when opened, that's not good
@material(blockid=[96,167,11332,11333,11334,11335,11336], data=range(16), transparent=True, nospawn=True)
@material(blockid=[96,167,11332,11333,11334,11335,11336], data=list(range(16)), transparent=True, nospawn=True)
def trapdoor(self, blockid, data):
# rotation
@@ -3539,7 +3552,7 @@ def trapdoor(self, blockid, data):
return img
# block with hidden silverfish (stone, cobblestone and stone brick)
@material(blockid=97, data=range(3), solid=True)
@material(blockid=97, data=list(range(3)), solid=True)
def hidden_silverfish(self, blockid, data):
if data == 0: # stone
t = self.load_image_texture("assets/minecraft/textures/block/stone.png")
@@ -3553,7 +3566,7 @@ def hidden_silverfish(self, blockid, data):
return img
# stone brick
@material(blockid=98, data=range(4), solid=True)
@material(blockid=98, data=list(range(4)), solid=True)
def stone_brick(self, blockid, data):
if data == 0: # normal
t = self.load_image_texture("assets/minecraft/textures/block/stone_bricks.png")
@@ -3569,7 +3582,7 @@ def stone_brick(self, blockid, data):
return img
# huge brown and red mushroom
@material(blockid=[99,100], data= range(11) + [14,15], solid=True)
@material(blockid=[99,100], data= list(range(11)) + [14,15], solid=True)
def huge_mushroom(self, blockid, data):
# rotation
if self.rotation == 1:
@@ -3653,7 +3666,7 @@ def huge_mushroom(self, blockid, data):
# iron bars and glass pane
# TODO glass pane is not a sprite, it has a texture for the side,
# at the moment is not used
@material(blockid=[101,102, 160], data=range(256), transparent=True, nospawn=True)
@material(blockid=[101,102, 160], data=list(range(256)), transparent=True, nospawn=True)
def panes(self, blockid, data):
# no rotation, uses pseudo data
if blockid == 101:
@@ -3705,7 +3718,7 @@ block(blockid=103, top_image="assets/minecraft/textures/block/melon_top.png", si
# TODO To render it as in game needs from pseudo data and ancil data:
# once fully grown the stem bends to the melon/pumpkin block,
# at the moment only render the growing stem
@material(blockid=[104,105], data=range(8), transparent=True)
@material(blockid=[104,105], data=list(range(8)), transparent=True)
def stem(self, blockid, data):
# the ancildata value indicates how much of the texture
# is shown.
@@ -3725,7 +3738,7 @@ def stem(self, blockid, data):
# vines
@material(blockid=106, data=range(16), transparent=True)
@material(blockid=106, data=list(range(16)), transparent=True)
def vines(self, blockid, data):
# rotation
# vines data is bit coded. decode it first.
@@ -3766,7 +3779,7 @@ def vines(self, blockid, data):
return img
# fence gates
@material(blockid=[107, 183, 184, 185, 186, 187], data=range(8), transparent=True, nospawn=True)
@material(blockid=[107, 183, 184, 185, 186, 187], data=list(range(8)), transparent=True, nospawn=True)
def fence_gate(self, blockid, data):
# rotation
@@ -3870,7 +3883,7 @@ block(blockid=110, top_image="assets/minecraft/textures/block/mycelium_top.png",
# At the moment of writing this lilypads has no ancil data and their
# orientation depends on their position on the map. So it uses pseudo
# ancildata.
@material(blockid=111, data=range(4), transparent=True)
@material(blockid=111, data=list(range(4)), transparent=True)
def lilypad(self, blockid, data):
t = self.load_image_texture("assets/minecraft/textures/block/lily_pad.png").copy()
if data == 0:
@@ -3888,7 +3901,7 @@ def lilypad(self, blockid, data):
block(blockid=112, top_image="assets/minecraft/textures/block/nether_bricks.png")
# nether wart
@material(blockid=115, data=range(4), transparent=True)
@material(blockid=115, data=list(range(4)), transparent=True)
def nether_wart(self, blockid, data):
if data == 0: # just come up
t = self.load_image_texture("assets/minecraft/textures/block/nether_wart_stage0.png")
@@ -3915,7 +3928,7 @@ def enchantment_table(self, blockid, data):
# brewing stand
# TODO this is a place holder, is a 2d image pasted
@material(blockid=117, data=range(5), transparent=True)
@material(blockid=117, data=list(range(5)), transparent=True)
def brewing_stand(self, blockid, data):
base = self.load_image_texture("assets/minecraft/textures/block/brewing_stand_base.png")
img = self.build_full_block(None, None, None, None, None, base)
@@ -3925,7 +3938,7 @@ def brewing_stand(self, blockid, data):
return img
# cauldron
@material(blockid=118, data=range(4), transparent=True)
@material(blockid=118, data=list(range(4)), transparent=True)
def cauldron(self, blockid, data):
side = self.load_image_texture("assets/minecraft/textures/block/cauldron_side.png")
top = self.load_image_texture("assets/minecraft/textures/block/cauldron_top.png")
@@ -3971,7 +3984,7 @@ def end_portal(self, blockid, data):
return img
# end portal frame (data range 8 to get all orientations of filled)
@material(blockid=120, data=range(8), transparent=True)
@material(blockid=120, data=list(range(8)), transparent=True)
def end_portal_frame(self, blockid, data):
# The bottom 2 bits are oritation info but seems there is no
# graphical difference between orientations
@@ -4046,7 +4059,7 @@ def daylight_sensor(self, blockid, data):
# wooden double and normal slabs
# these are the new wooden slabs, blockids 43 44 still have wooden
# slabs, but those are unobtainable without cheating
@material(blockid=[125, 126], data=range(16), transparent=(44,), solid=True)
@material(blockid=[125, 126], data=list(range(16)), transparent=(44,), solid=True)
def wooden_slabs(self, blockid, data):
texture = data & 7
if texture== 0: # oak
@@ -4076,7 +4089,7 @@ block(blockid=129, top_image="assets/minecraft/textures/block/emerald_ore.png")
block(blockid=133, top_image="assets/minecraft/textures/block/emerald_block.png")
# cocoa plant
@material(blockid=127, data=range(12), transparent=True)
@material(blockid=127, data=list(range(12)), transparent=True)
def cocoa_plant(self, blockid, data):
orientation = data & 3
# rotation
@@ -4198,7 +4211,7 @@ def beacon(self, blockid, data):
# cobblestone and mossy cobblestone walls, chorus plants
# one additional bit of data value added for mossy and cobblestone
@material(blockid=[139, 199], data=range(32), transparent=True, nospawn=True)
@material(blockid=[139, 199], data=list(range(32)), transparent=True, nospawn=True)
def cobblestone_wall(self, blockid, data):
# chorus plants
if blockid == 199:
@@ -4329,7 +4342,7 @@ def cobblestone_wall(self, blockid, data):
return img
# carrots, potatoes
@material(blockid=[141,142], data=range(8), transparent=True, nospawn=True)
@material(blockid=[141,142], data=list(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,
@@ -4355,7 +4368,7 @@ def crops4(self, blockid, data):
return img
# anvils
@material(blockid=145, data=range(12), transparent=True)
@material(blockid=145, data=list(range(12)), transparent=True)
def anvil(self, blockid, data):
# anvils only have two orientations, invert it for rotations 1 and 3
@@ -4447,7 +4460,7 @@ block(blockid=152, top_image="assets/minecraft/textures/block/redstone_block.png
block(blockid=153, top_image="assets/minecraft/textures/block/nether_quartz_ore.png")
# block of quartz
@material(blockid=155, data=range(5), solid=True)
@material(blockid=155, data=list(range(5)), solid=True)
def quartz_block(self, blockid, data):
if data in (0,1): # normal and chiseled quartz block
@@ -4475,7 +4488,7 @@ def quartz_block(self, blockid, data):
return self.build_full_block(side.rotate(90), None, None, top, side.rotate(90))
# hopper
@material(blockid=154, data=range(4), transparent=True)
@material(blockid=154, data=list(range(4)), transparent=True)
def hopper(self, blockid, data):
#build the top
side = self.load_image_texture("assets/minecraft/textures/block/hopper_outside.png")
@@ -4502,7 +4515,7 @@ def hopper(self, blockid, data):
block(blockid=165, top_image="assets/minecraft/textures/block/slime_block.png")
# prismarine block
@material(blockid=168, data=range(3), solid=True)
@material(blockid=168, data=list(range(3)), solid=True)
def prismarine_block(self, blockid, data):
if data == 0: # prismarine
@@ -4520,7 +4533,7 @@ def prismarine_block(self, blockid, data):
block(blockid=169, top_image="assets/minecraft/textures/block/sea_lantern.png")
# hay block
@material(blockid=170, data=range(9), solid=True)
@material(blockid=170, data=list(range(9)), solid=True)
def hayblock(self, blockid, data):
top = self.load_image_texture("assets/minecraft/textures/block/hay_block_top.png")
side = self.load_image_texture("assets/minecraft/textures/block/hay_block_side.png")
@@ -4542,7 +4555,7 @@ def hayblock(self, blockid, data):
# carpet - wool block that's small?
@material(blockid=171, data=range(16), transparent=True)
@material(blockid=171, data=list(range(16)), transparent=True)
def carpet(self, blockid, data):
texture = self.load_image_texture("assets/minecraft/textures/block/%s_wool.png" % color_map[data])
@@ -4552,7 +4565,7 @@ def carpet(self, blockid, data):
block(blockid=172, top_image="assets/minecraft/textures/block/terracotta.png")
#stained hardened clay
@material(blockid=159, data=range(16), solid=True)
@material(blockid=159, data=list(range(16)), solid=True)
def stained_clay(self, blockid, data):
texture = self.load_image_texture("assets/minecraft/textures/block/%s_terracotta.png" % color_map[data])
@@ -4586,7 +4599,7 @@ block(blockid=11323, top_image="assets/minecraft/textures/block/dead_fire_coral_
block(blockid=11324, top_image="assets/minecraft/textures/block/dead_horn_coral_block.png")
block(blockid=11325, top_image="assets/minecraft/textures/block/dead_tube_coral_block.png")
@material(blockid=175, data=range(16), transparent=True)
@material(blockid=175, data=list(range(16)), transparent=True)
def flower(self, blockid, data):
double_plant_map = ["sunflower", "lilac", "tall_grass", "large_fern", "rose_bush", "peony", "peony", "peony"]
plant = double_plant_map[data & 0x7]
@@ -4608,7 +4621,7 @@ def flower(self, blockid, data):
return img
# chorus flower
@material(blockid=200, data=range(6), solid=True)
@material(blockid=200, data=list(range(6)), solid=True)
def chorus_flower(self, blockid, data):
# aged 5, dead
if data == 5:
@@ -4622,7 +4635,7 @@ def chorus_flower(self, blockid, data):
block(blockid=201, top_image="assets/minecraft/textures/block/purpur_block.png")
# purpur pilar
@material(blockid=202, data=range(12) , solid=True)
@material(blockid=202, data=list(range(12)) , solid=True)
def purpur_pillar(self, blockid, data):
pillar_orientation = data & 12
top=self.load_image_texture("assets/minecraft/textures/block/purpur_pillar_top.png")
@@ -4639,7 +4652,7 @@ def purpur_pillar(self, blockid, data):
block(blockid=206, top_image="assets/minecraft/textures/block/end_stone_bricks.png")
# frosted ice
@material(blockid=212, data=range(4), solid=True)
@material(blockid=212, data=list(range(4)), solid=True)
def frosted_ice(self, blockid, data):
img = self.load_image_texture("assets/minecraft/textures/block/frosted_ice_%d.png" % data)
return self.build_block(img, img)
@@ -4653,7 +4666,7 @@ block(blockid=214, top_image="assets/minecraft/textures/block/nether_wart_block.
# red nether brick
block(blockid=215, top_image="assets/minecraft/textures/block/red_nether_bricks.png")
@material(blockid=216, data=range(12), solid=True)
@material(blockid=216, data=list(range(12)), solid=True)
def boneblock(self, blockid, data):
# extract orientation
boneblock_orientation = data & 12
@@ -4676,7 +4689,7 @@ def boneblock(self, blockid, data):
return self.build_full_block(side, None, None, side.rotate(270), top)
# observer
@material(blockid=218, data=range(6), solid=True, nospawn=True)
@material(blockid=218, data=list(range(6)), solid=True, nospawn=True)
def observer(self, blockid, data):
# first, do the rotation if needed
if self.rotation == 1:
@@ -4718,7 +4731,7 @@ def observer(self, blockid, data):
return img
# shulker box
@material(blockid=range(219,235), data=range(6), solid=True, nospawn=True)
@material(blockid=list(range(219,235)), data=list(range(6)), solid=True, nospawn=True)
def shulker_box(self, blockid, data):
# first, do the rotation if needed
data = data & 7
@@ -4741,15 +4754,15 @@ def shulker_box(self, blockid, data):
color = color_map[blockid - 219]
shulker_t = self.load_image_texture("assets/minecraft/textures/entity/shulker/shulker_%s.png" % color).copy()
w,h = shulker_t.size
res = w / 4
res = w // 4
# Cut out the parts of the shulker texture we need for the box
top = shulker_t.crop((res,0,res*2,res))
bottom = shulker_t.crop((res*2,int(res*1.75),res*3,int(res*2.75)))
side_top = shulker_t.crop((0,res,res,int(res*1.75)))
side_bottom = shulker_t.crop((0,int(res*2.75),res,int(res*3.25)))
side = Image.new('RGBA', (res,res))
side.paste(side_top, (0,0), side_top)
side.paste(side_bottom, (0,res/2), side_bottom)
top = shulker_t.crop((res, 0, res * 2, res))
bottom = shulker_t.crop((res * 2, int(res * 1.75), res * 3, int(res * 2.75)))
side_top = shulker_t.crop((0, res, res, int(res * 1.75)))
side_bottom = shulker_t.crop((0, int(res * 2.75), res, int(res * 3.25)))
side = Image.new('RGBA', (res, res))
side.paste(side_top, (0, 0), side_top)
side.paste(side_bottom, (0, res // 2), side_bottom)
if data == 0: # down
side = side.rotate(180)
@@ -4768,7 +4781,7 @@ def shulker_box(self, blockid, data):
return img
# structure block
@material(blockid=255, data=range(4), solid=True)
@material(blockid=255, data=list(range(4)), solid=True)
def structure_block(self, blockid, data):
if data == 0:
img = self.load_image_texture("assets/minecraft/textures/block/structure_block_save.png")
@@ -4781,7 +4794,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=list(range(4)), transparent=True, nospawn=True)
def crops(self, blockid, data):
raw_crop = self.load_image_texture("assets/minecraft/textures/block/beetroots_stage%d.png" % data)
crop1 = self.transform_image_top(raw_crop)
@@ -4795,19 +4808,19 @@ def crops(self, blockid, data):
return img
# Concrete
@material(blockid=251, data=range(16), solid=True)
@material(blockid=251, data=list(range(16)), solid=True)
def concrete(self, blockid, data):
texture = self.load_image_texture("assets/minecraft/textures/block/%s_concrete.png" % color_map[data])
return self.build_block(texture, texture)
# Concrete Powder
@material(blockid=252, data=range(16), solid=True)
@material(blockid=252, data=list(range(16)), solid=True)
def concrete(self, blockid, data):
texture = self.load_image_texture("assets/minecraft/textures/block/%s_concrete_powder.png" % color_map[data])
return self.build_block(texture, texture)
# Glazed Terracotta
@material(blockid=range(235,251), data=range(8), solid=True)
@material(blockid=list(range(235,251)), data=list(range(8)), solid=True)
def glazed_terracotta(self, blockid, data):
texture = self.load_image_texture("assets/minecraft/textures/block/%s_glazed_terracotta.png" % color_map[blockid - 235])
glazed_terracotta_orientation = data & 3