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:
parent
55dc972e22
commit
e8870e76e4
@ -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()
|
||||
|
||||
|
35
level.py
35
level.py
@ -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
|
||||
|
29
schematic.py
29
schematic.py
@ -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):
|
||||
|
Reference in New Issue
Block a user