add iterator-type counterparts to extractSchematic, extractZipSchematic and copyBlocksFrom to facilitate progress bars. iterators repeatedly yield a tuple of (progress, total). extract methods finally yield the extracted schematic object.

This commit is contained in:
David Vierra 2011-08-13 09:57:59 -10:00
parent 55dc972e22
commit e8870e76e4
3 changed files with 96 additions and 30 deletions

View File

@ -1576,6 +1576,10 @@ class MCInfdevOldLevel(MCLevel):
info(u"Saved {0} chunks".format(dirtyChunkCount)) info(u"Saved {0} chunks".format(dirtyChunkCount))
def generateLights(self, dirtyChunks=None): def generateLights(self, dirtyChunks=None):
for i in generateLightsIter(self, dirtyChunks):
pass
def generateLightsIter(self, dirtyChunks=None):
""" dirtyChunks may be an iterable yielding (xPos,zPos) tuples """ dirtyChunks may be an iterable yielding (xPos,zPos) tuples
if none, generate lights for all chunks that need lighting if none, generate lights for all chunks that need lighting
""" """
@ -1629,13 +1633,16 @@ class MCInfdevOldLevel(MCLevel):
info(u"Using {0} batches to conserve memory.".format(len(chunkLists))) info(u"Using {0} batches to conserve memory.".format(len(chunkLists)))
i = 0 i = 0
for dc in chunkLists: for dc in chunkLists:
i += 1; i += 1;
info(u"Batch {0}/{1}".format(i, len(chunkLists))) info(u"Batch {0}/{1}".format(i, len(chunkLists)))
dc = sorted(dc, key=lambda x:x.chunkPosition) dc = sorted(dc, key=lambda x:x.chunkPosition)
self._generateLights(dc) for j in self._generateLightsIter(dc):
yield j
for ch in dc: for ch in dc:
ch.compress(); ch.compress();
timeDelta = datetime.now() - startTime; timeDelta = datetime.now() - startTime;
@ -1645,7 +1652,7 @@ class MCInfdevOldLevel(MCLevel):
return; return;
def _generateLights(self, dirtyChunks): def _generateLightsIter(self, dirtyChunks):
conserveMemory = False conserveMemory = False
la = array(self.materials.lightAbsorption) la = array(self.materials.lightAbsorption)
@ -1692,6 +1699,8 @@ class MCInfdevOldLevel(MCLevel):
else: else:
lights = ("BlockLight", "SkyLight") lights = ("BlockLight", "SkyLight")
info(u"Dispersing light...") info(u"Dispersing light...")
j = 0
for light in lights: for light in lights:
zerochunkLight = getattr(zeroChunk, light); zerochunkLight = getattr(zeroChunk, light);
@ -1721,6 +1730,8 @@ class MCInfdevOldLevel(MCLevel):
for chunk in dirtyChunks: for chunk in dirtyChunks:
#xxx code duplication #xxx code duplication
yield (j, len(dirtyChunks))
j += 1
(cx, cz) = chunk.chunkPosition (cx, cz) = chunk.chunkPosition
neighboringChunks = {}; neighboringChunks = {};
try: try:
@ -2030,7 +2041,7 @@ class MCInfdevOldLevel(MCLevel):
def copyBlocksFromFinite(self, sourceLevel, sourceBox, destinationPoint, blocksToCopy): def copyBlocksFromFiniteIter(self, sourceLevel, sourceBox, destinationPoint, blocksToCopy):
#assumes destination point and bounds have already been checked. #assumes destination point and bounds have already been checked.
(sx, sy, sz) = sourceBox.origin (sx, sy, sz) = sourceBox.origin
@ -2043,11 +2054,15 @@ class MCInfdevOldLevel(MCLevel):
typemask[blocksToCopy] = 1; typemask[blocksToCopy] = 1;
destChunks = self.getChunkSlices(BoundingBox(destinationPoint, sourceBox.size)) destBox = BoundingBox(destinationPoint, sourceBox.size)
destChunks = self.getChunkSlices(destBox)
i = 0; i = 0;
chunkCount = float(destBox.chunkCount)
for (chunk, slices, point) in destChunks: for (chunk, slices, point) in destChunks:
i += 1; i += 1;
yield (i, chunkCount)
if i % 100 == 0: if i % 100 == 0:
info("Chunk {0}...".format(i)) info("Chunk {0}...".format(i))
@ -2098,19 +2113,21 @@ class MCInfdevOldLevel(MCLevel):
#chunk.compress(); #xxx find out why this trashes changes to tile entities #chunk.compress(); #xxx find out why this trashes changes to tile entities
def copyBlocksFromInfinite(self, sourceLevel, sourceBox, destinationPoint, blocksToCopy): def copyBlocksFromInfiniteIter(self, sourceLevel, sourceBox, destinationPoint, blocksToCopy):
""" copy blocks between two infinite levels via repeated export/import. hilariously slow. """ """ copy blocks between two infinite levels via repeated export/import. hilariously slow. """
#assumes destination point and bounds have already been checked. #assumes destination point and bounds have already been checked.
tempSize = 128 tempSize = 128
dx, dy, dz = destinationPoint
ox, oy, oz = sourceBox.origin
sx, sy, sz = sourceBox.size
mx, my, mz = sourceBox.maximum
def subsectionCount():
return (ox, ox + sx, tempSize) * (oz, oz + sz, tempSize)
def iterateSubsections(): def iterateSubsections():
#tempShape = (tempSize, sourceBox.height, tempSize) #tempShape = (tempSize, sourceBox.height, tempSize)
dx, dy, dz = destinationPoint
ox, oy, oz = sourceBox.origin
sx, sy, sz = sourceBox.size
mx, my, mz = sourceBox.maximum
for x, z in itertools.product(arange(ox, ox + sx, tempSize), arange(oz, oz + sz, tempSize)): for x, z in itertools.product(arange(ox, ox + sx, tempSize), arange(oz, oz + sz, tempSize)):
box = BoundingBox((x, oy, z), (min(tempSize, mx - x), sy, min(tempSize, mz - z))) box = BoundingBox((x, oy, z), (min(tempSize, mx - x), sy, min(tempSize, mz - z)))
destPoint = (dx + x - ox, dy, dz + z - oz) destPoint = (dx + x - ox, dy, dz + z - oz)
@ -2121,9 +2138,13 @@ class MCInfdevOldLevel(MCLevel):
def isChunkBox(box): def isChunkBox(box):
return box.isChunkAligned and box.miny == 0 and box.height == sourceLevel.Height return box.isChunkAligned and box.miny == 0 and box.height == sourceLevel.Height
i = 0
print sourceBox.chunkCount
chunkCount = float(sourceBox.chunkCount)
if isChunkBox(sourceBox) and isChunkBox(destBox): if isChunkBox(sourceBox) and isChunkBox(destBox):
print "Copying with chunk alignment!" print "Copying with chunk alignment!"
cxoffset = destBox.mincx - sourceBox.mincx cxoffset = destBox.mincx - sourceBox.mincx
czoffset = destBox.mincz - sourceBox.mincz czoffset = destBox.mincz - sourceBox.mincz
@ -2132,9 +2153,9 @@ class MCInfdevOldLevel(MCLevel):
typemask[blocksToCopy] = True typemask[blocksToCopy] = True
changedChunks = deque(); changedChunks = deque();
i = 0;
for cx, cz in sourceBox.chunkPositions: for cx, cz in sourceBox.chunkPositions:
i += 1; i += 1
yield (i, chunkCount)
if i % 100 == 0: if i % 100 == 0:
info("Chunk {0}...".format(i)) info("Chunk {0}...".format(i))
@ -2186,15 +2207,21 @@ class MCInfdevOldLevel(MCLevel):
ch.needsLighting = True ch.needsLighting = True
else: else:
i = 0; chunkCount = subsectionCount()
for box, destPoint in iterateSubsections(): for box, destPoint in iterateSubsections():
info("Subsection {0} at {1}".format(i, destPoint)) info("Subsection {0} at {1}".format(i, destPoint))
temp = sourceLevel.extractSchematic(box); temp = sourceLevel.extractSchematic(box);
self.copyBlocksFrom(temp, BoundingBox((0, 0, 0), box.size), destPoint, blocksToCopy); self.copyBlocksFrom(temp, BoundingBox((0, 0, 0), box.size), destPoint, blocksToCopy);
i += 1; i += 1
yield (i, chunkCount)
def copyBlocksFrom(self, sourceLevel, sourceBox, destinationPoint, blocksToCopy=None, entities=True): def copyBlocksFrom(self, sourceLevel, sourceBox, destinationPoint, blocksToCopy=None, entities=True):
for i in self.copyBlocksFromIter(sourceLevel, sourceBox, destinationPoint, blocksToCopy, entities):
pass
def copyBlocksFromIter(self, sourceLevel, sourceBox, destinationPoint, blocksToCopy=None, entities=True):
(x, y, z) = destinationPoint; (x, y, z) = destinationPoint;
(lx, ly, lz) = sourceBox.size (lx, ly, lz) = sourceBox.size
#sourcePoint, sourcePoint1 = sourceBox #sourcePoint, sourcePoint1 = sourceBox
@ -2205,13 +2232,16 @@ class MCInfdevOldLevel(MCLevel):
startTime = datetime.now() startTime = datetime.now()
if(not isinstance(sourceLevel, MCInfdevOldLevel)): if(not isinstance(sourceLevel, MCInfdevOldLevel)):
self.copyBlocksFromFinite(sourceLevel, sourceBox, destinationPoint, blocksToCopy) for i in self.copyBlocksFromFiniteIter(sourceLevel, sourceBox, destinationPoint, blocksToCopy):
yield i
else: else:
self.copyBlocksFromInfinite(sourceLevel, sourceBox, destinationPoint, blocksToCopy) for i in self.copyBlocksFromInfiniteIter(sourceLevel, sourceBox, destinationPoint, blocksToCopy):
yield i
self.copyEntitiesFrom(sourceLevel, sourceBox, destinationPoint, entities) for i in self.copyEntitiesFromIter(sourceLevel, sourceBox, destinationPoint, entities):
yield i
info("Duration: {0}".format(datetime.now() - startTime)) info("Duration: {0}".format(datetime.now() - startTime))
#self.saveInPlace() #self.saveInPlace()

