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(u32 daylight_factor, v3s16 p, v3s16 face_dir)
153 MapNode n = getNodeParent(p);
154 MapNode n2 = getNodeParent(p + face_dir);
156 u8 l1 = n.getLightBlend(daylight_factor);
157 u8 l2 = n2.getLightBlend(daylight_factor);
163 // Make some nice difference to different sides
165 /*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1)
166 light = diminish_light(diminish_light(light));
167 else if(face_dir.X == -1 || face_dir.Z == -1)
168 light = diminish_light(light);*/
170 if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1)
171 light = diminish_light(diminish_light(light));
172 else if(face_dir.Z == 1 || face_dir.Z == -1)
173 light = diminish_light(light);
177 catch(InvalidPositionException &e)
184 Gets node tile from any place relative to block.
185 Returns TILE_NODE if doesn't exist or should not be drawn.
187 TileSpec MapBlock::getNodeTile(v3s16 p, v3s16 face_dir)
191 spec.feature = TILEFEAT_NONE;
193 MapNode n = getNodeParent(p);
195 spec.id = n.getTile(face_dir);
197 catch(InvalidPositionException &e)
203 Check temporary modifications on this node
205 core::map<v3s16, NodeMod>::Node *n;
206 n = m_temp_mods.find(p);
211 struct NodeMod mod = n->getValue();
212 if(mod.type == NODEMOD_CHANGECONTENT)
214 spec.id = content_tile(mod.param, face_dir);
216 if(mod.type == NODEMOD_CRACK)
224 u8 MapBlock::getNodeContent(v3s16 p)
227 Check temporary modifications on this node
229 core::map<v3s16, NodeMod>::Node *n;
230 n = m_temp_mods.find(p);
235 struct NodeMod mod = n->getValue();
236 if(mod.type == NODEMOD_CHANGECONTENT)
241 if(mod.type == NODEMOD_CRACK)
244 Content doesn't change.
246 face_contents works just like it should, because
247 there should not be faces between differently cracked
250 If a semi-transparent node is cracked in front an
251 another one, it really doesn't matter whether there
252 is a cracked face drawn in between or not.
258 MapNode n = getNodeParent(p);
262 catch(InvalidPositionException &e)
264 return CONTENT_IGNORE;
270 translate_dir: unit vector with only one of x, y or z
271 face_dir: unit vector with only one of x, y or z
273 void MapBlock::updateFastFaceRow(
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(daylight_factor, 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(daylight_factor, 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(u32 daylight_factor)
479 /*v3s16 p = getPosRelative();
480 std::cout<<"MapBlock("<<p.X<<","<<p.Y<<","<<p.Z<<")"
481 <<"::updateMesh(): ";*/
482 //<<"::updateMesh()"<<std::endl;
483 TimeTaker timer1("updateMesh()", g_device);
486 TODO: Change this to directly generate the mesh (and get rid
490 core::list<FastFace*> *fastfaces_new = new core::list<FastFace*>;
493 We are including the faces of the trailing edges of the block.
494 This means that when something changes, the caller must
495 also update the meshes of the blocks at the leading edges.
497 NOTE: This is the slowest part of this method. The other parts
498 take around 0ms, this takes around 15-70ms.
502 Go through every y,z and get top faces in rows of x+
504 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
505 //for(s16 y=-1; y<MAP_BLOCKSIZE; y++){
506 for(s16 z=0; z<MAP_BLOCKSIZE; z++){
507 updateFastFaceRow(daylight_factor,
508 v3s16(0,y,z), MAP_BLOCKSIZE,
515 Go through every x,y and get right faces in rows of z+
517 for(s16 x=0; x<MAP_BLOCKSIZE; x++){
518 //for(s16 x=-1; x<MAP_BLOCKSIZE; x++){
519 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
520 updateFastFaceRow(daylight_factor,
521 v3s16(x,y,0), MAP_BLOCKSIZE,
528 Go through every y,z and get back faces in rows of x+
530 for(s16 z=0; z<MAP_BLOCKSIZE; z++){
531 //for(s16 z=-1; z<MAP_BLOCKSIZE; z++){
532 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
533 updateFastFaceRow(daylight_factor,
534 v3s16(0,y,z), MAP_BLOCKSIZE,
541 scene::SMesh *mesh_new = NULL;
543 mesh_new = new scene::SMesh();
545 if(fastfaces_new->getSize() > 0)
547 MeshCollector collector;
549 core::list<FastFace*>::Iterator i = fastfaces_new->begin();
551 for(; i != fastfaces_new->end(); i++)
555 const u16 indices[] = {0,1,2,2,3,0};
557 if(f->tile.feature == TILEFEAT_NONE)
559 collector.append(g_tile_materials[f->tile.id], f->vertices, 4,
569 collector.fillMesh(mesh_new);
571 // Use VBO for mesh (this just would set this for ever buffer)
572 mesh_new->setHardwareMappingHint(scene::EHM_STATIC);
574 /*std::cout<<"MapBlock has "<<fastfaces_new->getSize()<<" faces "
575 <<"and uses "<<mesh_new->getMeshBufferCount()
576 <<" materials (meshbuffers)"<<std::endl;*/
580 Clear temporary FastFaces
583 core::list<FastFace*>::Iterator i;
584 i = fastfaces_new->begin();
585 for(; i != fastfaces_new->end(); i++)
589 fastfaces_new->clear();
590 delete fastfaces_new;
593 Add special graphics:
596 TODO: Optimize by using same meshbuffer for same textures
599 /*scene::ISceneManager *smgr = NULL;
600 video::IVideoDriver* driver = NULL;
603 smgr = g_device->getSceneManager();
604 driver = smgr->getVideoDriver();
607 for(s16 z=0; z<MAP_BLOCKSIZE; z++)
608 for(s16 y=0; y<MAP_BLOCKSIZE; y++)
609 for(s16 x=0; x<MAP_BLOCKSIZE; x++)
613 MapNode &n = getNodeRef(x,y,z);
615 if(n.d == CONTENT_TORCH)
617 //scene::IMeshBuffer *buf = new scene::SMeshBuffer();
618 scene::SMeshBuffer *buf = new scene::SMeshBuffer();
619 video::SColor c(255,255,255,255);
621 video::S3DVertex vertices[4] =
623 video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c, 0,1),
624 video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c, 1,1),
625 video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0),
626 video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, 0,0),
629 v3s16 dir = unpackDir(n.dir);
631 for(s32 i=0; i<4; i++)
633 if(dir == v3s16(1,0,0))
634 vertices[i].Pos.rotateXZBy(0);
635 if(dir == v3s16(-1,0,0))
636 vertices[i].Pos.rotateXZBy(180);
637 if(dir == v3s16(0,0,1))
638 vertices[i].Pos.rotateXZBy(90);
639 if(dir == v3s16(0,0,-1))
640 vertices[i].Pos.rotateXZBy(-90);
641 if(dir == v3s16(0,-1,0))
642 vertices[i].Pos.rotateXZBy(45);
643 if(dir == v3s16(0,1,0))
644 vertices[i].Pos.rotateXZBy(-45);
646 vertices[i].Pos += intToFloat(p + getPosRelative());
649 u16 indices[] = {0,1,2,2,3,0};
650 buf->append(vertices, 4, indices, 6);
653 buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
654 buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
655 buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
656 //buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
657 buf->getMaterial().MaterialType
658 = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
659 if(dir == v3s16(0,-1,0))
660 buf->getMaterial().setTexture(0,
661 g_texturecache.get("torch_on_floor"));
662 else if(dir == v3s16(0,1,0))
663 buf->getMaterial().setTexture(0,
664 g_texturecache.get("torch_on_ceiling"));
665 // For backwards compatibility
666 else if(dir == v3s16(0,0,0))
667 buf->getMaterial().setTexture(0,
668 g_texturecache.get("torch_on_floor"));
670 buf->getMaterial().setTexture(0, g_texturecache.get("torch"));
673 mesh_new->addMeshBuffer(buf);
679 Do some stuff to the mesh
682 mesh_new->recalculateBoundingBox();
685 Delete new mesh if it is empty
688 if(mesh_new->getMeshBufferCount() == 0)
700 scene::SMesh *mesh_old = mesh;
703 setMeshExpired(false);
707 // Remove hardware buffers of meshbuffers of mesh
708 // NOTE: No way, this runs in a different thread and everything
709 /*u32 c = mesh_old->getMeshBufferCount();
710 for(u32 i=0; i<c; i++)
712 IMeshBuffer *buf = mesh_old->getMeshBuffer(i);
721 //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
725 Propagates sunlight down through the block.
726 Doesn't modify nodes that are not affected by sunlight.
728 Returns false if sunlight at bottom block is invalid
729 Returns true if bottom block doesn't exist.
731 If there is a block above, continues from it.
732 If there is no block above, assumes there is sunlight, unless
733 is_underground is set.
735 At the moment, all sunlighted nodes are added to light_sources.
736 TODO: This could be optimized.
738 bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources)
740 // Whether the sunlight at the top of the bottom block is valid
741 bool block_below_is_valid = true;
743 v3s16 pos_relative = getPosRelative();
745 for(s16 x=0; x<MAP_BLOCKSIZE; x++)
747 for(s16 z=0; z<MAP_BLOCKSIZE; z++)
749 bool no_sunlight = false;
750 bool no_top_block = false;
751 // Check if node above block has sunlight
753 MapNode n = getNodeParent(v3s16(x, MAP_BLOCKSIZE, z));
754 if(n.getLight(LIGHTBANK_DAY) != LIGHT_SUN)
763 catch(InvalidPositionException &e)
767 // TODO: This makes over-ground roofed places sunlighted
768 // Assume sunlight, unless is_underground==true
774 // TODO: There has to be some way to allow this behaviour
775 // As of now, it just makes everything dark.
777 //no_sunlight = true;
780 /*std::cout<<"("<<x<<","<<z<<"): "
781 <<"no_top_block="<<no_top_block
782 <<", is_underground="<<is_underground
783 <<", no_sunlight="<<no_sunlight
786 s16 y = MAP_BLOCKSIZE-1;
788 if(no_sunlight == false)
790 // Continue spreading sunlight downwards through transparent
796 MapNode &n = getNodeRef(pos);
798 if(n.sunlight_propagates())
800 n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
802 light_sources.insert(pos_relative + pos, true);
810 bool sunlight_should_go_down = (y==-1);
812 // Fill rest with black (only transparent ones)
816 MapNode &n = getNodeRef(pos);
818 if(n.light_propagates())
820 n.setLight(LIGHTBANK_DAY, 0);
828 If the block below hasn't already been marked invalid:
830 Check if the node below the block has proper sunlight at top.
831 If not, the block below is invalid.
833 Ignore non-transparent nodes as they always have no light
837 if(block_below_is_valid)
839 MapNode n = getNodeParent(v3s16(x, -1, z));
840 if(n.light_propagates())
842 if(n.getLight(LIGHTBANK_DAY) == LIGHT_SUN
843 && sunlight_should_go_down == false)
844 block_below_is_valid = false;
845 else if(n.getLight(LIGHTBANK_DAY) != LIGHT_SUN
846 && sunlight_should_go_down == true)
847 block_below_is_valid = false;
851 catch(InvalidPositionException &e)
853 /*std::cout<<"InvalidBlockException for bottom block node"
855 // Just no block below, no need to panic.
860 return block_below_is_valid;
863 void MapBlock::copyTo(VoxelManipulator &dst)
865 v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE);
866 VoxelArea data_area(v3s16(0,0,0), data_size - v3s16(1,1,1));
868 dst.copyFrom(data, data_area, v3s16(0,0,0),
869 getPosRelative(), data_size);
872 /*void getPseudoObjects(v3f origin, f32 max_d,
873 core::array<DistanceSortedObject> &dest)
881 void MapBlock::serialize(std::ostream &os, u8 version)
883 if(!ser_ver_supported(version))
884 throw VersionMismatchException("ERROR: MapBlock format not supported");
888 throw SerializationError("ERROR: Not writing dummy block.");
891 // These have no compression
892 if(version <= 3 || version == 5 || version == 6)
894 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
896 u32 buflen = 1 + nodecount * MapNode::serializedLength(version);
897 SharedBuffer<u8> dest(buflen);
899 dest[0] = is_underground;
900 for(u32 i=0; i<nodecount; i++)
902 u32 s = 1 + i * MapNode::serializedLength(version);
903 data[i].serialize(&dest[s], version);
906 os.write((char*)*dest, dest.getSize());
908 else if(version <= 10)
912 Compress the materials and the params separately.
916 os.write((char*)&is_underground, 1);
918 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
920 // Get and compress materials
921 SharedBuffer<u8> materialdata(nodecount);
922 for(u32 i=0; i<nodecount; i++)
924 materialdata[i] = data[i].d;
926 compress(materialdata, os, version);
928 // Get and compress lights
929 SharedBuffer<u8> lightdata(nodecount);
930 for(u32 i=0; i<nodecount; i++)
932 lightdata[i] = data[i].param;
934 compress(lightdata, os, version);
938 // Get and compress pressure
939 SharedBuffer<u8> pressuredata(nodecount);
940 for(u32 i=0; i<nodecount; i++)
942 pressuredata[i] = data[i].pressure;
944 compress(pressuredata, os, version);
947 // All other versions (newest)
951 os.write((char*)&is_underground, 1);
953 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
959 SharedBuffer<u8> databuf(nodecount*3);
962 for(u32 i=0; i<nodecount; i++)
964 databuf[i] = data[i].d;
968 for(u32 i=0; i<nodecount; i++)
970 databuf[i+nodecount] = data[i].param;
974 for(u32 i=0; i<nodecount; i++)
976 databuf[i+nodecount*2] = data[i].pressure;
980 Compress data to output stream
983 compress(databuf, os, version);
987 void MapBlock::deSerialize(std::istream &is, u8 version)
989 if(!ser_ver_supported(version))
990 throw VersionMismatchException("ERROR: MapBlock format not supported");
992 // These have no compression
993 if(version <= 3 || version == 5 || version == 6)
995 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
999 throw SerializationError
1000 ("MapBlock::deSerialize: no enough input data");
1001 is_underground = tmp;
1002 for(u32 i=0; i<nodecount; i++)
1004 s32 len = MapNode::serializedLength(version);
1005 SharedBuffer<u8> d(len);
1006 is.read((char*)*d, len);
1007 if(is.gcount() != len)
1008 throw SerializationError
1009 ("MapBlock::deSerialize: no enough input data");
1010 data[i].deSerialize(*d, version);
1013 else if(version <= 10)
1015 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1018 is.read((char*)&t8, 1);
1019 is_underground = t8;
1022 // Uncompress and set material data
1023 std::ostringstream os(std::ios_base::binary);
1024 decompress(is, os, version);
1025 std::string s = os.str();
1026 if(s.size() != nodecount)
1027 throw SerializationError
1028 ("MapBlock::deSerialize: invalid format");
1029 for(u32 i=0; i<s.size(); i++)
1035 // Uncompress and set param data
1036 std::ostringstream os(std::ios_base::binary);
1037 decompress(is, os, version);
1038 std::string s = os.str();
1039 if(s.size() != nodecount)
1040 throw SerializationError
1041 ("MapBlock::deSerialize: invalid format");
1042 for(u32 i=0; i<s.size(); i++)
1044 data[i].param = s[i];
1050 // Uncompress and set pressure data
1051 std::ostringstream os(std::ios_base::binary);
1052 decompress(is, os, version);
1053 std::string s = os.str();
1054 if(s.size() != nodecount)
1055 throw SerializationError
1056 ("MapBlock::deSerialize: invalid format");
1057 for(u32 i=0; i<s.size(); i++)
1059 data[i].pressure = s[i];
1063 // All other versions (newest)
1066 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1069 is.read((char*)&t8, 1);
1070 is_underground = t8;
1073 std::ostringstream os(std::ios_base::binary);
1074 decompress(is, os, version);
1075 std::string s = os.str();
1076 if(s.size() != nodecount*3)
1077 throw SerializationError
1078 ("MapBlock::deSerialize: invalid format");
1081 for(u32 i=0; i<nodecount; i++)
1086 for(u32 i=0; i<nodecount; i++)
1088 data[i].param = s[i+nodecount];
1091 for(u32 i=0; i<nodecount; i++)
1093 data[i].pressure = s[i+nodecount*2];