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(u16 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(material == CONTENT_WATER || material == CONTENT_OCEAN)
123 //if(tile == CONTENT_WATER || tile == CONTENT_OCEAN)
124 if(tile == TILE_WATER)
129 video::SColor c = video::SColor(alpha,li,li,li);
131 f->vertices[0] = video::S3DVertex(vertex_pos[0], zerovector, c,
132 core::vector2d<f32>(0,1));
133 f->vertices[1] = video::S3DVertex(vertex_pos[1], zerovector, c,
134 core::vector2d<f32>(abs_scale,1));
135 f->vertices[2] = video::S3DVertex(vertex_pos[2], zerovector, c,
136 core::vector2d<f32>(abs_scale,0));
137 f->vertices[3] = video::S3DVertex(vertex_pos[3], zerovector, c,
138 core::vector2d<f32>(0,0));
142 //f->tile = TILE_GRASS;
148 Parameters must consist of air and !air.
149 Order doesn't matter.
151 If either of the nodes doesn't exist, light is 0.
153 u8 MapBlock::getFaceLight(v3s16 p, v3s16 face_dir)
156 MapNode n = getNodeParent(p);
157 MapNode n2 = getNodeParent(p + face_dir);
159 /*if(n.solidness() < n2.solidness())
160 light = n.getLight();
162 light = n2.getLight();*/
163 if(n.getLight() > n2.getLight())
164 light = n.getLight();
166 light = n2.getLight();
168 // Make some nice difference to different sides
170 /*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1)
171 light = diminish_light(diminish_light(light));
172 else if(face_dir.X == -1 || face_dir.Z == -1)
173 light = diminish_light(light);*/
175 if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1)
176 light = diminish_light(diminish_light(light));
177 else if(face_dir.Z == 1 || face_dir.Z == -1)
178 light = diminish_light(light);
182 catch(InvalidPositionException &e)
189 Gets node tile from any place relative to block.
190 Returns CONTENT_IGNORE if doesn't exist or should not be drawn.
192 u16 MapBlock::getNodeTile(v3s16 p, v3s16 face_dir)
195 MapNode n = getNodeParent(p);
197 //return content_tile(n.d);
198 return n.getTile(face_dir);
200 catch(InvalidPositionException &e)
202 //return CONTENT_IGNORE;
207 u8 MapBlock::getNodeContent(v3s16 p)
210 MapNode n = getNodeParent(p);
214 catch(InvalidPositionException &e)
216 return CONTENT_IGNORE;
222 translate_dir: unit vector with only one of x, y or z
223 face_dir: unit vector with only one of x, y or z
225 void MapBlock::updateFastFaceRow(v3s16 startpos,
229 core::list<FastFace*> &dest)
232 Precalculate some variables
234 v3f translate_dir_f(translate_dir.X, translate_dir.Y,
235 translate_dir.Z); // floating point conversion
236 v3f face_dir_f(face_dir.X, face_dir.Y,
237 face_dir.Z); // floating point conversion
238 v3f posRelative_f(getPosRelative().X, getPosRelative().Y,
239 getPosRelative().Z); // floating point conversion
243 Get face light at starting position
245 u8 light = getFaceLight(p, face_dir);
247 u16 continuous_tiles_count = 0;
249 u8 tile0 = getNodeTile(p, face_dir);
250 u8 tile1 = getNodeTile(p + face_dir, -face_dir);
252 for(u16 j=0; j<length; j++)
254 bool next_is_different = true;
262 p_next = p + translate_dir;
263 tile0_next = getNodeTile(p_next, face_dir);
264 tile1_next = getNodeTile(p_next + face_dir, -face_dir);
265 light_next = getFaceLight(p_next, face_dir);
267 if(tile0_next == tile0
268 && tile1_next == tile1
269 && light_next == light)
271 next_is_different = false;
275 continuous_tiles_count++;
277 if(next_is_different)
280 Create a face if there should be one
282 //u8 mf = face_contents(tile0, tile1);
284 u8 content0 = getNodeContent(p);
285 u8 content1 = getNodeContent(p + face_dir);
286 u8 mf = face_contents(content0, content1);
290 // Floating point conversion of the position vector
291 v3f pf(p.X, p.Y, p.Z);
292 // Center point of face (kind of)
293 v3f sp = pf - ((f32)continuous_tiles_count / 2. - 0.5) * translate_dir_f;
295 if(translate_dir.X != 0){
296 scale.X = continuous_tiles_count;
298 if(translate_dir.Y != 0){
299 scale.Y = continuous_tiles_count;
301 if(translate_dir.Z != 0){
302 scale.Z = continuous_tiles_count;
307 // If node at sp (tile0) is more solid
310 f = makeFastFace(tile0, light,
314 // If node at sp is less solid (mf == 2)
317 f = makeFastFace(tile1, light,
318 sp+face_dir_f, -face_dir, scale,
324 continuous_tiles_count = 0;
335 This is used because CMeshBuffer::append() is very slow
339 video::SMaterial material;
340 core::array<u16> indices;
341 core::array<video::S3DVertex> vertices;
348 video::SMaterial material,
349 const video::S3DVertex* const vertices,
351 const u16* const indices,
355 PreMeshBuffer *p = NULL;
356 for(u32 i=0; i<m_prebuffers.size(); i++)
358 PreMeshBuffer &pp = m_prebuffers[i];
359 if(pp.material != material)
369 pp.material = material;
370 m_prebuffers.push_back(pp);
371 p = &m_prebuffers[m_prebuffers.size()-1];
374 u32 vertex_count = p->vertices.size();
375 for(u32 i=0; i<numIndices; i++)
377 u32 j = indices[i] + vertex_count;
380 dstream<<"FIXME: Meshbuffer ran out of indices"<<std::endl;
381 // NOTE: Fix is to just add an another MeshBuffer
383 p->indices.push_back(j);
385 for(u32 i=0; i<numVertices; i++)
387 p->vertices.push_back(vertices[i]);
391 void fillMesh(scene::SMesh *mesh)
393 /*dstream<<"Filling mesh with "<<m_prebuffers.size()
394 <<" meshbuffers"<<std::endl;*/
395 for(u32 i=0; i<m_prebuffers.size(); i++)
397 PreMeshBuffer &p = m_prebuffers[i];
399 /*dstream<<"p.vertices.size()="<<p.vertices.size()
400 <<", p.indices.size()="<<p.indices.size()
405 // This is a "Standard MeshBuffer",
406 // it's a typedeffed CMeshBuffer<video::S3DVertex>
407 scene::SMeshBuffer *buf = new scene::SMeshBuffer();
409 buf->Material = p.material;
410 //((scene::SMeshBuffer*)buf)->Material = p.material;
412 //buf->setHardwareMappingHint(scene::EHM_STATIC);
414 mesh->addMeshBuffer(buf);
418 buf->append(p.vertices.pointer(), p.vertices.size(),
419 p.indices.pointer(), p.indices.size());
424 core::array<PreMeshBuffer> m_prebuffers;
427 void MapBlock::updateMesh()
429 /*v3s16 p = getPosRelative();
430 std::cout<<"MapBlock("<<p.X<<","<<p.Y<<","<<p.Z<<")"
431 <<"::updateMesh(): ";*/
432 //<<"::updateMesh()"<<std::endl;
435 TODO: Change this to directly generate the mesh (and get rid
439 core::list<FastFace*> *fastfaces_new = new core::list<FastFace*>;
442 We are including the faces of the trailing edges of the block.
443 This means that when something changes, the caller must
444 also update the meshes of the blocks at the leading edges.
448 Go through every y,z and get top faces in rows of x+
450 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
451 //for(s16 y=-1; y<MAP_BLOCKSIZE; y++){
452 for(s16 z=0; z<MAP_BLOCKSIZE; z++){
453 updateFastFaceRow(v3s16(0,y,z), MAP_BLOCKSIZE,
460 Go through every x,y and get right faces in rows of z+
462 for(s16 x=0; x<MAP_BLOCKSIZE; x++){
463 //for(s16 x=-1; x<MAP_BLOCKSIZE; x++){
464 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
465 updateFastFaceRow(v3s16(x,y,0), MAP_BLOCKSIZE,
472 Go through every y,z and get back faces in rows of x+
474 for(s16 z=0; z<MAP_BLOCKSIZE; z++){
475 //for(s16 z=-1; z<MAP_BLOCKSIZE; z++){
476 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
477 updateFastFaceRow(v3s16(0,y,z), MAP_BLOCKSIZE,
484 scene::SMesh *mesh_new = NULL;
486 mesh_new = new scene::SMesh();
488 if(fastfaces_new->getSize() > 0)
490 MeshCollector collector;
492 core::list<FastFace*>::Iterator i = fastfaces_new->begin();
494 for(; i != fastfaces_new->end(); i++)
498 const u16 indices[] = {0,1,2,2,3,0};
500 /*collector.append(g_materials[f->material], f->vertices, 4,
502 /*collector.append(g_materials[f->tile], f->vertices, 4,
504 collector.append(g_tile_materials[f->tile], f->vertices, 4,
508 collector.fillMesh(mesh_new);
510 // Use VBO for mesh (this just would set this for ever buffer)
511 //mesh_new->setHardwareMappingHint(scene::EHM_STATIC);
513 /*std::cout<<"MapBlock has "<<fastfaces_new->getSize()<<" faces "
514 <<"and uses "<<mesh_new->getMeshBufferCount()
515 <<" materials (meshbuffers)"<<std::endl;*/
519 Clear temporary FastFaces
522 core::list<FastFace*>::Iterator i;
523 i = fastfaces_new->begin();
524 for(; i != fastfaces_new->end(); i++)
528 fastfaces_new->clear();
529 delete fastfaces_new;
532 Add special graphics:
535 TODO: Optimize by using same meshbuffer for same textures
538 /*scene::ISceneManager *smgr = NULL;
539 video::IVideoDriver* driver = NULL;
542 smgr = g_device->getSceneManager();
543 driver = smgr->getVideoDriver();
546 for(s16 z=0; z<MAP_BLOCKSIZE; z++)
547 for(s16 y=0; y<MAP_BLOCKSIZE; y++)
548 for(s16 x=0; x<MAP_BLOCKSIZE; x++)
552 MapNode &n = getNodeRef(x,y,z);
554 if(n.d == CONTENT_LIGHT)
556 //scene::IMeshBuffer *buf = new scene::SMeshBuffer();
557 scene::SMeshBuffer *buf = new scene::SMeshBuffer();
558 video::SColor c(255,255,255,255);
560 video::S3DVertex vertices[4] =
562 video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c, 0,1),
563 video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c, 1,1),
564 video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0),
565 video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, 0,0),
568 v3s16 dir = unpackDir(n.dir);
570 for(s32 i=0; i<4; i++)
572 if(dir == v3s16(1,0,0))
573 vertices[i].Pos.rotateXZBy(0);
574 if(dir == v3s16(-1,0,0))
575 vertices[i].Pos.rotateXZBy(180);
576 if(dir == v3s16(0,0,1))
577 vertices[i].Pos.rotateXZBy(90);
578 if(dir == v3s16(0,0,-1))
579 vertices[i].Pos.rotateXZBy(-90);
580 if(dir == v3s16(0,-1,0))
581 vertices[i].Pos.rotateXZBy(45);
582 if(dir == v3s16(0,1,0))
583 vertices[i].Pos.rotateXZBy(-45);
585 vertices[i].Pos += intToFloat(p + getPosRelative());
588 u16 indices[] = {0,1,2,2,3,0};
589 buf->append(vertices, 4, indices, 6);
592 buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
593 buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
594 buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
595 //buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
596 buf->getMaterial().MaterialType
597 = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
598 if(dir == v3s16(0,-1,0))
599 buf->getMaterial().setTexture(0,
600 g_texturecache.get("torch_on_floor"));
601 else if(dir == v3s16(0,1,0))
602 buf->getMaterial().setTexture(0,
603 g_texturecache.get("torch_on_ceiling"));
604 // For backwards compatibility
605 else if(dir == v3s16(0,0,0))
606 buf->getMaterial().setTexture(0,
607 g_texturecache.get("torch_on_floor"));
609 buf->getMaterial().setTexture(0, g_texturecache.get("torch"));
612 mesh_new->addMeshBuffer(buf);
618 Do some stuff to the mesh
621 mesh_new->recalculateBoundingBox();
624 Delete new mesh if it is empty
627 if(mesh_new->getMeshBufferCount() == 0)
639 scene::SMesh *mesh_old = mesh;
645 // Remove hardware buffers of meshbuffers of mesh
646 // NOTE: No way, this runs in a different thread and everything
647 /*u32 c = mesh_old->getMeshBufferCount();
648 for(u32 i=0; i<c; i++)
650 IMeshBuffer *buf = mesh_old->getMeshBuffer(i);
659 //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
663 Propagates sunlight down through the block.
664 Doesn't modify nodes that are not affected by sunlight.
666 Returns false if sunlight at bottom block is invalid
667 Returns true if bottom block doesn't exist.
669 If there is a block above, continues from it.
670 If there is no block above, assumes there is sunlight, unless
671 is_underground is set.
673 At the moment, all sunlighted nodes are added to light_sources.
674 TODO: This could be optimized.
676 bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources)
678 // Whether the sunlight at the top of the bottom block is valid
679 bool block_below_is_valid = true;
681 v3s16 pos_relative = getPosRelative();
683 for(s16 x=0; x<MAP_BLOCKSIZE; x++)
685 for(s16 z=0; z<MAP_BLOCKSIZE; z++)
687 bool no_sunlight = false;
688 bool no_top_block = false;
689 // Check if node above block has sunlight
691 MapNode n = getNodeParent(v3s16(x, MAP_BLOCKSIZE, z));
692 if(n.getLight() != LIGHT_SUN)
701 catch(InvalidPositionException &e)
705 // TODO: This makes over-ground roofed places sunlighted
706 // Assume sunlight, unless is_underground==true
712 // TODO: There has to be some way to allow this behaviour
713 // As of now, it just makes everything dark.
715 //no_sunlight = true;
718 /*std::cout<<"("<<x<<","<<z<<"): "
719 <<"no_top_block="<<no_top_block
720 <<", is_underground="<<is_underground
721 <<", no_sunlight="<<no_sunlight
724 s16 y = MAP_BLOCKSIZE-1;
726 if(no_sunlight == false)
728 // Continue spreading sunlight downwards through transparent
734 MapNode &n = getNodeRef(pos);
736 if(n.sunlight_propagates())
738 n.setLight(LIGHT_SUN);
740 light_sources.insert(pos_relative + pos, true);
748 bool sunlight_should_go_down = (y==-1);
750 // Fill rest with black (only transparent ones)
754 MapNode &n = getNodeRef(pos);
756 if(n.light_propagates())
766 If the block below hasn't already been marked invalid:
768 Check if the node below the block has proper sunlight at top.
769 If not, the block below is invalid.
771 Ignore non-transparent nodes as they always have no light
775 if(block_below_is_valid)
777 MapNode n = getNodeParent(v3s16(x, -1, z));
778 if(n.light_propagates())
780 if(n.getLight() == LIGHT_SUN
781 && sunlight_should_go_down == false)
782 block_below_is_valid = false;
783 else if(n.getLight() != LIGHT_SUN
784 && sunlight_should_go_down == true)
785 block_below_is_valid = false;
789 catch(InvalidPositionException &e)
791 /*std::cout<<"InvalidBlockException for bottom block node"
793 // Just no block below, no need to panic.
798 return block_below_is_valid;
801 void MapBlock::copyTo(VoxelManipulator &dst)
803 v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE);
804 VoxelArea data_area(v3s16(0,0,0), data_size - v3s16(1,1,1));
806 dst.copyFrom(data, data_area, v3s16(0,0,0),
807 getPosRelative(), data_size);
810 /*void getPseudoObjects(v3f origin, f32 max_d,
811 core::array<DistanceSortedObject> &dest)
819 void MapBlock::serialize(std::ostream &os, u8 version)
821 if(!ser_ver_supported(version))
822 throw VersionMismatchException("ERROR: MapBlock format not supported");
826 throw SerializationError("ERROR: Not writing dummy block.");
829 // These have no compression
830 if(version <= 3 || version == 5 || version == 6)
832 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
834 u32 buflen = 1 + nodecount * MapNode::serializedLength(version);
835 SharedBuffer<u8> dest(buflen);
837 dest[0] = is_underground;
838 for(u32 i=0; i<nodecount; i++)
840 u32 s = 1 + i * MapNode::serializedLength(version);
841 data[i].serialize(&dest[s], version);
844 os.write((char*)*dest, dest.getSize());
846 else if(version <= 10)
850 Compress the materials and the params separately.
854 os.write((char*)&is_underground, 1);
856 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
858 // Get and compress materials
859 SharedBuffer<u8> materialdata(nodecount);
860 for(u32 i=0; i<nodecount; i++)
862 materialdata[i] = data[i].d;
864 compress(materialdata, os, version);
866 // Get and compress lights
867 SharedBuffer<u8> lightdata(nodecount);
868 for(u32 i=0; i<nodecount; i++)
870 lightdata[i] = data[i].param;
872 compress(lightdata, os, version);
876 // Get and compress pressure
877 SharedBuffer<u8> pressuredata(nodecount);
878 for(u32 i=0; i<nodecount; i++)
880 pressuredata[i] = data[i].pressure;
882 compress(pressuredata, os, version);
885 // All other versions (newest)
889 os.write((char*)&is_underground, 1);
891 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
897 SharedBuffer<u8> databuf(nodecount*3);
900 for(u32 i=0; i<nodecount; i++)
902 databuf[i] = data[i].d;
906 for(u32 i=0; i<nodecount; i++)
908 databuf[i+nodecount] = data[i].param;
912 for(u32 i=0; i<nodecount; i++)
914 databuf[i+nodecount*2] = data[i].pressure;
918 Compress data to output stream
921 compress(databuf, os, version);
925 void MapBlock::deSerialize(std::istream &is, u8 version)
927 if(!ser_ver_supported(version))
928 throw VersionMismatchException("ERROR: MapBlock format not supported");
930 // These have no compression
931 if(version <= 3 || version == 5 || version == 6)
933 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
937 throw SerializationError
938 ("MapBlock::deSerialize: no enough input data");
939 is_underground = tmp;
940 for(u32 i=0; i<nodecount; i++)
942 s32 len = MapNode::serializedLength(version);
943 SharedBuffer<u8> d(len);
944 is.read((char*)*d, len);
945 if(is.gcount() != len)
946 throw SerializationError
947 ("MapBlock::deSerialize: no enough input data");
948 data[i].deSerialize(*d, version);
951 else if(version <= 10)
953 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
956 is.read((char*)&t8, 1);
960 // Uncompress and set material data
961 std::ostringstream os(std::ios_base::binary);
962 decompress(is, os, version);
963 std::string s = os.str();
964 if(s.size() != nodecount)
965 throw SerializationError
966 ("MapBlock::deSerialize: invalid format");
967 for(u32 i=0; i<s.size(); i++)
973 // Uncompress and set param data
974 std::ostringstream os(std::ios_base::binary);
975 decompress(is, os, version);
976 std::string s = os.str();
977 if(s.size() != nodecount)
978 throw SerializationError
979 ("MapBlock::deSerialize: invalid format");
980 for(u32 i=0; i<s.size(); i++)
982 data[i].param = s[i];
988 // Uncompress and set pressure data
989 std::ostringstream os(std::ios_base::binary);
990 decompress(is, os, version);
991 std::string s = os.str();
992 if(s.size() != nodecount)
993 throw SerializationError
994 ("MapBlock::deSerialize: invalid format");
995 for(u32 i=0; i<s.size(); i++)
997 data[i].pressure = s[i];
1001 // All other versions (newest)
1004 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1007 is.read((char*)&t8, 1);
1008 is_underground = t8;
1011 std::ostringstream os(std::ios_base::binary);
1012 decompress(is, os, version);
1013 std::string s = os.str();
1014 if(s.size() != nodecount*3)
1015 throw SerializationError
1016 ("MapBlock::deSerialize: invalid format");
1019 for(u32 i=0; i<nodecount; i++)
1024 for(u32 i=0; i<nodecount; i++)
1026 data[i].param = s[i+nodecount];
1029 for(u32 i=0; i<nodecount; i++)
1031 data[i].pressure = s[i+nodecount*2];