View File

@ -526,7 +526,12 @@ class MCLevel(object):
return sourceBox, destinationPoint return sourceBox, destinationPoint
def copyBlocksFrom(self, sourceLevel, sourceBox, destinationPoint, blocksToCopy=None, entities=True): def copyBlocksFrom(self, sourceLevel, sourceBox, destinationPoint, blocksToCopy=None, entities=True):
for i in self.copyBlocksFromIter(sourceLevel, sourceBox, destinationPoint, blocksToCopy, entities):
pass
def copyBlocksFromIter(self, sourceLevel, sourceBox, destinationPoint, blocksToCopy=None, entities=True):
if (not sourceLevel.isInfinite) and not( if (not sourceLevel.isInfinite) and not(
sourceLevel.containsPoint(*sourceBox.origin) and sourceLevel.containsPoint(*sourceBox.origin) and
sourceLevel.containsPoint(*map(lambda x:x - 1, sourceBox.maximum))): sourceLevel.containsPoint(*map(lambda x:x - 1, sourceBox.maximum))):
@ -546,11 +551,12 @@ class MCLevel(object):
else: else:
self.copyBlocksFromInfinite(sourceLevel, sourceBox, destinationPoint, blocksToCopy) self.copyBlocksFromInfinite(sourceLevel, sourceBox, destinationPoint, blocksToCopy)
self.copyEntitiesFrom(sourceLevel, sourceBox, destinationPoint, entities) for i in self.copyEntitiesFromIter(sourceLevel, sourceBox, destinationPoint, entities):
yield i
def saveInPlace(self): def saveInPlace(self):
self.saveToFile(self.filename); self.saveToFile(self.filename);
@classmethod
def setPlayerPosition(self, pos, player="Player"): def setPlayerPosition(self, pos, player="Player"):
pass; pass;
@ -574,9 +580,10 @@ class MCLevel(object):
return (-45., 0.) return (-45., 0.)
def copyEntitiesFromInfinite(self, sourceLevel, sourceBox, destinationPoint): def copyEntitiesFromInfiniteIter(self, sourceLevel, sourceBox, destinationPoint):
chunkIterator = sourceLevel.getChunkSlices(sourceBox); chunkIterator = sourceLevel.getChunkSlices(sourceBox);
chunkCount = sourceBox.chunkCount
i = 0
for (chunk, slices, point) in chunkIterator: for (chunk, slices, point) in chunkIterator:
#remember, slices are ordered x,z,y so you can subscript them like so: chunk.Blocks[slices] #remember, slices are ordered x,z,y so you can subscript them like so: chunk.Blocks[slices]
cx, cz = chunk.chunkPosition cx, cz = chunk.chunkPosition
@ -602,16 +609,22 @@ class MCLevel(object):
self.addTileEntity(eTag) self.addTileEntity(eTag)
chunk.compress(); chunk.compress();
yield float(i) / float(chunkCount)
i += 1
def copyEntitiesFrom(self, sourceLevel, sourceBox, destinationPoint, entities=True): def copyEntitiesFrom(self, sourceLevel, sourceBox, destinationPoint, entities=True):
for i in self.copyEntitiesFromIter(sourceLevel, sourceBox, destinationPoint, entities):
pass
def copyEntitiesFromIter(self, sourceLevel, sourceBox, destinationPoint, entities=True):
#assume coords have already been adjusted by copyBlocks #assume coords have already been adjusted by copyBlocks
if not self.hasEntities or not sourceLevel.hasEntities: return; if not self.hasEntities or not sourceLevel.hasEntities: return;
sourcePoint0 = sourceBox.origin; sourcePoint0 = sourceBox.origin;
sourcePoint1 = sourceBox.maximum; sourcePoint1 = sourceBox.maximum;
if sourceLevel.isInfinite: if sourceLevel.isInfinite:
self.copyEntitiesFromInfinite(sourceLevel, sourceBox, destinationPoint) for i in self.copyEntitiesFromInfiniteIter(sourceLevel, sourceBox, destinationPoint):
yield i
else: else:
entsCopied = 0; entsCopied = 0;
tileEntsCopied = 0; tileEntsCopied = 0;
@ -623,8 +636,12 @@ class MCLevel(object):
self.addEntity(eTag) self.addEntity(eTag)
entsCopied += 1; entsCopied += 1;
i = 0
for entity in getTileEntitiesInRange(sourceBox, sourceLevel.TileEntities): for entity in getTileEntitiesInRange(sourceBox, sourceLevel.TileEntities):
i += 1
if i % 100 == 0:
yield
if not 'x' in entity: continue if not 'x' in entity: continue
eTag = TileEntity.copyWithOffset(entity, copyOffset) eTag = TileEntity.copyWithOffset(entity, copyOffset)
@ -633,6 +650,8 @@ class MCLevel(object):
tileEntsCopied += 1; tileEntsCopied += 1;
except ChunkNotPresent: except ChunkNotPresent:
pass pass
yield
debug(u"Copied {0} entities, {1} tile entities".format(entsCopied, tileEntsCopied)) debug(u"Copied {0} entities, {1} tile entities".format(entsCopied, tileEntsCopied))
@ -671,6 +690,8 @@ class MCLevel(object):
def generateLights(self, dirtyChunks=None): def generateLights(self, dirtyChunks=None):
pass; pass;
def generateLightsIter(self, dirtyChunks=None):
yield 0
def adjustExtractionParameters(self, box): def adjustExtractionParameters(self, box):
x, y, z = box.origin x, y, z = box.origin

