Example #1
0
    def do_relight():
        cx, cy, cz = poses.next()
        indices = numpy.indices((16, 16, 16), numpy.int32)
        indices.shape = 3, 16*16*16
        indices += ([cx << 4], [cy << 4], [cz << 4])
        x, y, z = indices

        relight.updateLightsByCoord(dim, x, y, z)
        def postCopy():  # profiling
            start = time.time()
            count = 0
            print("Relighting outside of copyBlocks. Updating %d cells" % (len(positions) * 16 * 16 * 16))
            for cx, cy, cz in positions:
                indices = numpy.indices((16, 16, 16), numpy.int32)
                indices.shape = 3, 16*16*16
                indices += ([cx << 4], [cy << 4], [cz << 4])
                x, y, z = indices
                relight.updateLightsByCoord(dim, x, y, z)
                count += 1
            t = time.time() - start

            print "Relight manmade building (outside copyBlocks): " \
                  "%d (out of %d) chunk-sections in %.02f seconds (%f sections per second; %dms per section)" \
                  % (count, len(positions), t, count / t, 1000 * t / count)
        def postCopy():  # profiling
            start = time.time()
            count = 0
            print ("Relighting outside of copyBlocks. Updating %d cells" % (len(positions) * 16 * 16 * 16))
            for cx, cy, cz in positions:
                indices = numpy.indices((16, 16, 16), numpy.int32)
                indices.shape = 3, 16 * 16 * 16
                indices += ([cx << 4], [cy << 4], [cz << 4])
                x, y, z = indices
                relight.updateLightsByCoord(dim, x, y, z)
                count += 1
            t = time.time() - start

            print "Relight manmade building (outside copyBlocks): " "%d (out of %d) chunk-sections in %.02f seconds (%f sections per second; %dms per section)" % (
                count,
                len(positions),
                t,
                count / t,
                1000 * t / count,
            )
Example #4
0
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)
Example #5
0
def setBlocks(
        dimension,
        x,
        y,
        z,
        Blocks=None,
        Data=None,  # Deprecate soon
        BlockLight=None,
        SkyLight=None,
        Biomes=None,
        updateLights=True):
    """
    Change the blocks at the given positions. All parameters must be arrays of the same shape, or single values.

    :type dimension: mceditlib.worldeditor.WorldEditorDimension
    """
    x = atleast_3d(x)
    y = atleast_3d(y)
    z = atleast_3d(z)
    if Blocks is not None:
        if isinstance(Blocks, (BlockType, basestring)):
            Blocks = [Blocks]
        _Blocks = []
        _Data = []
        if isinstance(Blocks, int):
            Blocks = [Blocks]

        for block in Blocks:
            if isinstance(block, basestring):
                block = dimension.blocktypes[block]
            if isinstance(block, BlockType):
                _Blocks.append(block.ID)
                _Data.append(block.meta)
            else:
                _Blocks.append(block)
        if len(_Blocks):
            Blocks = _Blocks
        if len(_Data):
            Data = _Data

    if Blocks is None and Data is None:
        updateLights = False

    Blocks = atleast_3d(Blocks) if Blocks is not None else None
    Data = atleast_3d(Data) if Data is not None else None
    BlockLight = atleast_3d(BlockLight) if BlockLight is not None else None
    SkyLight = atleast_3d(SkyLight) if SkyLight is not None else None
    Biomes = atleast_3d(Biomes) if Biomes is not None else None

    arrays_to_broadcast = [x, y, z]

    if Blocks is not None:
        arrays_to_broadcast.append(Blocks)
    if Data is not None:
        arrays_to_broadcast.append(Data)
    if BlockLight is not None:
        arrays_to_broadcast.append(BlockLight)
    if SkyLight is not None:
        arrays_to_broadcast.append(SkyLight)
    if Biomes is not None:
        arrays_to_broadcast.append(Biomes)

    if any(a.size == 0 for a in (x, y, z)):
        return

    broadcasted_arrays = numpy.broadcast_arrays(*arrays_to_broadcast)

    x, y, z = broadcasted_arrays[:3]
    broadcasted_arrays = broadcasted_arrays[3:]

    if Blocks is not None:
        Blocks, broadcasted_arrays = broadcasted_arrays[0], broadcasted_arrays[
            1:]
    if Data is not None:
        Data, broadcasted_arrays = broadcasted_arrays[0], broadcasted_arrays[
            1:]
    if BlockLight is not None:
        BlockLight, broadcasted_arrays = broadcasted_arrays[
            0], broadcasted_arrays[1:]
    if SkyLight is not None:
        SkyLight, broadcasted_arrays = broadcasted_arrays[
            0], broadcasted_arrays[1:]
    if Biomes is not None:
        Biomes, broadcasted_arrays = broadcasted_arrays[0], broadcasted_arrays[
            1:]

    for cx, cz, sx, sy, sz, mask in coords_by_chunk(x, y, z):
        chunk = dimension.getChunk(cx, cz, create=True)
        if chunk is None:
            continue
        setChunkBlocks(chunk, sx, sy, sz, maskArray(Blocks, mask),
                       maskArray(Data, mask), maskArray(BlockLight, mask),
                       maskArray(SkyLight, mask), maskArray(Biomes, mask))
        chunk.dirty = True

    if updateLights:
        relight.updateLightsByCoord(dimension, x, y, z)
