0

Merge branch 'master' into dtt-merge

Conflicts:
	chunk.py
This commit is contained in:
Aaron Griffith
2011-03-06 18:05:28 -05:00
5 changed files with 231 additions and 227 deletions

View File

@@ -92,10 +92,10 @@ biome-accurate tinting, the Overviewer can use biome data produced by the
Minecraft Biome Extractor tool. This tool can be downloaded from: Minecraft Biome Extractor tool. This tool can be downloaded from:
http://www.minecraftforum.net/viewtopic.php?f=25&t=80902 http://www.minecraftforum.net/viewtopic.php?f=25&t=80902
If the EXTRACTEDBIOMES folder is present in the world directory, then the If the "biomes" folder is present in the world directory, then the Overviewer
Overviewer will use the biome data to tint grass and leaves automatically -- will use the biome data to tint grass and leaves automatically -- there is no
there is no command line option to turn this feature on. If this folder does command line option to turn this feature on. If this folder does not exist,
not exist, then the Overviewer will use a static tinting for grass and leaves. then the Overviewer will use a static tinting for grass and leaves.
Compiling the C Extension (optional) Compiling the C Extension (optional)
------------------------------------ ------------------------------------

400
chunk.py
View File

@@ -49,7 +49,12 @@ def get_lvldata(filename, x, y):
"""Takes a filename and chunkcoords and returns the Level struct, which contains all the """Takes a filename and chunkcoords and returns the Level struct, which contains all the
level info""" level info"""
d = nbt.load_from_region(filename, x, y) try:
d = nbt.load_from_region(filename, x, y)
except Exception, e:
logging.warning("Error opening chunk (%i, %i) in %s. It may be corrupt. %s", x, y, filename, e)
raise ChunkCorrupt(str(e))
if not d: raise NoSuchChunk(x,y) if not d: raise NoSuchChunk(x,y)
return d[1]['Level'] return d[1]['Level']
@@ -96,21 +101,6 @@ def get_tileentity_data(level):
data = level['TileEntities'] data = level['TileEntities']
return data return data
def iterate_chunkblocks(xoff,yoff):
"""Iterates over the 16x16x128 blocks of a chunk in rendering order.
Yields (x,y,z,imgx,imgy)
x,y,z is the block coordinate in the chunk
imgx,imgy is the image offset in the chunk image where that block should go
"""
for x in xrange(15,-1,-1):
for y in xrange(16):
imgx = xoff + x*12 + y*12
imgy = yoff - x*6 + y*6 + 128*12 + 16*12//2
for z in xrange(128):
yield x,y,z,imgx,imgy
imgy -= 12
# This set holds blocks ids that can be seen through, for occlusion calculations # This set holds blocks ids that can be seen through, for occlusion calculations
transparent_blocks = set([0, 6, 8, 9, 18, 20, 37, 38, 39, 40, 44, 50, 51, 52, 53, 55, transparent_blocks = set([0, 6, 8, 9, 18, 20, 37, 38, 39, 40, 44, 50, 51, 52, 53, 55,
59, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 74, 75, 76, 77, 78, 79, 81, 83, 85]) 59, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 74, 75, 76, 77, 78, 79, 81, 83, 85])
@@ -207,11 +197,8 @@ class ChunkRenderer(object):
try: try:
self._level = get_lvldata(self.regionfile, self.chunkX, self.chunkY) self._level = get_lvldata(self.regionfile, self.chunkX, self.chunkY)
except NoSuchChunk, e: except NoSuchChunk, e:
#logging.debug("Skipping non-existant chunk") logging.debug("Skipping non-existant chunk")
raise raise
except Exception, e:
logging.warning("Error opening chunk file %s. It may be corrupt. %s", self.regionfile, e)
raise ChunkCorrupt(str(e))
return self._level return self._level
level = property(_load_level) level = property(_load_level)
@@ -543,9 +530,9 @@ class ChunkRenderer(object):
if self.world.useBiomeData: if self.world.useBiomeData:
biomeColorData = textures.getBiomeData(self.world.worlddir, biomeColorData = textures.getBiomeData(self.world.worlddir,
self.chunkX, self.chunkY) self.chunkX, self.chunkY)
# in the 8x8 block of biome data, what chunk is this?l # in the 32x32 block of biome data, what chunk is this?l
startX = (self.chunkX - int(math.floor(self.chunkX/8)*8)) startX = self.chunkX % 32
startY = (self.chunkY - int(math.floor(self.chunkY/8)*8)) startY = self.chunkY % 32
# Each block is 24x24 # Each block is 24x24
# The next block on the X axis adds 12px to x and subtracts 6px from y in the image # The next block on the X axis adds 12px to x and subtracts 6px from y in the image
@@ -557,201 +544,214 @@ class ChunkRenderer(object):
if not img: if not img:
img = Image.new("RGBA", (384, 1728), (38,92,255,0)) img = Image.new("RGBA", (384, 1728), (38,92,255,0))
for x,y,z,imgx,imgy in iterate_chunkblocks(xoff,yoff): for x in xrange(15,-1,-1):
# make sure we're drawing within the image boundaries for y in xrange(16):
# 24 == approximate width, height of one block imgx = xoff + x*12 + y*12
if imgx >= img.size[0] + 24 or imgx <= -24: imgy = yoff - x*6 + y*6 + 128*12 + 16*12//2
continue imgy += 12
if imgy >= img.size[1] + 24 or imgy <= -24:
continue
blockid = blocks[x,y,z] # make sure we're drawing within the image boundaries
# 24 == approximate width, height of one block
# the following blocks don't have textures that can be pre-computed from the blockid if imgx >= img.size[0] + 24 or imgx <= -24:
# alone. additional data is required.
# TODO torches, redstone torches, crops, ladders, stairs,
# levers, doors, buttons, and signs all need to be handled here (and in textures.py)
## minecart track, crops, ladder, doors, etc.
if blockid in textures.special_blocks:
# also handle furnaces here, since one side has a different texture than the other
ancilData = blockData_expanded[x,y,z]
try:
if blockid in pseudo_ancildata_blocks:
pseudo_ancilData = self.generate_pseudo_ancildata(x,y,z,blockid)
ancilData = pseudo_ancilData
t = textures.specialblockmap[(blockid, ancilData)]
except KeyError:
t = None
else:
t = textures.blockmap[blockid]
if not t:
continue
if self.world.useBiomeData:
if blockid == 2: #grass
index = biomeColorData[ ((startY*16)+y) * 128 + (startX*16) + x]
c = textures.grasscolor[index]
# only tint the top texture
t = textures.prepareGrassTexture(c)
elif blockid == 18: # leaves
index = biomeColorData[ ((startY*16)+y) * 128 + (startX*16) + x]
c = textures.foliagecolor[index]
t = textures.prepareLeafTexture(c)
# Check if this block is occluded
if cave and (
x == 0 and y != 15 and z != 127
):
# If it's on the x face, only render if there's a
# transparent block in the y+1 direction OR the z-1
# direction
if (
blocks[x,y+1,z] not in transparent_blocks and
blocks[x,y,z+1] not in transparent_blocks
):
continue continue
elif cave and (
y == 15 and x != 0 and z != 127
):
# If it's on the facing y face, only render if there's
# a transparent block in the x-1 direction OR the z-1
# direction
if (
blocks[x-1,y,z] not in transparent_blocks and
blocks[x,y,z+1] not in transparent_blocks
):
continue
elif cave and (
y == 15 and x == 0 and z != 127
):
# If it's on the facing edge, only render if what's
# above it is transparent
if (
blocks[x,y,z+1] not in transparent_blocks
):
continue
elif (left_blocks == None and right_blocks == None):
# Normal block or not cave mode, check sides for
# transparentcy or render if it's a border chunk.
if ( for z in xrange(128):
x != 0 and y != 15 and z != 127 and imgy -= 12
blocks[x-1,y,z] not in transparent_blocks and
blocks[x,y+1,z] not in transparent_blocks and # similar check for y, as above
blocks[x,y,z+1] not in transparent_blocks if imgy >= img.size[1] + 24 or imgy <= -24:
):
continue continue
elif (left_blocks != None and right_blocks == None): blockid = blocks[x,y,z]
if ( # the following blocks don't have textures that can be pre-computed from the blockid
# If it has the left face covered check for # alone. additional data is required.
# transparent blocks in left face # TODO torches, redstone torches, crops, ladders, stairs,
y != 15 and z != 127 and # levers, doors, buttons, and signs all need to be handled here (and in textures.py)
(left_blocks[15,y,z] if x == 0 else blocks[x - 1,y,z]) not in transparent_blocks and
blocks[x,y+1,z] not in transparent_blocks and
blocks[x,y,z+1] not in transparent_blocks
):
continue
elif (left_blocks == None and right_blocks != None): ## minecart track, crops, ladder, doors, etc.
if blockid in textures.special_blocks:
# also handle furnaces here, since one side has a different texture than the other
ancilData = blockData_expanded[x,y,z]
try:
if blockid in pseudo_ancildata_blocks:
if ( pseudo_ancilData = self.generate_pseudo_ancildata(x,y,z,blockid)
# If it has the right face covered check for ancilData = pseudo_ancilData
# transparent blocks in right face t = textures.specialblockmap[(blockid, ancilData)]
x != 0 and z != 127 and except KeyError:
blocks[x-1,y,z] not in transparent_blocks and t = None
(right_blocks[x,0,z] if y == 15 else blocks[x,y + 1,z]) not in transparent_blocks and
blocks[x,y,z+1] not in transparent_blocks
):
continue
elif (
# If it's a interior chunk check for transparent blocks
# in the adjacent chunks.
z != 127 and
(left_blocks[15,y,z] if x == 0 else blocks[x - 1,y,z]) not in transparent_blocks and
(right_blocks[x,0,z] if y == 15 else blocks[x,y + 1,z]) not in transparent_blocks and
blocks[x,y,z+1] not in transparent_blocks
# Don't render if all sides aren't transparent
):
continue
# Draw the actual block on the image. For cave images,
# tint the block with a color proportional to its depth
if cave:
# no lighting for cave -- depth is probably more useful
composite.alpha_over(img, Image.blend(t[0],depth_colors[z],0.3), (imgx, imgy), t[1])
else:
if not self.quadtree.lighting:
# no lighting at all
composite.alpha_over(img, t[0], (imgx, imgy), t[1])
elif blockid in transparent_blocks:
# transparent means draw the whole
# block shaded with the current
# block's light
black_coeff, _ = self.get_lighting_coefficient(x, y, z)
if self.quadtree.spawn and black_coeff > 0.8 and blockid in solid_blocks and not (
blockid in nospawn_blocks or (
z != 127 and (blocks[x,y,z+1] in solid_blocks or blocks[x,y,z+1] in fluid_blocks)
)
):
composite.alpha_over(img, Image.blend(t[0], red_color, black_coeff), (imgx, imgy), t[1])
else: else:
composite.alpha_over(img, Image.blend(t[0], black_color, black_coeff), (imgx, imgy), t[1]) t = textures.blockmap[blockid]
else:
# draw each face lit appropriately,
# but first just draw the block
composite.alpha_over(img, t[0], (imgx, imgy), t[1])
# top face if not t:
black_coeff, face_occlude = self.get_lighting_coefficient(x, y, z + 1) continue
# Use red instead of black for spawnable blocks
if self.quadtree.spawn and black_coeff > 0.8 and blockid in solid_blocks and not ( if self.world.useBiomeData:
blockid in nospawn_blocks or ( # 16 : number of blocks in a chunk (in one direction)
z != 127 and (blocks[x,y,z+1] in solid_blocks or blocks[x,y,z+1] in fluid_blocks) # 32 : number of chunks in a region (and biome file) in one direction
) # so 16 * 32 == 512 : number of blocks in biome file, in one direction
if blockid == 2: #grass
index = biomeColorData[ ((startY*16)+y) * 512 + (startX*16) + x]
c = textures.grasscolor[index]
# only tint the top texture
t = textures.prepareGrassTexture(c)
elif blockid == 18: # leaves
index = biomeColorData[ ((startY*16)+y) * 512 + (startX*16) + x]
c = textures.foliagecolor[index]
t = textures.prepareLeafTexture(c)
# Check if this block is occluded
if cave and (
x == 0 and y != 15 and z != 127
): ):
over_color = red_color # If it's on the x face, only render if there's a
# transparent block in the y+1 direction OR the z-1
# direction
if (
blocks[x,y+1,z] not in transparent_blocks and
blocks[x,y,z+1] not in transparent_blocks
):
continue
elif cave and (
y == 15 and x != 0 and z != 127
):
# If it's on the facing y face, only render if there's
# a transparent block in the x-1 direction OR the z-1
# direction
if (
blocks[x-1,y,z] not in transparent_blocks and
blocks[x,y,z+1] not in transparent_blocks
):
continue
elif cave and (
y == 15 and x == 0 and z != 127
):
# If it's on the facing edge, only render if what's
# above it is transparent
if (
blocks[x,y,z+1] not in transparent_blocks
):
continue
elif (left_blocks == None and right_blocks == None):
# Normal block or not cave mode, check sides for
# transparentcy or render if it's a border chunk.
if (
x != 0 and y != 15 and z != 127 and
blocks[x-1,y,z] not in transparent_blocks and
blocks[x,y+1,z] not in transparent_blocks and
blocks[x,y,z+1] not in transparent_blocks
):
continue
elif (left_blocks != None and right_blocks == None):
if (
# If it has the left face covered check for
# transparent blocks in left face
y != 15 and z != 127 and
(left_blocks[15,y,z] if x == 0 else blocks[x - 1,y,z]) not in transparent_blocks and
blocks[x,y+1,z] not in transparent_blocks and
blocks[x,y,z+1] not in transparent_blocks
):
continue
elif (left_blocks == None and right_blocks != None):
if (
# If it has the right face covered check for
# transparent blocks in right face
x != 0 and z != 127 and
blocks[x-1,y,z] not in transparent_blocks and
(right_blocks[x,0,z] if y == 15 else blocks[x,y + 1,z]) not in transparent_blocks and
blocks[x,y,z+1] not in transparent_blocks
):
continue
elif (
# If it's a interior chunk check for transparent blocks
# in the adjacent chunks.
z != 127 and
(left_blocks[15,y,z] if x == 0 else blocks[x - 1,y,z]) not in transparent_blocks and
(right_blocks[x,0,z] if y == 15 else blocks[x,y + 1,z]) not in transparent_blocks and
blocks[x,y,z+1] not in transparent_blocks
# Don't render if all sides aren't transparent
):
continue
# Draw the actual block on the image. For cave images,
# tint the block with a color proportional to its depth
if cave:
# no lighting for cave -- depth is probably more useful
composite.alpha_over(img, Image.blend(t[0],depth_colors[z],0.3), (imgx, imgy), t[1])
else: else:
over_color = black_color if not self.quadtree.lighting:
# no lighting at all
composite.alpha_over(img, t[0], (imgx, imgy), t[1])
elif blockid in transparent_blocks:
# transparent means draw the whole
# block shaded with the current
# block's light
black_coeff, _ = self.get_lighting_coefficient(x, y, z)
if self.quadtree.spawn and black_coeff > 0.8 and blockid in solid_blocks and not (
blockid in nospawn_blocks or (
z != 127 and (blocks[x,y,z+1] in solid_blocks or blocks[x,y,z+1] in fluid_blocks)
)
):
composite.alpha_over(img, Image.blend(t[0], red_color, black_coeff), (imgx, imgy), t[1])
else:
composite.alpha_over(img, Image.blend(t[0], black_color, black_coeff), (imgx, imgy), t[1])
else:
# draw each face lit appropriately,
# but first just draw the block
composite.alpha_over(img, t[0], (imgx, imgy), t[1])
if not face_occlude: # top face
composite.alpha_over(img, over_color, (imgx, imgy), ImageEnhance.Brightness(facemasks[0]).enhance(black_coeff)) black_coeff, face_occlude = self.get_lighting_coefficient(x, y, z + 1)
# Use red instead of black for spawnable blocks
if self.quadtree.spawn and black_coeff > 0.8 and blockid in solid_blocks and not (
blockid in nospawn_blocks or (
z != 127 and (blocks[x,y,z+1] in solid_blocks or blocks[x,y,z+1] in fluid_blocks)
)
):
over_color = red_color
else:
over_color = black_color
# left face if not face_occlude:
black_coeff, face_occlude = self.get_lighting_coefficient(x - 1, y, z) composite.alpha_over(img, over_color, (imgx, imgy), ImageEnhance.Brightness(facemasks[0]).enhance(black_coeff))
if not face_occlude:
composite.alpha_over(img, over_color, (imgx, imgy), ImageEnhance.Brightness(facemasks[1]).enhance(black_coeff))
# right face # left face
black_coeff, face_occlude = self.get_lighting_coefficient(x, y + 1, z) black_coeff, face_occlude = self.get_lighting_coefficient(x - 1, y, z)
if not face_occlude: if not face_occlude:
composite.alpha_over(img, over_color, (imgx, imgy), ImageEnhance.Brightness(facemasks[2]).enhance(black_coeff)) composite.alpha_over(img, over_color, (imgx, imgy), ImageEnhance.Brightness(facemasks[1]).enhance(black_coeff))
# Draw edge lines # right face
if blockid in (44,): # step block black_coeff, face_occlude = self.get_lighting_coefficient(x, y + 1, z)
increment = 6 if not face_occlude:
elif blockid in (78,): # snow composite.alpha_over(img, over_color, (imgx, imgy), ImageEnhance.Brightness(facemasks[2]).enhance(black_coeff))
increment = 9
else:
increment = 0
if blockid not in transparent_blocks or blockid in (78,): #special case snow so the outline is still drawn # Draw edge lines
draw = ImageDraw.Draw(img) if blockid in (44,): # step block
if x != 15 and blocks[x+1,y,z] == 0: increment = 6
draw.line(((imgx+12,imgy+increment), (imgx+22,imgy+5+increment)), fill=(0,0,0), width=1) elif blockid in (78,): # snow
if y != 0 and blocks[x,y-1,z] == 0: increment = 9
draw.line(((imgx,imgy+6+increment), (imgx+12,imgy+increment)), fill=(0,0,0), width=1) else:
increment = 0
if blockid not in transparent_blocks or blockid in (78,): #special case snow so the outline is still drawn
draw = ImageDraw.Draw(img)
if x != 15 and blocks[x+1,y,z] == 0:
draw.line(((imgx+12,imgy+increment), (imgx+22,imgy+5+increment)), fill=(0,0,0), width=1)
if y != 0 and blocks[x,y-1,z] == 0:
draw.line(((imgx,imgy+6+increment), (imgx+12,imgy+increment)), fill=(0,0,0), width=1)
for entity in tileEntities: for entity in tileEntities:

