0

added the option to specify a list of chunks to update.

This commit is contained in:
Andrew Brown
2010-09-27 00:52:11 -04:00
parent 58202bd779
commit d637ddbbe1
4 changed files with 93 additions and 8 deletions

View File

@@ -17,8 +17,9 @@ import functools
import os
import os.path
import multiprocessing
import numpy
import sys
import numpy
from PIL import Image
import chunk
@@ -85,16 +86,51 @@ class WorldRenderer(object):
"""Renders a world's worth of chunks.
worlddir is the path to the minecraft world
cachedir is the path to a directory that should hold the resulting images.
It may be the same as worlddir (which used to be the default)"""
def __init__(self, worlddir, cachedir):
It may be the same as worlddir (which used to be the default).
If chunklist is given, it is assumed to be an iterator over paths to chunk
files to update. If it includes a trailing newline, it is stripped, so you
can pass in file handles just fine.
"""
def __init__(self, worlddir, cachedir, chunklist=None):
self.worlddir = worlddir
self.caves = False
self.cachedir = cachedir
self.chunklist = chunklist
# stores Points Of Interest to be mapped with markers
# a list of dictionaries, see below for an example
self.POI = []
def _get_chunk_renderset(self):
"""Returns a set of (col, row) chunks that should be rendered. Returns
None if all chunks should be rendered"""
if not self.chunklist:
return None
# Get a list of the (chunks, chunky, filename) from the passed in list
# of filenames
chunklist = []
for path in self.chunklist:
if path.endswith("\n"):
path = path[:-1]
f = os.path.basename(path)
if f and f.startswith("c.") and f.endswith(".dat"):
p = f.split(".")
chunklist.append((base36decode(p[1]), base36decode(p[2]),
path))
# Translate to col, row coordinates
_, _, _, _, chunklist = _convert_coords(chunklist)
# Build a set from the col, row pairs
inclusion_set = set()
for col, row, filename in chunklist:
inclusion_set.add((col, row))
return inclusion_set
def findTrueSpawn(self):
"""Adds the true spawn location to self.POI. The spawn Y coordinate
is almost always the default of 64. Find the first air block above
@@ -157,8 +193,12 @@ class WorldRenderer(object):
Returns a list of (chunkx, chunky, filename) where chunkx and chunky are
given in chunk coordinates. Use convert_coords() to turn the resulting list
into an oblique coordinate system"""
into an oblique coordinate system.
Usually this scans the given worlddir, but will use the chunk list
given to the constructor if one was provided."""
all_chunks = []
for dirpath, dirnames, filenames in os.walk(self.worlddir):
if not dirnames and filenames:
for f in filenames:
@@ -166,6 +206,10 @@ class WorldRenderer(object):
p = f.split(".")
all_chunks.append((base36decode(p[1]), base36decode(p[2]),
os.path.join(dirpath, f)))
if not all_chunks:
print "Error: No chunks found!"
sys.exit(1)
return all_chunks
def _render_chunks_async(self, chunks, processes):
@@ -176,11 +220,25 @@ class WorldRenderer(object):
Returns a dictionary mapping (col, row) to the file where that
chunk is rendered as an image
"""
# The set of chunks to render, or None for all of them. The logic is
# slightly more compliated than it should seem, since we still need to
# build the results dict out of all chunks, even if they're not being
# rendered.
inclusion_set = self._get_chunk_renderset()
results = {}
if processes == 1:
# Skip the multiprocessing stuff
print "Rendering chunks synchronously since you requested 1 process"
for i, (col, row, chunkfile) in enumerate(chunks):
if inclusion_set and (col, row) not in inclusion_set:
# Skip rendering, just find where the existing image is
_, imgpath = chunk.ChunkRenderer(chunkfile,
self.cachedir).find_oldimage(False)
if imgpath:
results[(col, row)] = imgpath
continue
result = chunk.render_and_save(chunkfile, self.cachedir, cave=self.caves)
results[(col, row)] = result
if i > 0:
@@ -191,6 +249,14 @@ class WorldRenderer(object):
pool = multiprocessing.Pool(processes=processes)
asyncresults = []
for col, row, chunkfile in chunks:
if inclusion_set and (col, row) not in inclusion_set:
# Skip rendering, just find where the existing image is
_, imgpath = chunk.ChunkRenderer(chunkfile,
self.cachedir).find_oldimage(False)
if imgpath:
results[(col, row)] = imgpath
continue
result = pool.apply_async(chunk.render_and_save,
args=(chunkfile,self.cachedir),
kwds=dict(cave=self.caves))
@@ -202,7 +268,7 @@ class WorldRenderer(object):
results[(col, row)] = result.get()
if i > 0:
if 1000 % i == 0 or i % 1000 == 0:
print "{0}/{1} chunks rendered".format(i, len(chunks))
print "{0}/{1} chunks rendered".format(i, len(asyncresults))
pool.join()
print "Done!"