def testCreate(self): # log.info("Schematic from indev") size = (64, 64, 64) temp = mktemp("testcreate.schematic") editor = createSchematic(shape=size, blocktypes='Classic') editor.filename = temp dim = editor.getDimension() level = self.schematicLevel dim.importSchematic(level, (0, 0, 0)) assert((schematic.Blocks[0:64, 0:64, 0:64] == level.adapter.Blocks[0:64, 0:64, 0:64]).all()) dim.importSchematic(level, (-32, -32, -32)) assert((schematic.Blocks[0:32, 0:32, 0:32] == level.adapter.Blocks[32:64, 32:64, 32:64]).all()) schematic.saveChanges() schem = WorldEditor("test_files/Station.schematic") tempEditor = createSchematic(shape=(1, 1, 3)) tempDim = tempEditor.getDimension() tempDim.copyBlocks(schem, BoundingBox((0, 0, 0), (1, 1, 3)), (0, 0, 0)) level = self.anvilLevel for cx, cz in itertools.product(xrange(0, 4), xrange(0, 4)): try: level.createChunk(cx, cz) except ValueError: pass dim.copyBlocks(level.getDimension(), BoundingBox((0, 0, 0), (64, 64, 64,)), (0, 0, 0)) os.remove(temp)
def __init__(self, pos, commandObj): """ Parameters ---------- commandObj : ExecuteCommand Returns ------- """ super(ExecuteVisuals, self).__init__() selector = commandObj.targetSelector if selector.playerName is not None: return selectorPos = [selector.getArg(a) for a in 'xyz'] if None in (selectorPos): log.warn("No selector coordinates for command %s", commandObj) targetPos = commandObj.resolvePosition((0, 0, 0)) else: targetPos = commandObj.resolvePosition(selectorPos) # Draw box at selector pos and draw line from command block to selector pos # xxxx selector pos is a sphere of radius `selector.getArg('r')` boxNode = SelectionBoxNode() boxNode.filled = False boxNode.wireColor = (0.9, 0.2, 0.2, 0.6) boxNode.selectionBox = BoundingBox(selectorPos, (1, 1, 1)) lineNode = LineArcNode( Vector(*pos) + (0.5, 0.5, 0.5), Vector(*selectorPos) + (.5, .5, .5), (0.9, 0.2, 0.2, 0.6)) self.addChild(boxNode) self.addChild(lineNode) if selectorPos != targetPos: # Command block's own coordinates are different from the selected pos, # either relative or absolute. # Draw a box at the target coordinates and a line from # the selected pos to the target boxNode = SelectionBoxNode() boxNode.filled = False boxNode.wireColor = (0.9, 0.2, 0.2, 0.6) boxNode.selectionBox = BoundingBox(targetPos, (1, 1, 1)) lineNode = LineArcNode( Vector(*selectorPos) + (0.5, 0.5, 0.5), Vector(*targetPos) + (.5, .5, .5), (0.9, 0.2, 0.2, 0.6)) self.addChild(boxNode) self.addChild(lineNode) if not isinstance(commandObj.subcommand, UnknownCommand): subvisuals = CommandVisuals(targetPos, commandObj.subcommand) self.addChild(subvisuals)
def test_difference(): box1 = BoundingBox((0, 0, 0), (10, 10, 10)) box2 = BoundingBox((0, 5, 0), (10, 10, 10)) diff = box1 - box2 mask = diff.box_mask(box1) assert not mask[5:, :, :].any()
def updateBoxHandle(self): if self.transformedWorldScene is None: bounds = BoundingBox(self.basePosition, self.pendingImport.bounds.size) else: origin = self.transformedPosition bounds = BoundingBox(origin, self.pendingImport.importBounds.size) #if self.handleNode.bounds.size != bounds.size: self.handleNode.bounds = bounds
def __init__(self, box=None, **kw): Symbol.__init__(self, **kw) if box is None: origin = kw['minx'], kw['miny'], kw['minz'] size = kw['width'], kw['height'], kw['length'] else: origin = box.origin size = box.size BoundingBox.__init__(self, origin, size)
def getWorldBounds(self): chunkPositions = list(self.chunkPositions()) if len(chunkPositions) == 0: return BoundingBox((0, 0, 0), (0, 0, 0)) chunkPositions = numpy.array(chunkPositions) mincx = (chunkPositions[:, 0]).min() maxcx = (chunkPositions[:, 0]).max() mincz = (chunkPositions[:, 1]).min() maxcz = (chunkPositions[:, 1]).max() origin = (mincx << 4, 0, mincz << 4) size = ((maxcx - mincx + 1) << 4, self.worldEditor.maxHeight, (maxcz - mincz + 1) << 4) return BoundingBox(origin, size)
def getEntity(self, dim): assert self.resultType == self.EntityResult box = BoundingBox(self.position, (1, 1, 1)).chunkBox(dim) entities = dim.getEntities(box, UUID=self.uuid) for entity in entities: return entity return None
def continueMove(self, event): if self.dragStartFace is None: return delta = self.dragMovePoint(event.ray) - self.dragStartPoint movePosition = self.dragStartMovePosition + map(int, delta) self.bounds = BoundingBox(movePosition, self.bounds.size)
def transformBounds(bounds, matrix): # matrix goes from dest to source; we need source to dest here, so get inverse matrix = np.linalg.inv(matrix) corners = np.array(boundsCorners(bounds)) corners = np.hstack([corners, ([1], ) * 8]) corners = corners * matrix minx = math.floor(min(corners[:, 0])) miny = math.floor(min(corners[:, 1])) minz = math.floor(min(corners[:, 2])) maxx = math.ceil(max(corners[:, 0])) maxy = math.ceil(max(corners[:, 1])) maxz = math.ceil(max(corners[:, 2])) # Why? Weird hacks for rotation? # if maxx % 1: # maxx += 1 # if maxy % 1: # maxy += 1 # if maxz % 1: # maxz += 1 newbox = BoundingBox(origin=Vector(minx, miny, minz).intfloor(), maximum=Vector(maxx, maxy, maxz).intfloor()) return newbox
def __init__(self, pos, commandObj): super(CloneVisuals, self).__init__() sourceBox = commandObj.resolveBoundingBox(pos) dest = commandObj.resolveDestination(pos) destBox = BoundingBox(dest, sourceBox.size) sourceColor = (0.3, 0.5, 0.9, 0.6) destColor = (0.0, 0.0, 0.9, 0.6) sourceBoxNode = SelectionBoxNode() sourceBoxNode.filled = False sourceBoxNode.wireColor = sourceColor sourceBoxNode.selectionBox = sourceBox destBoxNode = SelectionBoxNode() destBoxNode.filled = False destBoxNode.wireColor = destColor destBoxNode.selectionBox = destBox lineToSourceNode = LineArcNode( Vector(*pos) + (0.5, 0.5, 0.5), sourceBox.center, sourceColor) lineToDestNode = LineArcNode(sourceBox.center, destBox.center, destColor) self.addChild(sourceBoxNode) self.addChild(destBoxNode) self.addChild(lineToSourceNode) self.addChild(lineToDestNode)
def boxFromDragResize(self, box, ray): point = self.dragResizePoint(ray) side = self.dragResizeFace & 1 dragdim = self.dragResizeFace >> 1 origin, size = list(box.origin), list(box.size) if side: origin[dragdim] += size[dragdim] size[dragdim] = 0 otherSide = BoundingBox(origin, size) origin[dragdim] = int(numpy.floor(point[dragdim] + 0.5)) thisSide = BoundingBox(origin, size) return thisSide.union(otherSide)
def inspectBlock(self, pos): self.clearVisuals() self.blockPos = pos self.entity = None self.entityPtr = None self.currentChunk = None self.chunkPos = None self.stackedWidget.setCurrentWidget(self.pageInspectBlock) x, y, z = pos self.blockXSpinBox.setValue(x) self.blockYSpinBox.setValue(y) self.blockZSpinBox.setValue(z) blockID = self.editorSession.currentDimension.getBlockID(x, y, z) blockData = self.editorSession.currentDimension.getBlockData(x, y, z) blockLight = self.editorSession.currentDimension.getBlockLight(x, y, z) skyLight = self.editorSession.currentDimension.getSkyLight(x, y, z) self.blockIDLabel.setText(str(blockID)) self.blockDataLabel.setText(str(blockData)) self.blockLightLabel.setText(str(blockLight)) self.skyLightLabel.setText(str(skyLight)) block = self.editorSession.currentDimension.getBlock(x, y, z) self.blockNameLabel.setText(block.displayName) self.blockInternalNameLabel.setText(block.internalName) self.blockStateLabel.setText(str(block.blockState)) blockBox = BoundingBox((x, y, z), (1, 1, 1)) self.selectionNode.selectionBox = blockBox self.updateTileEntity()
def drawSelf(self): point = self.sceneNode.point if point is None: return r, g, b, a = self.sceneNode.color box = BoundingBox(point, (1, 1, 1)) with gl.glPushAttrib(GL.GL_DEPTH_BUFFER_BIT | GL.GL_ENABLE_BIT | GL.GL_POLYGON_BIT): GL.glDepthMask(False) GL.glEnable(GL.GL_BLEND) GL.glPolygonOffset(DepthOffsets.SelectionCursor, DepthOffsets.SelectionCursor) # Highlighted face GL.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_FILL) GL.glColor(r, g, b, a) cubes.drawFace(box, self.sceneNode.face) # Wire box GL.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_LINE) GL.glLineWidth(3.0) GL.glColor(1., 1., 1., a) cubes.drawBox(box) GL.glLineWidth(1.0) GL.glColor(0.2, 0.2, 0.2, a) cubes.drawBox(box)
def brushBoundingBox(self, center, options={}): # Return a box of size options['brushSize'] centered around point. # also used to position the preview cursor size = options['brushSize'] x, y, z = size origin = Vector(*center) - (Vector(x, y, z) / 2) + Vector((x % 2) * 0.5, (y % 2) * 0.5, (z % 2) * 0.5) return BoundingBox(origin, size)
def redo(self): super(MoveFinishCommand, self).redo() self.previousSelection = self.editorSession.currentSelection self.currentImport = self.moveTool.currentImport self.editorSession.currentSelection = BoundingBox( self.pendingImport.pos, self.previousSelection.size) self.moveTool.currentImport = None self.editorSession.removePendingImport(self.currentImport)
def setMinX(self, value): origin, size = self.boundingBox dx = value - origin[0] size = size[0] - dx, size[1], size[2] origin = value, origin[1], origin[2] box = BoundingBox(origin, size) self.boundingBox = box self.boxChanged.emit(box)
def setMinY(self, value): origin, size = self.boundingBox dy = value - origin[1] size = size[0], size[1] - dy, size[2] origin = origin[0], value, origin[2] box = BoundingBox(origin, size) self.boundingBox = box self.boxChanged.emit(box)
def setMinZ(self, value): origin, size = self.boundingBox dz = value - origin[2] size = size[0], size[1], size[2] - dz origin = origin[0], origin[1], value box = BoundingBox(origin, size) self.boundingBox = box self.boxChanged.emit(box)
def testImport(world, sourceLevel): dim = world.getDimension() dim.copyBlocks(sourceLevel.getDimension(), BoundingBox((0, 0, 0), ( 32, 64, 32, )), dim.bounds.origin) world.saveChanges()
def updateImportPos(self): if self.transformedDim is None: self.importPos = self.basePosition size = self.selection.size else: self.importPos = self.basePosition + self.transformOffset size = self.transformedDim.bounds.size self.importBounds = BoundingBox(self.importPos, size)
def getEntity(self): assert self.resultType == self.EntityResult dim = self.dimension box = BoundingBox(self.position.intfloor(), (1, 1, 1)).chunkBox(dim) entities = dim.getEntities(box, UUID=self.uuid) for entity in entities: return entity return None
def setMaxZ(self, value): origin, size = self.boundingBox if self.editSizeInput.checkState(): size = size[0], size[1], value else: size = size[0], size[1], value - origin[2] box = BoundingBox(origin, size) self.boundingBox = box self.boxChanged.emit(box)
def do_copy(dim, station, relight): times = 1 boxes = [] for x in range(times): for z in range(times): origin = (x * station.bounds.width, 54, z * station.bounds.length) boxes.append(BoundingBox(origin, station.bounds.size)) dim.copyBlocks(station, station.bounds, origin, create=True, updateLights=relight) return reduce(lambda a, b: a.union(b), boxes)
def testImport(any_world, schematic_world): dim = any_world.getDimension() dim.copyBlocks(schematic_world.getDimension(), BoundingBox((0, 0, 0), ( 32, 64, 32, )), dim.bounds.origin) any_world.saveChanges()
def testCopyRelight(anvilLevel, sourceLevel): destDim = anvilLevel.getDimension() exhaust( destDim.copyBlocksIter(sourceLevel.getDimension(), BoundingBox((0, 0, 0), ( 32, 64, 32, )), destDim.bounds.origin)) anvilLevel.saveChanges()
def testCopyRelight(pc_world, schematic_world): destDim = pc_world.getDimension() exhaust( destDim.copyBlocksIter(schematic_world.getDimension(), BoundingBox((0, 0, 0), ( 32, 64, 32, )), destDim.bounds.origin)) pc_world.saveChanges()
def updateNodes(self): box = self.currentSelection if box: self.boxHandleNode.bounds = BoundingBox(box.origin, box.size) self.selectionNode.visible = True self.selectionNode.selection = box else: self.boxHandleNode.bounds = None self.selectionNode.visible = False self.faceHoverNode.visible = False
def main(): app = QtGui.QApplication([]) selection = ShapeFuncSelection(BoundingBox((0, 0, 0), (63, 63, 63)), SphereShape) scene = SelectionScene() def timeBuild(): scene.selection = selection for _ in scene.loadSections(): pass duration = timeit.timeit(timeBuild, number=1) * 1000 print("timeBuild x1 in %0.2fms (%0.3fms per chunk)" % (duration, duration / selection.chunkCount))
def timeFillCeiling(): temp = bench_temp_level("AnvilWorld") editor = temp dim = editor.getDimension() bounds = dim.bounds x, y, z = bounds.center y = 254 x -= size // 2 z -= size // 2 bounds = BoundingBox((x, y, z), (size, 1, size)) exhaust(dim.fillBlocksIter(bounds, editor.blocktypes["planks"]))
def testRotate(pc_world): dim = pc_world.getDimension() schematic = dim.exportSchematic(BoundingBox((0, 0, 0), (21, 11, 8))) schematic.rotateLeft() dim.importSchematic(schematic, dim.bounds.origin) schematic.flipEastWest() dim.importSchematic(schematic, dim.bounds.origin) schematic.flipVertical() dim.importSchematic(schematic, dim.bounds.origin)
def boxFromDragSelect(self, event): """ Create a flat selection from dragging the mouse outside the selection. Parameters ---------- ray: mcedit2.util.geometry.Ray Returns ------- box: BoundingBox """ point = self.dragStartPoint face = self.dragStartFace size = [1, 1, 1] if self.classicSelection: endPoint = event.blockPosition else: ray = event.ray dim = face >> 1 size[dim] = 0 s = [0,0,0] if face & 1 == 0: s[dim] = 1 point = point + s endPoint = ray.intersectPlane(dim, point[dim]) startBox = BoundingBox(point, size) endBox = BoundingBox(endPoint.intfloor(), size) return startBox.union(endBox)
def boxFromDragSelect(self, ray): """ Create a flat selection from dragging the mouse outside the selection. :type ray: mcedit2.util.geometry.Ray :rtype: BoundingBox """ point = self.dragStartPoint face = self.dragStartFace size = [1, 1, 1] dim = face >> 1 size[dim] = 0 s = [0,0,0] if face & 1 == 0: s[dim] = 1 point = point + s startBox = BoundingBox(point, size) endPoint = ray.intersectPlane(dim, point[dim]) endBox = BoundingBox(endPoint.intfloor(), size) return startBox.union(endBox)
def copyBlocksIter(destDim, sourceDim, sourceSelection, destinationPoint, blocksToCopy=None, entities=True, create=False, biomes=False, updateLights=False): """ Copy blocks and entities from the `sourceBox` area of `sourceDim` to `destDim` starting at `destinationPoint`. :param sourceDim: WorldEditorDimension :param destDim: WorldEditorDimension Optional parameters: - `blocksToCopy`: list of blockIDs to copy. - `entities`: True to copy Entities and TileEntities, False otherwise. - `create`: True to create new chunks in destLevel, False otherwise. - `biomes`: True to copy biome data, False otherwise. """ (lx, ly, lz) = sourceSelection.size # needs work xxx log.info(u"Copying {0} blocks from {1} to {2}" .format(ly * lz * lx, sourceSelection, destinationPoint)) startTime = time.time() destBox = BoundingBox(destinationPoint, sourceSelection.size) chunkCount = destBox.chunkCount i = 0 entitiesCopied = 0 tileEntitiesCopied = 0 entitiesSeen = 0 tileEntitiesSeen = 0 if updateLights: allChangedX = [] allChangedY = [] allChangedZ = [] makeSourceMask = sourceMaskFunc(blocksToCopy) copyOffset = destBox.origin - sourceSelection.origin # Visit each chunk in the source area # Visit each section in this chunk # Find the chunks and sections of the destination area corresponding to this section # Compute slices for Blocks array and mask # Use slices and mask to copy Blocks and Data # Copy entities and tile entities from this chunk. sourceBiomeMask = None convertBlocks = blocktypes.blocktypeConverter(destDim.blocktypes, sourceDim.blocktypes) for sourceCpos in sourceSelection.chunkPositions(): # Visit each chunk if not sourceDim.containsChunk(*sourceCpos): continue sourceChunk = sourceDim.getChunk(*sourceCpos) i += 1 yield (i, chunkCount) if i % 20 == 0: log.info("Copying: Chunk {0}/{1}...".format(i, chunkCount)) # Use sourceBiomeMask to accumulate a list of columns over all sections whose biomes should be copied. sourceBiomes = None if biomes and hasattr(sourceChunk, 'Biomes'): sourceBiomes = sourceChunk.Biomes sourceBiomeMask = numpy.zeros_like(sourceBiomes) for sourceCy in sourceChunk.sectionPositions(): # Visit each section sourceSection = sourceChunk.getSection(sourceCy) if sourceSection is None: continue selectionMask = sourceSelection.section_mask(sourceCpos[0], sourceCy, sourceCpos[1]) if selectionMask is None: continue typeMask = makeSourceMask(sourceSection.Blocks) sourceMask = selectionMask & typeMask # Update sourceBiomeMask if sourceBiomes is not None: sourceBiomeMask |= sourceMask.any(axis=0) # Find corresponding destination area(s) sectionBox = SectionBox(sourceCpos[0], sourceCy, sourceCpos[1]) destBox = BoundingBox(sectionBox.origin + copyOffset, sectionBox.size) for destCpos in destBox.chunkPositions(): if not create and not destDim.containsChunk(*destCpos): continue destChunk = destDim.getChunk(*destCpos, create=True) for destCy in destBox.sectionPositions(*destCpos): # Compute slices for source and dest arrays destSectionBox = SectionBox(destCpos[0], destCy, destCpos[1]) intersect = destSectionBox.intersect(destBox) if intersect.volume == 0: continue destSection = destChunk.getSection(destCy, create=True) if destSection is None: continue destSlices = ( slice(intersect.miny - (destCy << 4), intersect.maxy - (destCy << 4)), slice(intersect.minz - (destCpos[1] << 4), intersect.maxz - (destCpos[1] << 4)), slice(intersect.minx - (destCpos[0] << 4), intersect.maxx - (destCpos[0] << 4)), ) sourceIntersect = BoundingBox(intersect.origin - copyOffset, intersect.size) sourceSlices = ( slice(sourceIntersect.miny - (sourceCy << 4), sourceIntersect.maxy - (sourceCy << 4)), slice(sourceIntersect.minz - (sourceCpos[1] << 4), sourceIntersect.maxz - (sourceCpos[1] << 4)), slice(sourceIntersect.minx - (sourceCpos[0] << 4), sourceIntersect.maxx - (sourceCpos[0] << 4)), ) # Read blocks sourceBlocks = sourceSection.Blocks[sourceSlices] sourceData = sourceSection.Data[sourceSlices] sourceMaskPart = sourceMask[sourceSlices] # Convert blocks convertedSourceBlocks, convertedSourceData = convertBlocks(sourceBlocks, sourceData) convertedSourceBlocksMasked = convertedSourceBlocks[sourceMaskPart] # Find blocks that need direct lighting update - block opacity or brightness changed oldBrightness = destDim.blocktypes.brightness[destSection.Blocks[destSlices][sourceMaskPart]] newBrightness = destDim.blocktypes.brightness[convertedSourceBlocksMasked] oldOpacity = destDim.blocktypes.opacity[destSection.Blocks[destSlices][sourceMaskPart]] newOpacity = destDim.blocktypes.opacity[convertedSourceBlocksMasked] changedLight = (oldBrightness != newBrightness) | (oldOpacity != newOpacity) # Write blocks destSection.Blocks[destSlices][sourceMaskPart] = convertedSourceBlocks[sourceMaskPart] destSection.Data[destSlices][sourceMaskPart] = convertedSourceData[sourceMaskPart] if updateLights: # Find coordinates of lighting updates (changedFlat,) = changedLight.nonzero() # Since convertedSourceBlocksMasked is a 1d array, changedFlat is an index # into this array. Thus, changedFlat is also an index into the nonzero values # of sourceMaskPart. if len(changedFlat): x, y, z = sourceMaskPart.nonzero() changedX = x[changedFlat].astype('i4') changedY = y[changedFlat].astype('i4') changedZ = z[changedFlat].astype('i4') changedX += intersect.minx changedY += intersect.miny changedZ += intersect.minz if updateLights == "all": allChangedX.append(changedX) allChangedY.append(changedY) allChangedZ.append(changedZ) else: # log.info("Updating section lights in %s blocks... (ob %s)", # changedFlat.shape, # oldBrightness.shape) relight.updateLightsByCoord(destDim, changedX, changedY, changedZ) destChunk.dirty = True # Copy biomes if sourceBiomes is not None: bx, bz = sourceBiomeMask.nonzero() wbx = bx + (sourceCpos[0] << 4) wbz = bz + (sourceCpos[1] << 4) destDim.setBlocks(wbx, 1, wbz, Biomes=sourceBiomes[bx, bz]) # Copy entities and tile entities if entities: entitiesSeen += len(sourceChunk.Entities) for entity in sourceChunk.Entities: if entity.Position in sourceSelection: entitiesCopied += 1 newEntity = entity.copyWithOffset(copyOffset) destDim.addEntity(newEntity) tileEntitiesSeen += len(sourceChunk.TileEntities) for tileEntity in sourceChunk.TileEntities: if tileEntity.Position in sourceSelection: tileEntitiesCopied += 1 newEntity = tileEntity.copyWithOffset(copyOffset) destDim.addTileEntity(newEntity) duration = time.time() - startTime log.info("Duration: %0.3fs, %d/%d chunks, %0.2fms per chunk (%0.2f chunks per second)", duration, i, sourceSelection.chunkCount, 1000 * duration/i, i/duration) log.info("Copied %d/%d entities and %d/%d tile entities", entitiesCopied, entitiesSeen, tileEntitiesCopied, tileEntitiesSeen) if updateLights == "all": log.info("Updating all at once for %d sections (%d cells)", len(allChangedX), sum(len(a) for a in allChangedX)) startTime = time.time() for i in range(len(allChangedX)): x = allChangedX[i] y = allChangedY[i] z = allChangedZ[i] relight.updateLightsByCoord(destDim, x, y, z) i = i or 1 duration = time.time() - startTime duration = duration or 1 log.info("Lighting complete.") log.info("Duration: %0.3fs, %d sections, %0.2fms per section (%0.2f sections per second)", duration, i, 1000 * duration/i, i/duration)
def copyBlocksIter(destDim, sourceDim, sourceSelection, destinationPoint, blocksToCopy=None, entities=True, create=False, biomes=False): """ Copy blocks and entities from the `sourceBox` area of `sourceDim` to `destDim` starting at `destinationPoint`. :param sourceDim: WorldEditorDimension :param destDim: WorldEditorDimension Optional parameters: - `blocksToCopy`: list of blockIDs to copy. - `entities`: True to copy Entities and TileEntities, False otherwise. - `create`: True to create new chunks in destLevel, False otherwise. - `biomes`: True to copy biome data, False otherwise. """ (lx, ly, lz) = sourceSelection.size # needs work xxx log.info(u"Copying {0} blocks from {1} to {2}" .format(ly * lz * lx, sourceSelection, destinationPoint)) startTime = datetime.now() destBox = BoundingBox(destinationPoint, sourceSelection.size) chunkCount = destBox.chunkCount i = 0 entitiesCopied = 0 tileEntitiesCopied = 0 entitiesSeen = 0 tileEntitiesSeen = 0 makeSourceMask = sourceMaskFunc(blocksToCopy) copyOffset = destBox.origin - sourceSelection.origin # Visit each chunk in the source area # Visit each section in this chunk # Find the chunks and sections of the destination area corresponding to this section # Compute slices for Blocks array and mask # Use slices and mask to copy Blocks and Data # Copy entities and tile entities from this chunk. sourceBiomeMask = None convertBlocks = blocktypes.blocktypeConverter(destDim.blocktypes, sourceDim.blocktypes) for sourceCpos in sourceSelection.chunkPositions(): # Visit each chunk if not sourceDim.containsChunk(*sourceCpos): continue sourceChunk = sourceDim.getChunk(*sourceCpos) i += 1 yield (i, chunkCount) if i % 100 == 0: log.info("Copying: Chunk {0}...".format(i)) # Use sourceBiomeMask to accumulate a list of columns over all sections whose biomes should be copied. sourceBiomes = None if biomes and hasattr(sourceChunk, 'Biomes'): sourceBiomes = sourceChunk.Biomes sourceBiomeMask = numpy.zeros_like(sourceBiomes) for sourceCy in sourceChunk.sectionPositions(): # Visit each section sourceSection = sourceChunk.getSection(sourceCy) if sourceSection is None: continue selectionMask = sourceSelection.section_mask(sourceCpos[0], sourceCy, sourceCpos[1]) if selectionMask is None: continue typeMask = makeSourceMask(sourceSection.Blocks) sourceMask = selectionMask & typeMask # Update sourceBiomeMask if sourceBiomes is not None: sourceBiomeMask |= sourceMask.any(axis=0) # Find corresponding destination area(s) sectionBox = SectionBox(sourceCpos[0], sourceCy, sourceCpos[1], sourceSection) destBox = BoundingBox(sectionBox.origin + copyOffset, sectionBox.size) for destCpos in destBox.chunkPositions(): if not create and not destDim.containsChunk(*destCpos): continue destChunk = destDim.getChunk(*destCpos, create=True) for destCy in destBox.sectionPositions(*destCpos): # Compute slices for source and dest arrays destSectionBox = SectionBox(destCpos[0], destCy, destCpos[1]) intersect = destSectionBox.intersect(destBox) if intersect.volume == 0: continue destSection = destChunk.getSection(destCy, create=True) if destSection is None: continue # Recompute destSectionBox and intersect using the shape of destSection.Blocks # after destChunk is loaded to work with odd shaped FakeChunkDatas XXXXXXXXXXXX destSectionBox = SectionBox(destCpos[0], destCy, destCpos[1], destSection) intersect = destSectionBox.intersect(destBox) if intersect.volume == 0: continue destSlices = ( slice(intersect.miny - (destCy << 4), intersect.maxy - (destCy << 4)), slice(intersect.minz - (destCpos[1] << 4), intersect.maxz - (destCpos[1] << 4)), slice(intersect.minx - (destCpos[0] << 4), intersect.maxx - (destCpos[0] << 4)), ) sourceIntersect = BoundingBox(intersect.origin - copyOffset, intersect.size) sourceSlices = ( slice(sourceIntersect.miny - (sourceCy << 4), sourceIntersect.maxy - (sourceCy << 4)), slice(sourceIntersect.minz - (sourceCpos[1] << 4), sourceIntersect.maxz - (sourceCpos[1] << 4)), slice(sourceIntersect.minx - (sourceCpos[0] << 4), sourceIntersect.maxx - (sourceCpos[0] << 4)), ) # Read blocks sourceBlocks = sourceSection.Blocks[sourceSlices] sourceData = sourceSection.Data[sourceSlices] sourceMaskPart = sourceMask[sourceSlices] # Convert blocks convertedSourceBlocks, convertedSourceData = convertBlocks(sourceBlocks, sourceData) # Write blocks destSection.Blocks[destSlices][sourceMaskPart] = convertedSourceBlocks[sourceMaskPart] destSection.Data[destSlices][sourceMaskPart] = convertedSourceData[sourceMaskPart] destChunk.dirty = True # Copy biomes if sourceBiomes is not None: bx, bz = sourceBiomeMask.nonzero() wbx = bx + (sourceCpos[0] << 4) wbz = bz + (sourceCpos[1] << 4) destDim.setBlocks(wbx, 1, wbz, Biomes=sourceBiomes[bx, bz]) # Copy entities and tile entities if entities: entitiesSeen += len(sourceChunk.Entities) for entity in sourceChunk.Entities: if entity.Position in sourceSelection: entitiesCopied += 1 newEntity = entity.copyWithOffset(copyOffset) destDim.addEntity(newEntity) tileEntitiesSeen += len(sourceChunk.TileEntities) for tileEntity in sourceChunk.TileEntities: if tileEntity.Position in sourceSelection: tileEntitiesCopied += 1 newEntity = tileEntity.copyWithOffset(copyOffset) destDim.addTileEntity(newEntity) log.info("Duration: {0}".format(datetime.now() - startTime)) log.info("Copied %d/%d entities and %d/%d tile entities", entitiesCopied, entitiesSeen, tileEntitiesCopied, tileEntitiesSeen)