Example #6
0
def setBlocks(dimension, x, y, z,
              Blocks=None,
              Data=None,  # Deprecate soon
              BlockLight=None,
              SkyLight=None,
              Biomes=None,
              updateLights=True):
    """
    Change the blocks at the given positions. All parameters must be arrays of the same shape, or single values.

    :type dimension: mceditlib.worldeditor.WorldEditorDimension
    """
    x = atleast_3d(x)
    y = atleast_3d(y)
    z = atleast_3d(z)
    if Blocks is not None:
        if isinstance(Blocks, (BlockType, basestring)):
            Blocks = [Blocks]
        _Blocks = []
        _Data = []
        if isinstance(Blocks, int):
            Blocks = [Blocks]


        for block in Blocks:
            if isinstance(block, basestring):
                block = dimension.blocktypes[block]
            if isinstance(block, BlockType):
                _Blocks.append(block.ID)
                _Data.append(block.meta)
            else:
                _Blocks.append(block)
        if len(_Blocks):
            Blocks = _Blocks
        if len(_Data):
            Data = _Data

    if Blocks is None and Data is None:
        updateLights = False


    Blocks = atleast_3d(Blocks) if Blocks is not None else None
    Data = atleast_3d(Data) if Data is not None else None
    BlockLight = atleast_3d(BlockLight) if BlockLight is not None else None
    SkyLight = atleast_3d(SkyLight) if SkyLight is not None else None
    Biomes = atleast_3d(Biomes) if Biomes is not None else None

    arrays_to_broadcast = [x, y, z]

    if Blocks is not None:
        arrays_to_broadcast.append(Blocks)
    if Data is not None:
        arrays_to_broadcast.append(Data)
    if BlockLight is not None:
        arrays_to_broadcast.append(BlockLight)
    if SkyLight is not None:
        arrays_to_broadcast.append(SkyLight)
    if Biomes is not None:
        arrays_to_broadcast.append(Biomes)

    if any(a.size == 0 for a in (x, y, z)):
        return

    broadcasted_arrays = numpy.broadcast_arrays(*arrays_to_broadcast)

    x, y, z = broadcasted_arrays[:3]
    broadcasted_arrays = broadcasted_arrays[3:]


    if Blocks is not None:
        Blocks, broadcasted_arrays = broadcasted_arrays[0], broadcasted_arrays[1:]
    if Data is not None:
        Data, broadcasted_arrays = broadcasted_arrays[0], broadcasted_arrays[1:]
    if BlockLight is not None:
        BlockLight, broadcasted_arrays = broadcasted_arrays[0], broadcasted_arrays[1:]
    if SkyLight is not None:
        SkyLight, broadcasted_arrays = broadcasted_arrays[0], broadcasted_arrays[1:]
    if Biomes is not None:
        Biomes, broadcasted_arrays = broadcasted_arrays[0], broadcasted_arrays[1:]


    for cx, cz, sx, sy, sz, mask in coords_by_chunk(x, y, z):
        chunk = dimension.getChunk(cx, cz, create=True)
        if chunk is None:
            continue
        setChunkBlocks(chunk, sx, sy, sz,
                       maskArray(Blocks, mask),
                       maskArray(Data, mask),
                       maskArray(BlockLight, mask),
                       maskArray(SkyLight, mask),
                       maskArray(Biomes, mask))
        chunk.dirty = True

    if updateLights:
        relight.updateLightsByCoord(dimension, x, y, z)