Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
152 lines (103 sloc) 5.76 KB
from datetime import datetime
import logging
log = logging.getLogger(__name__)
import numpy
from box import BoundingBox, Vector
from mclevelbase import exhaust
import materials
from entity import Entity, TileEntity
def convertBlocks(destLevel, sourceLevel, blocks, blockData):
return materials.convertBlocks(destLevel.materials, sourceLevel.materials, blocks, blockData)
def sourceMaskFunc(blocksToCopy):
if blocksToCopy is not None:
typemask = numpy.zeros(materials.id_limit, dtype='bool')
typemask[blocksToCopy] = 1
def maskedSourceMask(sourceBlocks):
return typemask[sourceBlocks]
return maskedSourceMask
def unmaskedSourceMask(_sourceBlocks):
return slice(None, None)
return unmaskedSourceMask
def adjustCopyParameters(destLevel, sourceLevel, sourceBox, destinationPoint):
# if the destination box is outside the level, it and the source corners are moved inward to fit.
(dx, dy, dz) = map(int, destinationPoint)
log.debug(u"Asked to copy {} blocks \n\tfrom {} in {}\n\tto {} in {}" .format(
sourceBox.volume, sourceBox, sourceLevel, destinationPoint, destLevel))
if destLevel.Width == 0:
return sourceBox, destinationPoint
destBox = BoundingBox(destinationPoint, sourceBox.size)
actualDestBox = destBox.intersect(destLevel.bounds)
actualSourceBox = BoundingBox(sourceBox.origin + actualDestBox.origin - destBox.origin, destBox.size)
actualDestPoint = actualDestBox.origin
return actualSourceBox, actualDestPoint
def copyBlocksFromIter(destLevel, sourceLevel, sourceBox, destinationPoint, blocksToCopy=None, entities=True, create=False, biomes=False):
""" copy blocks between two infinite levels by looping through the
destination's chunks. make a sub-box of the source level for each chunk
and copy block and entities in the sub box to the dest chunk."""
(lx, ly, lz) = sourceBox.size
sourceBox, destinationPoint = adjustCopyParameters(destLevel, sourceLevel, sourceBox, destinationPoint)
# needs work xxx
log.info(u"Copying {0} blocks from {1} to {2}" .format(ly * lz * lx, sourceBox, destinationPoint))
startTime = datetime.now()
destBox = BoundingBox(destinationPoint, sourceBox.size)
chunkCount = destBox.chunkCount
i = 0
e = 0
t = 0
sourceMask = sourceMaskFunc(blocksToCopy)
copyOffset = [d - s for s, d in zip(sourceBox.origin, destinationPoint)]
# Visit each chunk in the destination area.
# Get the region of the source area corresponding to that chunk
# Visit each chunk of the region of the source area
# Get the slices of the destination chunk
# Get the slices of the source chunk
# Copy blocks and data
for destCpos in destBox.chunkPositions:
cx, cz = destCpos
destChunkBox = BoundingBox((cx << 4, 0, cz << 4), (16, destLevel.Height, 16)).intersect(destBox)
destChunkBoxInSourceLevel = BoundingBox([d - o for o, d in zip(copyOffset, destChunkBox.origin)], destChunkBox.size)
if not destLevel.containsChunk(*destCpos):
if create and any(sourceLevel.containsChunk(*c) for c in destChunkBoxInSourceLevel.chunkPositions):
# Only create chunks in the destination level if the source level has chunks covering them.
destLevel.createChunk(*destCpos)
else:
continue
destChunk = destLevel.getChunk(*destCpos)
i += 1
yield (i, chunkCount)
if i % 100 == 0:
log.info("Chunk {0}...".format(i))
for srcCpos in destChunkBoxInSourceLevel.chunkPositions:
if not sourceLevel.containsChunk(*srcCpos):
continue
sourceChunk = sourceLevel.getChunk(*srcCpos)
sourceChunkBox, sourceSlices = sourceChunk.getChunkSlicesForBox(destChunkBoxInSourceLevel)
if sourceChunkBox.volume == 0:
continue
sourceChunkBoxInDestLevel = BoundingBox([d + o for o, d in zip(copyOffset, sourceChunkBox.origin)], sourceChunkBox.size)
_, destSlices = destChunk.getChunkSlicesForBox(sourceChunkBoxInDestLevel)
sourceBlocks = sourceChunk.Blocks[sourceSlices]
sourceData = sourceChunk.Data[sourceSlices]
mask = sourceMask(sourceBlocks)
convertedSourceBlocks, convertedSourceData = convertBlocks(destLevel, sourceLevel, sourceBlocks, sourceData)
destChunk.Blocks[destSlices][mask] = convertedSourceBlocks[mask]
if convertedSourceData is not None:
destChunk.Data[destSlices][mask] = convertedSourceData[mask]
if entities:
ents = sourceChunk.getEntitiesInBox(destChunkBoxInSourceLevel)
e += len(ents)
for entityTag in ents:
eTag = Entity.copyWithOffset(entityTag, copyOffset)
destLevel.addEntity(eTag)
tileEntities = sourceChunk.getTileEntitiesInBox(destChunkBoxInSourceLevel)
t += len(tileEntities)
for tileEntityTag in tileEntities:
eTag = TileEntity.copyWithOffset(tileEntityTag, copyOffset)
destLevel.addTileEntity(eTag)
if biomes and hasattr(destChunk, 'Biomes') and hasattr(sourceChunk, 'Biomes'):
destChunk.Biomes[destSlices[:2]] = sourceChunk.Biomes[sourceSlices[:2]]
destChunk.chunkChanged()
log.info("Duration: {0}".format(datetime.now() - startTime))
log.info("Copied {0} entities and {1} tile entities".format(e, t))
def copyBlocksFrom(destLevel, sourceLevel, sourceBox, destinationPoint, blocksToCopy=None, entities=True, create=False, biomes=False):
return exhaust(copyBlocksFromIter(destLevel, sourceLevel, sourceBox, destinationPoint, blocksToCopy, entities, create, biomes))