View File

@ -459,20 +459,32 @@ class INVEditChest(MCSchematic):
def extractSchematicFrom(sourceLevel, box, entities=True): def extractSchematicFrom(sourceLevel, box, entities=True):
for i in extractSchematicFromIter(sourceLevel, box, entities):
pass
return i
def extractSchematicFromIter(sourceLevel, box, entities=True):
p = sourceLevel.adjustExtractionParameters(box); p = sourceLevel.adjustExtractionParameters(box);
if p is None: return if p is None: return
newbox, destPoint = p newbox, destPoint = p
tempSchematic = MCSchematic(shape=box.size) tempSchematic = MCSchematic(shape=box.size)
tempSchematic.materials = sourceLevel.materials tempSchematic.materials = sourceLevel.materials
tempSchematic.copyBlocksFrom(sourceLevel, newbox, destPoint, entities=entities) for i in tempSchematic.copyBlocksFromIter(sourceLevel, newbox, destPoint, entities=entities):
yield i
return tempSchematic yield tempSchematic
MCLevel.extractSchematic = extractSchematicFrom MCLevel.extractSchematic = extractSchematicFrom
MCLevel.extractSchematicIter = extractSchematicFromIter
import tempfile import tempfile
def extractZipSchematicFrom(sourceLevel, box, zipfilename=None, entities=True): def extractZipSchematicFrom(sourceLevel, box, zipfilename=None, entities=True):
for i in extractZipSchematicFromIter(sourceLevel, box, zipfilename, entities):
pass
return i
def extractZipSchematicFromIter(sourceLevel, box, zipfilename=None, entities=True):
#converts classic blocks to alpha #converts classic blocks to alpha
#probably should only apply to alpha levels #probably should only apply to alpha levels
@ -498,13 +510,15 @@ def extractZipSchematicFrom(sourceLevel, box, zipfilename=None, entities=True):
destChunks = destBox.chunkPositions destChunks = destBox.chunkPositions
chunkIter = itertools.izip(chunks, destChunks) chunkIter = itertools.izip(chunks, destChunks)
chunks = (x[1] for x in chunkIter if sourceLevel.containsChunk(*x[0])) for i, (src, chunk) in enumerate(chunkIter):
tempSchematic.createChunks(chunks) if sourceLevel.containsChunk(*src):
tempSchematic.createChunk(*chunk)
yield i, sourceBox.chunkCount
else: else:
tempSchematic.createChunksInBox(destBox) tempSchematic.createChunksInBox(destBox)
tempSchematic.copyBlocksFrom(sourceLevel, sourceBox, destPoint, entities=entities) for i in tempSchematic.copyBlocksFromIter(sourceLevel, sourceBox, destPoint, entities=entities):
yield i
tempSchematic.saveInPlace(); #lights not needed for this format - crashes minecraft though tempSchematic.saveInPlace(); #lights not needed for this format - crashes minecraft though
schematicDat = TAG_Compound() schematicDat = TAG_Compound()
@ -520,9 +534,10 @@ def extractZipSchematicFrom(sourceLevel, box, zipfilename=None, entities=True):
import shutil import shutil
shutil.rmtree(filename) shutil.rmtree(filename)
import mclevel import mclevel
return mclevel.fromFile(zipfilename) yield mclevel.fromFile(zipfilename)
MCLevel.extractZipSchematic = extractZipSchematicFrom MCLevel.extractZipSchematic = extractZipSchematicFrom
MCLevel.extractZipSchematicIter = extractZipSchematicFromIter
from zipfile import ZipFile, ZIP_STORED from zipfile import ZipFile, ZIP_STORED
def zipdir(basedir, archivename): def zipdir(basedir, archivename):