0

Performance improvements on update scan

This commit is contained in:
Xon
2011-03-19 02:50:44 +08:00
parent 08597ab1c0
commit 383e8197af
6 changed files with 99 additions and 104 deletions

View File

@@ -371,16 +371,16 @@ class ChunkRenderer(object):
# and finally check for a block with same blockid. I we aren't in the border of a chunk,
# check for the block having the sme blockid.
if (up_right_blocks != None and up_right_blocks[0,y,z] == blockid) if x == 15 else blocks[x+1,y,z] == blockid:
if (up_right_blocks is not None and up_right_blocks[0,y,z] == blockid) if x == 15 else blocks[x+1,y,z] == blockid:
pseudo_data = pseudo_data | 0b1000
if (right_blocks != None and right_blocks[x,0,z] == blockid) if y == 15 else blocks[x,y + 1,z] == blockid:
if (right_blocks is not None and right_blocks[x,0,z] == blockid) if y == 15 else blocks[x,y + 1,z] == blockid:
pseudo_data = pseudo_data | 0b0100
if (left_blocks != None and left_blocks[15,y,z] == blockid) if x == 0 else blocks[x - 1,y,z] == blockid:
if (left_blocks is not None and left_blocks[15,y,z] == blockid) if x == 0 else blocks[x - 1,y,z] == blockid:
pseudo_data = pseudo_data | 0b0010
if (up_left_blocks != None and up_left_blocks[x,15,z] == blockid) if y == 0 else blocks[x,y - 1,z] == blockid:
if (up_left_blocks is not None and up_left_blocks[x,15,z] == blockid) if y == 0 else blocks[x,y - 1,z] == blockid:
pseudo_data = pseudo_data | 0b0001
# rotate the bits for other north orientations
@@ -443,7 +443,7 @@ class ChunkRenderer(object):
# make sure we have a correctly-ranged coordinates and enough
# info about the chunk
if not (blocks != None and skylight != None and blocklight != None and
if not (blocks is not None and skylight is not None and blocklight is not None and
local_x >= 0 and local_x < 16 and local_y >= 0 and local_y < 16 and
local_z >= 0 and local_z < 128):
# we have no useful info, return default

View File

@@ -36,11 +36,11 @@ def alpha_over(dest, src, pos_or_rect=(0, 0), mask=None):
either be a position or a rectangle, specifying where on dest to
put src. Falls back to dest.paste() if the alpha_over extension
can't be found."""
if mask == None:
if mask is None:
mask = src
global extension_alpha_over
if extension_alpha_over != None:
if extension_alpha_over is not None:
# extension ALWAYS expects rects, so convert if needed
if len(pos_or_rect) == 2:
pos_or_rect = (pos_or_rect[0], pos_or_rect[1], src.size[0], src.size[1])

View File

@@ -26,6 +26,7 @@ import logging
import util
import cPickle
import stat
import errno
from time import gmtime, strftime, sleep
from PIL import Image
@@ -438,7 +439,7 @@ class QuadtreeGen(object):
# return (col, row, chunkx, chunky, regionpath)
chunkx, chunky = self.world.unconvert_coords(col, row)
c = self.world.get_region_path(chunkx, chunky)
if os.path.exists(c):
if c is not None:
chunklist.append((col, row, chunkx, chunky, c))
return chunklist
@@ -451,53 +452,38 @@ def render_innertile(dest, name, imgformat, optimizeimg):
imgpath = os.path.join(dest, name) + "." + imgformat
if name == "base":
q0path = os.path.join(dest, "0." + imgformat)
q1path = os.path.join(dest, "1." + imgformat)
q2path = os.path.join(dest, "2." + imgformat)
q3path = os.path.join(dest, "3." + imgformat)
quadPath = [[(0,0),os.path.join(dest, "0." + imgformat)],[(192,0),os.path.join(dest, "1." + imgformat)], [(0, 192),os.path.join(dest, "2." + imgformat)],[(192,192),os.path.join(dest, "3." + imgformat)]]
else:
q0path = os.path.join(dest, name, "0." + imgformat)
q1path = os.path.join(dest, name, "1." + imgformat)
q2path = os.path.join(dest, name, "2." + imgformat)
q3path = os.path.join(dest, name, "3." + imgformat)
quadPath = [[(0,0),os.path.join(dest, name, "0." + imgformat)],[(192,0),os.path.join(dest, name, "1." + imgformat)],[(0, 192),os.path.join(dest, name, "2." + imgformat)],[(192,192),os.path.join(dest, name, "3." + imgformat)]]
# Check which ones exist
if not os.path.exists(q0path):
q0path = None
if not os.path.exists(q1path):
q1path = None
if not os.path.exists(q2path):
q2path = None
if not os.path.exists(q3path):
q3path = None
#stat the tile, we need to know if it exists or it's mtime
try:
tile_mtime = os.stat(imgpath)[stat.ST_MTIME];
except OSError, e:
if e.errno != errno.ENOENT:
raise
tile_mtime = None
#check mtimes on each part of the quad, this also checks if they exist
needs_rerender = tile_mtime is None
quadPath_filtered = []
for path in quadPath:
try:
quad_mtime = os.stat(path[1])[stat.ST_MTIME];
quadPath_filtered.append(path)
if quad_mtime > tile_mtime:
needs_rerender = True
except OSError:
# We need to stat all the quad files, so keep looping
pass
# do they all not exist?
if not (q0path or q1path or q2path or q3path):
if os.path.exists(imgpath):
if quadPath_filtered == []:
if tile_mtime is not None:
os.unlink(imgpath)
return
# check the mtimes
try:
tile_mtime = os.path.getmtime(imgpath)
needs_rerender = False
# remove non-existant paths
components = [q0path, q1path, q2path, q3path]
components = filter(lambda p: p != None, components)
for mtime in [os.path.getmtime(path) for path in components]:
if mtime > tile_mtime:
needs_rerender = True
break
# quit now if we don't need rerender
if not needs_rerender:
return
except OSError:
# one of our mtime calls failed, so we'll continue
pass
# quit now if we don't need rerender
if not needs_rerender:
return
#logging.debug("writing out innertile {0}".format(imgpath))
# Create the actual image now
@@ -506,30 +492,12 @@ def render_innertile(dest, name, imgformat, optimizeimg):
# we'll use paste (NOT alpha_over) for quadtree generation because
# this is just straight image stitching, not alpha blending
if q0path:
for path in quadPath_filtered:
try:
quad0 = Image.open(q0path).resize((192,192), Image.ANTIALIAS)
img.paste(quad0, (0,0))
quad = Image.open(path[1]).resize((192,192), Image.ANTIALIAS)
img.paste(quad, path[0])
except Exception, e:
logging.warning("Couldn't open %s. It may be corrupt, you may need to delete it. %s", q0path, e)
if q1path:
try:
quad1 = Image.open(q1path).resize((192,192), Image.ANTIALIAS)
img.paste(quad1, (192,0))
except Exception, e:
logging.warning("Couldn't open %s. It may be corrupt, you may need to delete it. %s", q1path, e)
if q2path:
try:
quad2 = Image.open(q2path).resize((192,192), Image.ANTIALIAS)
img.paste(quad2, (0, 192))
except Exception, e:
logging.warning("Couldn't open %s. It may be corrupt, you may need to delete it. %s", q2path, e)
if q3path:
try:
quad3 = Image.open(q3path).resize((192,192), Image.ANTIALIAS)
img.paste(quad3, (192, 192))
except Exception, e:
logging.warning("Couldn't open %s. It may be corrupt, you may need to delete it. %s", q3path, e)
logging.warning("Couldn't open %s. It may be corrupt, you may need to delete it. %s", path[1], e)
# Save it
if imgformat == 'jpg':
@@ -594,12 +562,20 @@ def render_worldtile(quadtree, chunks, colstart, colend, rowstart, rowend, path)
_, _, chunkx, chunky, region = chunk
with open(region, 'rb') as region:
r = nbt.MCRFileReader(region)
return r.load_chunk(chunkx, chunky) != None
return r.chunkExists(chunkx, chunky)
chunks = filter(chunk_exists, chunks)
#stat the file, we need to know if it exists or it's mtime
try:
tile_mtime = os.stat(imgpath)[stat.ST_MTIME];
except OSError, e:
if e.errno != errno.ENOENT:
raise
tile_mtime = None
if not chunks:
# No chunks were found in this tile
if os.path.exists(imgpath):
if tile_mtime is not None:
os.unlink(imgpath)
return None
@@ -612,17 +588,22 @@ def render_worldtile(quadtree, chunks, colstart, colend, rowstart, rowend, path)
# Ignore errno EEXIST: file exists. Since this is multithreaded,
# two processes could conceivably try and create the same directory
# at the same time.
import errno
if e.errno != errno.EEXIST:
raise
# check chunk mtimes to see if they are newer
try:
tile_mtime = os.path.getmtime(imgpath)
#tile_mtime = os.path.getmtime(imgpath)
regionMtimes = {}
needs_rerender = False
for col, row, chunkx, chunky, regionfile in chunks:
# check region file mtime first
if os.path.getmtime(regionfile) <= tile_mtime:
# check region file mtime first.
# Note: we cache the value since it's actually very likely we will have multipule chunks in the same region, and syscalls are expensive
regionMtime = regionMtimes.get(regionfile,None)
if regionMtime is None:
regionMtime = os.path.getmtime(regionfile)
regionMtimes[regionfile] = regionMtime
if regionMtime <= tile_mtime:
continue
# checking chunk mtime

View File

@@ -23,7 +23,7 @@ setup_kwargs['cmdclass'] = {}
# py2exe options
#
if py2exe != None:
if py2exe is not None:
setup_kwargs['console'] = ['gmap.py']
setup_kwargs['data_files'] = [('textures', ['textures/lava.png', 'textures/water.png', 'textures/fire.png']),
('', ['config.js', 'COPYING.txt', 'README.rst']),

View File

@@ -878,15 +878,16 @@ def getBiomeData(worlddir, chunkX, chunkY):
if biomeFile == currentBiomeFile:
return currentBiomeData
f = open(os.path.join(worlddir, "biomes", biomeFile), "rb")
rawdata = f.read()
f.close()
# make sure the file size is correct
if not len(rawdata) == 512 * 512 * 2:
raise Exception("Biome file %s is not valid." % (biomeFile,))
data = numpy.frombuffer(rawdata, dtype=numpy.dtype(">u2"))
try:
with open(os.path.join(worlddir, "biomes", biomeFile), "rb") as f:
rawdata = f.read()
# make sure the file size is correct
if not len(rawdata) == 512 * 512 * 2:
raise Exception("Biome file %s is not valid." % (biomeFile,))
data = numpy.frombuffer(rawdata, dtype=numpy.dtype(">u2"))
except IOError:
data = None
pass # no biome data
currentBiomeFile = biomeFile
currentBiomeData = data

View File

@@ -67,10 +67,16 @@ class World(object):
mincol = maxcol = minrow = maxrow = 0
def __init__(self, worlddir, useBiomeData=False):
def __init__(self, worlddir, useBiomeData=False,regionlist=None):
self.worlddir = worlddir
self.useBiomeData = useBiomeData
#find region files, or load the region list
regionfiles = {}
for x, y, regionfile in self._iterate_regionfiles():
regionfiles[(x,y)] = (x,y,regionfile)
self.regionfiles = regionfiles
# figure out chunk format is in use
# if not mcregion, error out early
data = nbt.load(os.path.join(self.worlddir, "level.dat"))[1]['Data']
@@ -102,10 +108,8 @@ class World(object):
def get_region_path(self, chunkX, chunkY):
"""Returns the path to the region that contains chunk (chunkX, chunkY)
"""
chunkFile = "region/r.%s.%s.mcr" % (chunkX//32, chunkY//32)
return os.path.join(self.worlddir, chunkFile)
_, _, regionfile = self.regionfiles.get((chunkX//32, chunkY//32),(None,None,None));
return regionfile
def convert_coords(self, chunkx, chunky):
"""Takes a coordinate (chunkx, chunky) where chunkx and chunky are
@@ -168,7 +172,7 @@ class World(object):
# find the dimensions of the map, in region files
minx = maxx = miny = maxy = 0
found_regions = False
for x, y, regionfile in self._iterate_regionfiles():
for x, y in self.regionfiles:
found_regions = True
minx = min(minx, x)
maxx = max(maxx, x)
@@ -203,18 +207,27 @@ class World(object):
self.findTrueSpawn()
def _iterate_regionfiles(self):
def _iterate_regionfiles(self,regionlist=None):
"""Returns an iterator of all of the region files, along with their
coordinates
Returns (regionx, regiony, filename)"""
for dirpath, dirnames, filenames in os.walk(os.path.join(self.worlddir, 'region')):
if not dirnames and filenames and "DIM-1" not in dirpath:
for f in filenames:
if f.startswith("r.") and f.endswith(".mcr"):
p = f.split(".")
yield (int(p[1]), int(p[2]), os.path.join(dirpath, f))
join = os.path.join
if regionlist is not None:
for path in regionlist:
if path.endswith("\n"):
path = path[:-1]
f = os.path.basename(path)
if f.startswith("r.") and f.endswith(".mcr"):
p = f.split(".")
yield (int(p[1]), int(p[2]), join(self.worlddir, 'region', f))
else:
for dirpath, dirnames, filenames in os.walk(os.path.join(self.worlddir, 'region')):
if not dirnames and filenames and "DIM-1" not in dirpath:
for f in filenames:
if f.startswith("r.") and f.endswith(".mcr"):
p = f.split(".")
yield (int(p[1]), int(p[2]), join(dirpath, f))
def get_save_dir():
"""Returns the path to the local saves directory