Performance improvements on update scan
This commit is contained in:
10
chunk.py
10
chunk.py
@@ -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
|
||||
|
||||
@@ -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])
|
||||
|
||||
115
quadtree.py
115
quadtree.py
@@ -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
|
||||
|
||||
#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
|
||||
|
||||
2
setup.py
2
setup.py
@@ -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']),
|
||||
|
||||
@@ -878,15 +878,16 @@ def getBiomeData(worlddir, chunkX, chunkY):
|
||||
if biomeFile == currentBiomeFile:
|
||||
return currentBiomeData
|
||||
|
||||
f = open(os.path.join(worlddir, "biomes", biomeFile), "rb")
|
||||
try:
|
||||
with open(os.path.join(worlddir, "biomes", biomeFile), "rb") as f:
|
||||
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"))
|
||||
except IOError:
|
||||
data = None
|
||||
pass # no biome data
|
||||
|
||||
currentBiomeFile = biomeFile
|
||||
currentBiomeData = data
|
||||
|
||||
31
world.py
31
world.py
@@ -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)"""
|
||||
|
||||
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]), os.path.join(dirpath, f))
|
||||
yield (int(p[1]), int(p[2]), join(dirpath, f))
|
||||
|
||||
def get_save_dir():
|
||||
"""Returns the path to the local saves directory
|
||||
|
||||
Reference in New Issue
Block a user