13
gmap.py
View File

@@ -70,6 +70,13 @@ def main():
if not os.path.exists(worlddir): if not os.path.exists(worlddir):
# world given is either world number, or name # world given is either world number, or name
worlds = world.get_worlds() worlds = world.get_worlds()
# if there are no worlds found at all, exit now
if not worlds:
parser.print_help()
print "\nInvalid world path"
sys.exit(1)
try: try:
worldnum = int(worlddir) worldnum = int(worlddir)
worlddir = worlds[worldnum]['path'] worlddir = worlds[worldnum]['path']
@@ -79,13 +86,13 @@ def main():
worlddir = worlds[worlddir]['path'] worlddir = worlds[worlddir]['path']
except KeyError: except KeyError:
# it's not a number, name, or path # it's not a number, name, or path
print "Invalid world name or path"
parser.print_help() parser.print_help()
print "Invalid world name or path"
sys.exit(1) sys.exit(1)
except KeyError: except KeyError:
# it was an invalid number # it was an invalid number
print "Invalid world number"
parser.print_help() parser.print_help()
print "Invalid world number"
sys.exit(1) sys.exit(1)
if len(args) != 2: if len(args) != 2:
@@ -128,7 +135,7 @@ def main():
if not composite.extension_alpha_over: if not composite.extension_alpha_over:
logging.info("Notice: alpha_over extension not found; using default PIL paste()") logging.info("Notice: alpha_over extension not found; using default PIL paste()")
useBiomeData = os.path.exists(os.path.join(worlddir, 'EXTRACTEDBIOMES')) useBiomeData = os.path.exists(os.path.join(worlddir, 'biomes'))
if not useBiomeData: if not useBiomeData:
logging.info("Notice: Not using biome data for tinting") logging.info("Notice: Not using biome data for tinting")

