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))
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
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)))
i = 0
for dc in chunkLists:
i += 1;
info(u"Batch {0}/{1}".format(i, len(chunkLists)))
dc = sorted(dc, key=lambda x:x.chunkPosition)
self._generateLights(dc)
for j in self._generateLightsIter(dc):
yield j
for ch in dc:
ch.compress();
timeDelta = datetime.now() - startTime;
@ -1645,7 +1652,7 @@ class MCInfdevOldLevel(MCLevel):
return;
def _generateLights(self, dirtyChunks):
def _generateLightsIter(self, dirtyChunks):
conserveMemory = False
la = array(self.materials.lightAbsorption)
@ -1692,6 +1699,8 @@ class MCInfdevOldLevel(MCLevel):
else:
lights = ("BlockLight", "SkyLight")
info(u"Dispersing light...")
j = 0
for light in lights:
zerochunkLight = getattr(zeroChunk, light);
@ -1721,6 +1730,8 @@ class MCInfdevOldLevel(MCLevel):
for chunk in dirtyChunks:
#xxx code duplication
yield (j, len(dirtyChunks))
j += 1
(cx, cz) = chunk.chunkPosition
neighboringChunks = {};
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.
(sx, sy, sz) = sourceBox.origin
@ -2043,11 +2054,15 @@ class MCInfdevOldLevel(MCLevel):
typemask[blocksToCopy] = 1;
destChunks = self.getChunkSlices(BoundingBox(destinationPoint, sourceBox.size))
destBox = BoundingBox(destinationPoint, sourceBox.size)
destChunks = self.getChunkSlices(destBox)
i = 0;
chunkCount = float(destBox.chunkCount)
for (chunk, slices, point) in destChunks:
i += 1;
yield (i, chunkCount)
if i % 100 == 0:
info("Chunk {0}...".format(i))
@ -2098,19 +2113,21 @@ class MCInfdevOldLevel(MCLevel):
#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. """
#assumes destination point and bounds have already been checked.
tempSize = 128
def iterateSubsections():
#tempShape = (tempSize, sourceBox.height, tempSize)
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():
#tempShape = (tempSize, sourceBox.height, 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)))
destPoint = (dx + x - ox, dy, dz + z - oz)
@ -2121,9 +2138,13 @@ class MCInfdevOldLevel(MCLevel):
def isChunkBox(box):
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):
print "Copying with chunk alignment!"
cxoffset = destBox.mincx - sourceBox.mincx
czoffset = destBox.mincz - sourceBox.mincz
@ -2132,9 +2153,9 @@ class MCInfdevOldLevel(MCLevel):
typemask[blocksToCopy] = True
changedChunks = deque();
i = 0;
for cx, cz in sourceBox.chunkPositions:
i += 1;
i += 1
yield (i, chunkCount)
if i % 100 == 0:
info("Chunk {0}...".format(i))
@ -2186,15 +2207,21 @@ class MCInfdevOldLevel(MCLevel):
ch.needsLighting = True
else:
i = 0;
chunkCount = subsectionCount()
for box, destPoint in iterateSubsections():
info("Subsection {0} at {1}".format(i, destPoint))
temp = sourceLevel.extractSchematic(box);
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):
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;
(lx, ly, lz) = sourceBox.size
#sourcePoint, sourcePoint1 = sourceBox
@ -2205,13 +2232,16 @@ class MCInfdevOldLevel(MCLevel):
startTime = datetime.now()
if(not isinstance(sourceLevel, MCInfdevOldLevel)):
self.copyBlocksFromFinite(sourceLevel, sourceBox, destinationPoint, blocksToCopy)
for i in self.copyBlocksFromFiniteIter(sourceLevel, sourceBox, destinationPoint, blocksToCopy):
yield i
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))
#self.saveInPlace()

View File

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

View File

@ -459,20 +459,32 @@ class INVEditChest(MCSchematic):
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);
if p is None: return
newbox, destPoint = p
tempSchematic = MCSchematic(shape=box.size)
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.extractSchematicIter = extractSchematicFromIter
import tempfile
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
#probably should only apply to alpha levels
@ -498,13 +510,15 @@ def extractZipSchematicFrom(sourceLevel, box, zipfilename=None, entities=True):
destChunks = destBox.chunkPositions
chunkIter = itertools.izip(chunks, destChunks)
chunks = (x[1] for x in chunkIter if sourceLevel.containsChunk(*x[0]))
tempSchematic.createChunks(chunks)
for i, (src, chunk) in enumerate(chunkIter):
if sourceLevel.containsChunk(*src):
tempSchematic.createChunk(*chunk)
yield i, sourceBox.chunkCount
else:
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
schematicDat = TAG_Compound()
@ -520,9 +534,10 @@ def extractZipSchematicFrom(sourceLevel, box, zipfilename=None, entities=True):
import shutil
shutil.rmtree(filename)
import mclevel
return mclevel.fromFile(zipfilename)
yield mclevel.fromFile(zipfilename)
MCLevel.extractZipSchematic = extractZipSchematicFrom
MCLevel.extractZipSchematicIter = extractZipSchematicFromIter
from zipfile import ZipFile, ZIP_STORED
def zipdir(basedir, archivename):