def add_data(self, terrain=None, tile_entities=None, entities=None, subchunk=None):
        """Add terrain to chunk.

        terrain, tile_entities, entities: str: 4096 long string. Defaults to 'None'.
        subchunk: int: subchunk 'height'; generaly 0 to 15 number.
        """
        if type(subchunk) != int:
            raise TypeError("Bad subchunk type. Must be an int, got %s (%s)"%(type(subchunk), subchunk))
        if terrain:
            self.subchunks.append(subchunk)

            subchunk_version, terrain = ord(terrain[0]), terrain[1:]
            if subchunk_version in [0, 2, 3, 4, 5, 6, 7]:
                blocks, terrain = terrain[:4096], terrain[4096:]
                data, terrain = terrain[:2048], terrain[2048:]
                skyLight, terrain = terrain[:2048], terrain[2048:]
                blockLight, terrain = terrain[:2048], terrain[2048:]
                # 'Computing' data is needed before sending it to the data holders.
                self._Blocks.add_data(subchunk, numpy.fromstring(blocks, "uint8").astype(self._Blocks.bin_type))

                #             for k, v in ((self._Data, data), (self._SkyLight, skyLight), (self._BlockLight, blockLight)):
                #                 a = numpy.fromstring(v, k.bin_type)
                #                 a.shape = (16, 16, len(v) / 256)
                #                 k.add_data(subchunk, unpackNibbleArray(a).tostring())

                a = numpy.fromstring(data, "uint8")
                a.shape = (16, 16, len(data) / 256)
                self._Data.add_data(subchunk, numpy.fromstring(unpackNibbleArray(a).tostring(), "uint8").astype(self._Data.bin_type))

                if self.chunk_version == "\x03":
                    for k, v in ((self._SkyLight, skyLight), (self._BlockLight, blockLight)):
                        a = numpy.fromstring(v, "uint8")
                        a.shape = (16, 16, len(v) / 256)
                        k.add_data(subchunk,
                                   numpy.fromstring(unpackNibbleArray(a).tostring(), "uint8").astype(k.bin_type))
            elif subchunk_version == 1:
                blocks, data, terrain = self._read_block_storage(terrain)
                self._Blocks.add_data(subchunk, blocks)
                self._Data.add_data(subchunk, data)
            elif subchunk_version == 8:
                num_of_storages, terrain = ord(terrain[0]), terrain[1:]
                blocks, data, terrain = self._read_block_storage(terrain)
                self._Blocks.add_data(subchunk, blocks)
                self._Data.add_data(subchunk, data)
                if num_of_storages > 1:
                    extraBlocks, extraData, ignored_data = self._read_block_storage(terrain)
                    self._extra_blocks.add_data(subchunk, extraBlocks)
                    self._extra_blocks_data.add_data(subchunk, extraData)
                    # Only support for one layer of extra blocks is in place
            else:
                raise NotImplementedError("Not implemented this new type of world format yet")

            self.subchunks_versions[subchunk] = subchunk_version

#             if DEBUG_PE:
#                 write_dump("--- sub-chunk (%s, %s, %s) version: %s\n" % (self.chunkPosition[0], self.chunkPosition[1], subchunk, version))
#                 write_dump("--- sub-chunk (%s, %s, %s) blocks: %s\n    length: %s\n" % (self.chunkPosition[0], self.chunkPosition[1], subchunk, repr(blocks), len(blocks)))

        else:
            if subchunk == 0 and DEBUG_PE:
                write_dump("!!! No terrain for sub-chunk (%s, %s, %s)\n" % (self.chunkPosition[0], self.chunkPosition[1], subchunk))

        if tile_entities:
            if DEBUG_PE:
                write_dump(('/' * 80) + '\nParsing TileEntities in chunk %s,%s\n' % (self.chunkPosition[0], self.chunkPosition[1]))
            if DEBUG_PE == 2:
                write_dump("+ begin tile_entities raw data\n%s\n- end tile_entities raw data\n" % nbt.hexdump(tile_entities, length=16))
            for tile_entity in loadNBTCompoundList(tile_entities):
                self.TileEntities.insert(-1, tile_entity)
        if entities:
            mcedit_defs = self.world.defsIds.mcedit_defs
            defs_get = mcedit_defs.get
            ids_get = self.world.defsIds.mcedit_ids.get
            if DEBUG_PE:
                write_dump(('\\' * 80) + '\nParsing Entities in chunk %s,%s\n' % (self.chunkPosition[0], self.chunkPosition[1]))
            try:
                Entities = loadNBTCompoundList(entities)
            except Exception as exc:
                logger.error("The entities data for chunk %s:%s may be corrupted. The error is:\n%s" % (self.chunkPosition[0], self.chunkPosition[1], exc))
                Entities = nbt.TAG_List()

            # PE saves entities with their int ID instead of string name. We swap them to make it work in mcedit.
            # Whenever we save an entity, we need to make sure to swap back.
#             invertEntities = {v: k for k, v in entity.PocketEntity.entityList.items()}
            for ent in Entities:
                if 'identifier' in ent:
                    ent["id"] = nbt.TAG_String('see "identifier"')
                else:
                    try:
                        v = ent["id"].value
                        if DEBUG_PE:
                            _v = int(v)
                        v = int(v) & 0xFF
                    except Exception as e:
                        logger.warning("An error occured while getting entity ID:")
                        logger.warning(e)
                        logger.warning("Default 'Unknown' ID is used...")
                        v = 'Unknown'
                    # !
    #                 id = invertEntities.get(v, "Entity %s"%v)
                    # Add the built one to the entities
    #                 if id not in entity.PocketEntity.entityList.keys():
    #                     logger.warning("Found unknown entity '%s'"%v)
    #                     entity.PocketEntity.entityList[id] = v

                    try:
                        id = defs_get(ids_get(v, 'Unknown'),
                                             {'name': 'Unknown Entity %s' % v,
                                              'idStr': 'Unknown Entity %s' % v,
                                              'id': -1,
                                              'type': 'Unknown'}
                                             )['name']
                    except:
                        continue
                    if DEBUG_PE:
                        ent_def = defs_get(ids_get(v, 'Unknown'),
                                         {'name': 'Unknown Entity %s' % v,
                                          'idStr': 'Unknown Entity %s' % v,
                                          'id': -1,
                                          'type': 'Unknown'}
                                         )
                        _tn = ent_def.get('type', 'Unknown')
                        _tv = mcedit_defs['entity_types'].get(_tn, 'Unknown')
                        write_dump("* Internal ID: {id}, raw ID: {_v}, filtered ID: {_fid}, filter: {_f1} ({_f2}), type name {_tn}, type value: {_tv}\n".format(
                                                        id=id,
                                                        _v=_v,
                                                        _fid= _v & 0xff,
                                                        _f1= _v & 0xff00,
                                                        _f2= _v - (_v & 0xff),
                                                        _tn=_tn,
                                                        _tv=_tv)
                                                    )

                    ent["id"] = nbt.TAG_String(id)

                self.Entities.insert(-1, ent)
Add terrain to chunk.

        terrain, tile_entities, entities: str: 4096 long string. Defaults to 'None'.
        subchunk: int: subchunk 'height'; generaly 0 to 15 number.
        
pymclevel/leveldbpocket.py