View File

@@ -120,7 +120,7 @@ class QuadtreeGen(object):
yradius >= worldobj.maxrow and -yradius <= worldobj.minrow: yradius >= worldobj.maxrow and -yradius <= worldobj.minrow:
break break
else: else:
raise ValueError("Your map is waaaay too big!") raise ValueError("Your map is waaaay too big! Use the '-z' or '--zoom' options.")
self.p = p self.p = p
else: else:

View File

@@ -283,7 +283,7 @@ def _build_blockimages():
# 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 # 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
36, 37, 80, -1, 65, 4, 25, -1, 98, 24, 43, -1, 86, -1, -1, -1, # Torch from above? leaving out fire. Redstone wire? Crops/furnaces handled elsewhere. sign post 36, 37, 80, -1, 65, 4, 25, -1, 98, 24, 43, -1, 86, -1, -1, -1, # Torch from above? leaving out fire. Redstone wire? Crops/furnaces handled elsewhere. sign post
# 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 # 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
-1, -1, -1, 16, -1, -1, -1, -1, -1, 51, 51, -1, -1, 1, 66, 67, # door,ladder left out. Minecart rail orientation -1, -1, -1, 16, -1, -1, -1, -1, -1, 51, 51, -1, -1, -1, 66, 67, # door,ladder left out. Minecart rail orientation
# 80 81 82 83 84 85 86 87 88 89 90 91 # 80 81 82 83 84 85 86 87 88 89 90 91
66, 69, 72, 73, 74, -1,102,103,104,105,-1, 102 # clay? 66, 69, 72, 73, 74, -1,102,103,104,105,-1, 102 # clay?
] ]
@@ -300,7 +300,7 @@ def _build_blockimages():
# 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 # 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
36, 37, 80, -1, 65, 4, 25,101, 98, 24, 43, -1, 86, -1, -1, -1, 36, 37, 80, -1, 65, 4, 25,101, 98, 24, 43, -1, 86, -1, -1, -1,
# 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 # 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
-1, -1, -1, 16, -1, -1, -1, -1, -1, 51, 51, -1, -1, 1, 66, 67, -1, -1, -1, 16, -1, -1, -1, -1, -1, 51, 51, -1, -1, -1, 66, 67,
# 80 81 82 83 84 85 86 87 88 89 90 91 # 80 81 82 83 84 85 86 87 88 89 90 91
66, 69, 72, 73, 74,-1 ,118,103,104,105, -1, 118 66, 69, 72, 73, 74,-1 ,118,103,104,105, -1, 118
] ]
@@ -824,9 +824,9 @@ def prepareBiomeData(worlddir):
if grasscolor and foliagecolor: if grasscolor and foliagecolor:
return return
biomeDir = os.path.join(worlddir, "EXTRACTEDBIOMES") biomeDir = os.path.join(worlddir, "biomes")
if not os.path.exists(biomeDir): if not os.path.exists(biomeDir):
raise Exception("EXTRACTEDBIOMES not found") raise Exception("biomes not found")
# try to find the biome color images. If _find_file can't locate them # try to find the biome color images. If _find_file can't locate them
# then try looking in the EXTRACTEDBIOMES folder # then try looking in the EXTRACTEDBIOMES folder
@@ -850,16 +850,13 @@ def getBiomeData(worlddir, chunkX, chunkY):
global currentBiomeFile, currentBiomeData global currentBiomeFile, currentBiomeData
biomeFile = "%d.%d.biome" % ( biomeFile = "b.%d.%d.biome" % (chunkX // 32, chunkY // 32)
int(math.floor(chunkX/8)*8),
int(math.floor(chunkY/8)*8)
)
if biomeFile == currentBiomeFile: if biomeFile == currentBiomeFile:
return currentBiomeData return currentBiomeData
currentBiomeFile = biomeFile currentBiomeFile = biomeFile
f = open(os.path.join(worlddir, "EXTRACTEDBIOMES", biomeFile), "rb") f = open(os.path.join(worlddir, "biomes", biomeFile), "rb")
rawdata = f.read() rawdata = f.read()
f.close() f.close()