3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
32 bool MapBlock::isValidPositionParent(v3s16 p)
34 if(isValidPosition(p))
39 return m_parent->isValidPosition(getPosRelative() + p);
43 MapNode MapBlock::getNodeParent(v3s16 p)
45 if(isValidPosition(p) == false)
47 return m_parent->getNode(getPosRelative() + p);
52 throw InvalidPositionException();
53 return data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X];
57 void MapBlock::setNodeParent(v3s16 p, MapNode & n)
59 if(isValidPosition(p) == false)
61 m_parent->setNode(getPosRelative() + p, n);
66 throw InvalidPositionException();
67 data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X] = n;
71 FastFace * MapBlock::makeFastFace(TileSpec tile, u8 light, v3f p,
72 v3s16 dir, v3f scale, v3f posRelative_f)
74 FastFace *f = new FastFace;
76 // Position is at the center of the cube.
81 // If looking towards z+, this is the face that is behind
82 // the center point, facing towards z+.
83 vertex_pos[0] = v3f( BS/2,-BS/2,BS/2);
84 vertex_pos[1] = v3f(-BS/2,-BS/2,BS/2);
85 vertex_pos[2] = v3f(-BS/2, BS/2,BS/2);
86 vertex_pos[3] = v3f( BS/2, BS/2,BS/2);
88 for(u16 i=0; i<4; i++)
90 if(dir == v3s16(0,0,1))
91 vertex_pos[i].rotateXZBy(0);
92 else if(dir == v3s16(0,0,-1))
93 vertex_pos[i].rotateXZBy(180);
94 else if(dir == v3s16(1,0,0))
95 vertex_pos[i].rotateXZBy(-90);
96 else if(dir == v3s16(-1,0,0))
97 vertex_pos[i].rotateXZBy(90);
98 else if(dir == v3s16(0,1,0))
99 vertex_pos[i].rotateYZBy(-90);
100 else if(dir == v3s16(0,-1,0))
101 vertex_pos[i].rotateYZBy(90);
103 vertex_pos[i].X *= scale.X;
104 vertex_pos[i].Y *= scale.Y;
105 vertex_pos[i].Z *= scale.Z;
106 vertex_pos[i] += pos + posRelative_f;
110 if (scale.X < 0.999 || scale.X > 1.001) abs_scale = scale.X;
111 else if(scale.Y < 0.999 || scale.Y > 1.001) abs_scale = scale.Y;
112 else if(scale.Z < 0.999 || scale.Z > 1.001) abs_scale = scale.Z;
114 v3f zerovector = v3f(0,0,0);
116 u8 li = decode_light(light);
121 if(tile.id == TILE_WATER)
126 video::SColor c = video::SColor(alpha,li,li,li);
128 f->vertices[0] = video::S3DVertex(vertex_pos[0], zerovector, c,
129 core::vector2d<f32>(0,1));
130 f->vertices[1] = video::S3DVertex(vertex_pos[1], zerovector, c,
131 core::vector2d<f32>(abs_scale,1));
132 f->vertices[2] = video::S3DVertex(vertex_pos[2], zerovector, c,
133 core::vector2d<f32>(abs_scale,0));
134 f->vertices[3] = video::S3DVertex(vertex_pos[3], zerovector, c,
135 core::vector2d<f32>(0,0));
139 //f->tile = TILE_STONE;
145 Parameters must consist of air and !air.
146 Order doesn't matter.
148 If either of the nodes doesn't exist, light is 0.
150 u8 MapBlock::getFaceLight(v3s16 p, v3s16 face_dir)
153 MapNode n = getNodeParent(p);
154 MapNode n2 = getNodeParent(p + face_dir);
156 /*if(n.solidness() < n2.solidness())
157 light = n.getLight();
159 light = n2.getLight();*/
160 if(n.getLight() > n2.getLight())
161 light = n.getLight();
163 light = n2.getLight();
165 // Make some nice difference to different sides
167 /*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1)
168 light = diminish_light(diminish_light(light));
169 else if(face_dir.X == -1 || face_dir.Z == -1)
170 light = diminish_light(light);*/
172 if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1)
173 light = diminish_light(diminish_light(light));
174 else if(face_dir.Z == 1 || face_dir.Z == -1)
175 light = diminish_light(light);
179 catch(InvalidPositionException &e)
186 Gets node tile from any place relative to block.
187 Returns TILE_NODE if doesn't exist or should not be drawn.
189 TileSpec MapBlock::getNodeTile(v3s16 p, v3s16 face_dir)
193 spec.feature = TILEFEAT_NONE;
195 MapNode n = getNodeParent(p);
197 spec.id = n.getTile(face_dir);
199 catch(InvalidPositionException &e)
205 Check temporary modifications on this node
207 core::map<v3s16, NodeMod>::Node *n;
208 n = m_temp_mods.find(p);
213 struct NodeMod mod = n->getValue();
214 if(mod.type == NODEMOD_CHANGECONTENT)
216 spec.id = content_tile(mod.param, face_dir);
218 if(mod.type == NODEMOD_CRACK)
226 u8 MapBlock::getNodeContent(v3s16 p)
229 Check temporary modifications on this node
231 core::map<v3s16, NodeMod>::Node *n;
232 n = m_temp_mods.find(p);
237 struct NodeMod mod = n->getValue();
238 if(mod.type == NODEMOD_CHANGECONTENT)
243 if(mod.type == NODEMOD_CRACK)
246 Content doesn't change.
248 face_contents works just like it should, because
249 there should not be faces between differently cracked
252 If a semi-transparent node is cracked in front an
253 another one, it really doesn't matter whether there
254 is a cracked face drawn in between or not.
260 MapNode n = getNodeParent(p);
264 catch(InvalidPositionException &e)
266 return CONTENT_IGNORE;
272 translate_dir: unit vector with only one of x, y or z
273 face_dir: unit vector with only one of x, y or z
275 void MapBlock::updateFastFaceRow(v3s16 startpos,
279 core::list<FastFace*> &dest)
282 Precalculate some variables
284 v3f translate_dir_f(translate_dir.X, translate_dir.Y,
285 translate_dir.Z); // floating point conversion
286 v3f face_dir_f(face_dir.X, face_dir.Y,
287 face_dir.Z); // floating point conversion
288 v3f posRelative_f(getPosRelative().X, getPosRelative().Y,
289 getPosRelative().Z); // floating point conversion
293 Get face light at starting position
295 u8 light = getFaceLight(p, face_dir);
297 u16 continuous_tiles_count = 0;
299 TileSpec tile0 = getNodeTile(p, face_dir);
300 TileSpec tile1 = getNodeTile(p + face_dir, -face_dir);
302 for(u16 j=0; j<length; j++)
304 bool next_is_different = true;
312 p_next = p + translate_dir;
313 tile0_next = getNodeTile(p_next, face_dir);
314 tile1_next = getNodeTile(p_next + face_dir, -face_dir);
315 light_next = getFaceLight(p_next, face_dir);
317 if(tile0_next == tile0
318 && tile1_next == tile1
319 && light_next == light)
321 next_is_different = false;
325 continuous_tiles_count++;
327 if(next_is_different)
330 Create a face if there should be one
332 //u8 mf = face_contents(tile0, tile1);
334 u8 content0 = getNodeContent(p);
335 u8 content1 = getNodeContent(p + face_dir);
336 u8 mf = face_contents(content0, content1);
340 // Floating point conversion of the position vector
341 v3f pf(p.X, p.Y, p.Z);
342 // Center point of face (kind of)
343 v3f sp = pf - ((f32)continuous_tiles_count / 2. - 0.5) * translate_dir_f;
345 if(translate_dir.X != 0){
346 scale.X = continuous_tiles_count;
348 if(translate_dir.Y != 0){
349 scale.Y = continuous_tiles_count;
351 if(translate_dir.Z != 0){
352 scale.Z = continuous_tiles_count;
357 // If node at sp (tile0) is more solid
360 f = makeFastFace(tile0, light,
364 // If node at sp is less solid (mf == 2)
367 f = makeFastFace(tile1, light,
368 sp+face_dir_f, -face_dir, scale,
374 continuous_tiles_count = 0;
385 This is used because CMeshBuffer::append() is very slow
389 video::SMaterial material;
390 core::array<u16> indices;
391 core::array<video::S3DVertex> vertices;
398 video::SMaterial material,
399 const video::S3DVertex* const vertices,
401 const u16* const indices,
405 PreMeshBuffer *p = NULL;
406 for(u32 i=0; i<m_prebuffers.size(); i++)
408 PreMeshBuffer &pp = m_prebuffers[i];
409 if(pp.material != material)
419 pp.material = material;
420 m_prebuffers.push_back(pp);
421 p = &m_prebuffers[m_prebuffers.size()-1];
424 u32 vertex_count = p->vertices.size();
425 for(u32 i=0; i<numIndices; i++)
427 u32 j = indices[i] + vertex_count;
430 dstream<<"FIXME: Meshbuffer ran out of indices"<<std::endl;
431 // NOTE: Fix is to just add an another MeshBuffer
433 p->indices.push_back(j);
435 for(u32 i=0; i<numVertices; i++)
437 p->vertices.push_back(vertices[i]);
441 void fillMesh(scene::SMesh *mesh)
443 /*dstream<<"Filling mesh with "<<m_prebuffers.size()
444 <<" meshbuffers"<<std::endl;*/
445 for(u32 i=0; i<m_prebuffers.size(); i++)
447 PreMeshBuffer &p = m_prebuffers[i];
449 /*dstream<<"p.vertices.size()="<<p.vertices.size()
450 <<", p.indices.size()="<<p.indices.size()
455 // This is a "Standard MeshBuffer",
456 // it's a typedeffed CMeshBuffer<video::S3DVertex>
457 scene::SMeshBuffer *buf = new scene::SMeshBuffer();
459 buf->Material = p.material;
460 //((scene::SMeshBuffer*)buf)->Material = p.material;
462 //buf->setHardwareMappingHint(scene::EHM_STATIC);
464 mesh->addMeshBuffer(buf);
468 buf->append(p.vertices.pointer(), p.vertices.size(),
469 p.indices.pointer(), p.indices.size());
474 core::array<PreMeshBuffer> m_prebuffers;
477 void MapBlock::updateMesh()
479 /*v3s16 p = getPosRelative();
480 std::cout<<"MapBlock("<<p.X<<","<<p.Y<<","<<p.Z<<")"
481 <<"::updateMesh(): ";*/
482 //<<"::updateMesh()"<<std::endl;
485 TODO: Change this to directly generate the mesh (and get rid
489 core::list<FastFace*> *fastfaces_new = new core::list<FastFace*>;
492 We are including the faces of the trailing edges of the block.
493 This means that when something changes, the caller must
494 also update the meshes of the blocks at the leading edges.
498 Go through every y,z and get top faces in rows of x+
500 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
501 //for(s16 y=-1; y<MAP_BLOCKSIZE; y++){
502 for(s16 z=0; z<MAP_BLOCKSIZE; z++){
503 updateFastFaceRow(v3s16(0,y,z), MAP_BLOCKSIZE,
510 Go through every x,y and get right faces in rows of z+
512 for(s16 x=0; x<MAP_BLOCKSIZE; x++){
513 //for(s16 x=-1; x<MAP_BLOCKSIZE; x++){
514 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
515 updateFastFaceRow(v3s16(x,y,0), MAP_BLOCKSIZE,
522 Go through every y,z and get back faces in rows of x+
524 for(s16 z=0; z<MAP_BLOCKSIZE; z++){
525 //for(s16 z=-1; z<MAP_BLOCKSIZE; z++){
526 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
527 updateFastFaceRow(v3s16(0,y,z), MAP_BLOCKSIZE,
534 scene::SMesh *mesh_new = NULL;
536 mesh_new = new scene::SMesh();
538 if(fastfaces_new->getSize() > 0)
540 MeshCollector collector;
542 core::list<FastFace*>::Iterator i = fastfaces_new->begin();
544 for(; i != fastfaces_new->end(); i++)
548 const u16 indices[] = {0,1,2,2,3,0};
550 if(f->tile.feature == TILEFEAT_NONE)
552 collector.append(g_tile_materials[f->tile.id], f->vertices, 4,
562 collector.fillMesh(mesh_new);
564 // Use VBO for mesh (this just would set this for ever buffer)
565 mesh_new->setHardwareMappingHint(scene::EHM_STATIC);
567 /*std::cout<<"MapBlock has "<<fastfaces_new->getSize()<<" faces "
568 <<"and uses "<<mesh_new->getMeshBufferCount()
569 <<" materials (meshbuffers)"<<std::endl;*/
573 Clear temporary FastFaces
576 core::list<FastFace*>::Iterator i;
577 i = fastfaces_new->begin();
578 for(; i != fastfaces_new->end(); i++)
582 fastfaces_new->clear();
583 delete fastfaces_new;
586 Add special graphics:
589 TODO: Optimize by using same meshbuffer for same textures
592 /*scene::ISceneManager *smgr = NULL;
593 video::IVideoDriver* driver = NULL;
596 smgr = g_device->getSceneManager();
597 driver = smgr->getVideoDriver();
600 for(s16 z=0; z<MAP_BLOCKSIZE; z++)
601 for(s16 y=0; y<MAP_BLOCKSIZE; y++)
602 for(s16 x=0; x<MAP_BLOCKSIZE; x++)
606 MapNode &n = getNodeRef(x,y,z);
608 if(n.d == CONTENT_TORCH)
610 //scene::IMeshBuffer *buf = new scene::SMeshBuffer();
611 scene::SMeshBuffer *buf = new scene::SMeshBuffer();
612 video::SColor c(255,255,255,255);
614 video::S3DVertex vertices[4] =
616 video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c, 0,1),
617 video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c, 1,1),
618 video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0),
619 video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, 0,0),
622 v3s16 dir = unpackDir(n.dir);
624 for(s32 i=0; i<4; i++)
626 if(dir == v3s16(1,0,0))
627 vertices[i].Pos.rotateXZBy(0);
628 if(dir == v3s16(-1,0,0))
629 vertices[i].Pos.rotateXZBy(180);
630 if(dir == v3s16(0,0,1))
631 vertices[i].Pos.rotateXZBy(90);
632 if(dir == v3s16(0,0,-1))
633 vertices[i].Pos.rotateXZBy(-90);
634 if(dir == v3s16(0,-1,0))
635 vertices[i].Pos.rotateXZBy(45);
636 if(dir == v3s16(0,1,0))
637 vertices[i].Pos.rotateXZBy(-45);
639 vertices[i].Pos += intToFloat(p + getPosRelative());
642 u16 indices[] = {0,1,2,2,3,0};
643 buf->append(vertices, 4, indices, 6);
646 buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
647 buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
648 buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
649 //buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
650 buf->getMaterial().MaterialType
651 = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
652 if(dir == v3s16(0,-1,0))
653 buf->getMaterial().setTexture(0,
654 g_texturecache.get("torch_on_floor"));
655 else if(dir == v3s16(0,1,0))
656 buf->getMaterial().setTexture(0,
657 g_texturecache.get("torch_on_ceiling"));
658 // For backwards compatibility
659 else if(dir == v3s16(0,0,0))
660 buf->getMaterial().setTexture(0,
661 g_texturecache.get("torch_on_floor"));
663 buf->getMaterial().setTexture(0, g_texturecache.get("torch"));
666 mesh_new->addMeshBuffer(buf);
672 Do some stuff to the mesh
675 mesh_new->recalculateBoundingBox();
678 Delete new mesh if it is empty
681 if(mesh_new->getMeshBufferCount() == 0)
693 scene::SMesh *mesh_old = mesh;
699 // Remove hardware buffers of meshbuffers of mesh
700 // NOTE: No way, this runs in a different thread and everything
701 /*u32 c = mesh_old->getMeshBufferCount();
702 for(u32 i=0; i<c; i++)
704 IMeshBuffer *buf = mesh_old->getMeshBuffer(i);
713 //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
717 Propagates sunlight down through the block.
718 Doesn't modify nodes that are not affected by sunlight.
720 Returns false if sunlight at bottom block is invalid
721 Returns true if bottom block doesn't exist.
723 If there is a block above, continues from it.
724 If there is no block above, assumes there is sunlight, unless
725 is_underground is set.
727 At the moment, all sunlighted nodes are added to light_sources.
728 TODO: This could be optimized.
730 bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources)
732 // Whether the sunlight at the top of the bottom block is valid
733 bool block_below_is_valid = true;
735 v3s16 pos_relative = getPosRelative();
737 for(s16 x=0; x<MAP_BLOCKSIZE; x++)
739 for(s16 z=0; z<MAP_BLOCKSIZE; z++)
741 bool no_sunlight = false;
742 bool no_top_block = false;
743 // Check if node above block has sunlight
745 MapNode n = getNodeParent(v3s16(x, MAP_BLOCKSIZE, z));
746 if(n.getLight() != LIGHT_SUN)
755 catch(InvalidPositionException &e)
759 // TODO: This makes over-ground roofed places sunlighted
760 // Assume sunlight, unless is_underground==true
766 // TODO: There has to be some way to allow this behaviour
767 // As of now, it just makes everything dark.
769 //no_sunlight = true;
772 /*std::cout<<"("<<x<<","<<z<<"): "
773 <<"no_top_block="<<no_top_block
774 <<", is_underground="<<is_underground
775 <<", no_sunlight="<<no_sunlight
778 s16 y = MAP_BLOCKSIZE-1;
780 if(no_sunlight == false)
782 // Continue spreading sunlight downwards through transparent
788 MapNode &n = getNodeRef(pos);
790 if(n.sunlight_propagates())
792 n.setLight(LIGHT_SUN);
794 light_sources.insert(pos_relative + pos, true);
802 bool sunlight_should_go_down = (y==-1);
804 // Fill rest with black (only transparent ones)
808 MapNode &n = getNodeRef(pos);
810 if(n.light_propagates())
820 If the block below hasn't already been marked invalid:
822 Check if the node below the block has proper sunlight at top.
823 If not, the block below is invalid.
825 Ignore non-transparent nodes as they always have no light
829 if(block_below_is_valid)
831 MapNode n = getNodeParent(v3s16(x, -1, z));
832 if(n.light_propagates())
834 if(n.getLight() == LIGHT_SUN
835 && sunlight_should_go_down == false)
836 block_below_is_valid = false;
837 else if(n.getLight() != LIGHT_SUN
838 && sunlight_should_go_down == true)
839 block_below_is_valid = false;
843 catch(InvalidPositionException &e)
845 /*std::cout<<"InvalidBlockException for bottom block node"
847 // Just no block below, no need to panic.
852 return block_below_is_valid;
855 void MapBlock::copyTo(VoxelManipulator &dst)
857 v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE);
858 VoxelArea data_area(v3s16(0,0,0), data_size - v3s16(1,1,1));
860 dst.copyFrom(data, data_area, v3s16(0,0,0),
861 getPosRelative(), data_size);
864 /*void getPseudoObjects(v3f origin, f32 max_d,
865 core::array<DistanceSortedObject> &dest)
873 void MapBlock::serialize(std::ostream &os, u8 version)
875 if(!ser_ver_supported(version))
876 throw VersionMismatchException("ERROR: MapBlock format not supported");
880 throw SerializationError("ERROR: Not writing dummy block.");
883 // These have no compression
884 if(version <= 3 || version == 5 || version == 6)
886 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
888 u32 buflen = 1 + nodecount * MapNode::serializedLength(version);
889 SharedBuffer<u8> dest(buflen);
891 dest[0] = is_underground;
892 for(u32 i=0; i<nodecount; i++)
894 u32 s = 1 + i * MapNode::serializedLength(version);
895 data[i].serialize(&dest[s], version);
898 os.write((char*)*dest, dest.getSize());
900 else if(version <= 10)
904 Compress the materials and the params separately.
908 os.write((char*)&is_underground, 1);
910 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
912 // Get and compress materials
913 SharedBuffer<u8> materialdata(nodecount);
914 for(u32 i=0; i<nodecount; i++)
916 materialdata[i] = data[i].d;
918 compress(materialdata, os, version);
920 // Get and compress lights
921 SharedBuffer<u8> lightdata(nodecount);
922 for(u32 i=0; i<nodecount; i++)
924 lightdata[i] = data[i].param;
926 compress(lightdata, os, version);
930 // Get and compress pressure
931 SharedBuffer<u8> pressuredata(nodecount);
932 for(u32 i=0; i<nodecount; i++)
934 pressuredata[i] = data[i].pressure;
936 compress(pressuredata, os, version);
939 // All other versions (newest)
943 os.write((char*)&is_underground, 1);
945 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
951 SharedBuffer<u8> databuf(nodecount*3);
954 for(u32 i=0; i<nodecount; i++)
956 databuf[i] = data[i].d;
960 for(u32 i=0; i<nodecount; i++)
962 databuf[i+nodecount] = data[i].param;
966 for(u32 i=0; i<nodecount; i++)
968 databuf[i+nodecount*2] = data[i].pressure;
972 Compress data to output stream
975 compress(databuf, os, version);
979 void MapBlock::deSerialize(std::istream &is, u8 version)
981 if(!ser_ver_supported(version))
982 throw VersionMismatchException("ERROR: MapBlock format not supported");
984 // These have no compression
985 if(version <= 3 || version == 5 || version == 6)
987 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
991 throw SerializationError
992 ("MapBlock::deSerialize: no enough input data");
993 is_underground = tmp;
994 for(u32 i=0; i<nodecount; i++)
996 s32 len = MapNode::serializedLength(version);
997 SharedBuffer<u8> d(len);
998 is.read((char*)*d, len);
999 if(is.gcount() != len)
1000 throw SerializationError
1001 ("MapBlock::deSerialize: no enough input data");
1002 data[i].deSerialize(*d, version);
1005 else if(version <= 10)
1007 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1010 is.read((char*)&t8, 1);
1011 is_underground = t8;
1014 // Uncompress and set material data
1015 std::ostringstream os(std::ios_base::binary);
1016 decompress(is, os, version);
1017 std::string s = os.str();
1018 if(s.size() != nodecount)
1019 throw SerializationError
1020 ("MapBlock::deSerialize: invalid format");
1021 for(u32 i=0; i<s.size(); i++)
1027 // Uncompress and set param data
1028 std::ostringstream os(std::ios_base::binary);
1029 decompress(is, os, version);
1030 std::string s = os.str();
1031 if(s.size() != nodecount)
1032 throw SerializationError
1033 ("MapBlock::deSerialize: invalid format");
1034 for(u32 i=0; i<s.size(); i++)
1036 data[i].param = s[i];
1042 // Uncompress and set pressure data
1043 std::ostringstream os(std::ios_base::binary);
1044 decompress(is, os, version);
1045 std::string s = os.str();
1046 if(s.size() != nodecount)
1047 throw SerializationError
1048 ("MapBlock::deSerialize: invalid format");
1049 for(u32 i=0; i<s.size(); i++)
1051 data[i].pressure = s[i];
1055 // All other versions (newest)
1058 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1061 is.read((char*)&t8, 1);
1062 is_underground = t8;
1065 std::ostringstream os(std::ios_base::binary);
1066 decompress(is, os, version);
1067 std::string s = os.str();
1068 if(s.size() != nodecount*3)
1069 throw SerializationError
1070 ("MapBlock::deSerialize: invalid format");
1073 for(u32 i=0; i<nodecount; i++)
1078 for(u32 i=0; i<nodecount; i++)
1080 data[i].param = s[i+nodecount];
1083 for(u32 i=0; i<nodecount; i++)
1085 data[i].pressure = s[i+nodecount*2];