]> git.lizzy.rs Git - minetest.git/blob - src/mapblock.cpp
changed node metadata format to better accomodate future needs and problems
[minetest.git] / src / mapblock.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
4
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.
9
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.
14
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.
18 */
19
20 #include "mapblock.h"
21 #include "map.h"
22 // For g_settings and g_irrlicht
23 #include "main.h"
24 #include "light.h"
25 #include <sstream>
26
27 #ifndef SERVER
28 void MeshMakeData::fill(u32 daynight_ratio, MapBlock *block)
29 {
30         m_daynight_ratio = daynight_ratio;
31         m_blockpos = block->getPos();
32
33         v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE;
34         
35         /*
36                 There is no harm not copying the TempMods of the neighbors
37                 because they are already copied to this block
38         */
39         m_temp_mods.clear();
40         block->copyTempMods(m_temp_mods);
41         
42         /*
43                 Copy data
44         */
45
46         // Allocate this block + neighbors
47         m_vmanip.clear();
48         m_vmanip.addArea(VoxelArea(blockpos_nodes-v3s16(1,1,1)*MAP_BLOCKSIZE,
49                         blockpos_nodes+v3s16(1,1,1)*MAP_BLOCKSIZE*2-v3s16(1,1,1)));
50
51         {
52                 //TimeTaker timer("copy central block data");
53                 // 0ms
54
55                 // Copy our data
56                 block->copyTo(m_vmanip);
57         }
58         {
59                 //TimeTaker timer("copy neighbor block data");
60                 // 0ms
61
62                 /*
63                         Copy neighbors. This is lightning fast.
64                         Copying only the borders would be *very* slow.
65                 */
66                 
67                 // Get map
68                 NodeContainer *parentcontainer = block->getParent();
69                 // This will only work if the parent is the map
70                 assert(parentcontainer->nodeContainerId() == NODECONTAINER_ID_MAP);
71                 // OK, we have the map!
72                 Map *map = (Map*)parentcontainer;
73
74                 for(u16 i=0; i<6; i++)
75                 {
76                         const v3s16 &dir = g_6dirs[i];
77                         v3s16 bp = m_blockpos + dir;
78                         MapBlock *b = map->getBlockNoCreateNoEx(bp);
79                         if(b)
80                                 b->copyTo(m_vmanip);
81                 }
82         }
83 }
84 #endif
85
86 /*
87         Parameters must consist of air and !air.
88         Order doesn't matter.
89
90         If either of the nodes doesn't exist, light is 0.
91         
92         parameters:
93                 daynight_ratio: 0...1000
94                 n: getNodeParent(p)
95                 n2: getNodeParent(p + face_dir)
96                 face_dir: axis oriented unit vector from p to p2
97         
98         returns encoded light value.
99 */
100 u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
101                 v3s16 face_dir)
102 {
103         try{
104                 u8 light;
105                 u8 l1 = n.getLightBlend(daynight_ratio);
106                 u8 l2 = n2.getLightBlend(daynight_ratio);
107                 if(l1 > l2)
108                         light = l1;
109                 else
110                         light = l2;
111
112                 // Make some nice difference to different sides
113
114                 // This makes light come from a corner
115                 /*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1)
116                         light = diminish_light(diminish_light(light));
117                 else if(face_dir.X == -1 || face_dir.Z == -1)
118                         light = diminish_light(light);*/
119                 
120                 // All neighboring faces have different shade (like in minecraft)
121                 if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1)
122                         light = diminish_light(diminish_light(light));
123                 else if(face_dir.Z == 1 || face_dir.Z == -1)
124                         light = diminish_light(light);
125
126                 return light;
127         }
128         catch(InvalidPositionException &e)
129         {
130                 return 0;
131         }
132 }
133
134 #ifndef SERVER
135
136 void makeFastFace(TileSpec tile, u8 light, v3f p,
137                 v3s16 dir, v3f scale, v3f posRelative_f,
138                 core::array<FastFace> &dest)
139 {
140         FastFace face;
141         
142         // Position is at the center of the cube.
143         v3f pos = p * BS;
144         posRelative_f *= BS;
145
146         v3f vertex_pos[4];
147         // If looking towards z+, this is the face that is behind
148         // the center point, facing towards z+.
149         vertex_pos[0] = v3f(-BS/2,-BS/2,BS/2);
150         vertex_pos[1] = v3f( BS/2,-BS/2,BS/2);
151         vertex_pos[2] = v3f( BS/2, BS/2,BS/2);
152         vertex_pos[3] = v3f(-BS/2, BS/2,BS/2);
153         
154         if(dir == v3s16(0,0,1))
155         {
156                 for(u16 i=0; i<4; i++)
157                         vertex_pos[i].rotateXZBy(0);
158         }
159         else if(dir == v3s16(0,0,-1))
160         {
161                 for(u16 i=0; i<4; i++)
162                         vertex_pos[i].rotateXZBy(180);
163         }
164         else if(dir == v3s16(1,0,0))
165         {
166                 for(u16 i=0; i<4; i++)
167                         vertex_pos[i].rotateXZBy(-90);
168         }
169         else if(dir == v3s16(-1,0,0))
170         {
171                 for(u16 i=0; i<4; i++)
172                         vertex_pos[i].rotateXZBy(90);
173         }
174         else if(dir == v3s16(0,1,0))
175         {
176                 for(u16 i=0; i<4; i++)
177                         vertex_pos[i].rotateYZBy(-90);
178         }
179         else if(dir == v3s16(0,-1,0))
180         {
181                 for(u16 i=0; i<4; i++)
182                         vertex_pos[i].rotateYZBy(90);
183         }
184
185         for(u16 i=0; i<4; i++)
186         {
187                 vertex_pos[i].X *= scale.X;
188                 vertex_pos[i].Y *= scale.Y;
189                 vertex_pos[i].Z *= scale.Z;
190                 vertex_pos[i] += pos + posRelative_f;
191         }
192
193         f32 abs_scale = 1.;
194         if     (scale.X < 0.999 || scale.X > 1.001) abs_scale = scale.X;
195         else if(scale.Y < 0.999 || scale.Y > 1.001) abs_scale = scale.Y;
196         else if(scale.Z < 0.999 || scale.Z > 1.001) abs_scale = scale.Z;
197
198         v3f zerovector = v3f(0,0,0);
199         
200         //u8 li = decode_light(light);
201         u8 li = light;
202         //u8 li = 255; //DEBUG
203
204         u8 alpha = tile.alpha;
205         /*u8 alpha = 255;
206         if(tile.id == TILE_WATER)
207                 alpha = WATER_ALPHA;*/
208
209         video::SColor c = video::SColor(alpha,li,li,li);
210
211         float x0 = tile.texture.pos.X;
212         float y0 = tile.texture.pos.Y;
213         float w = tile.texture.size.X;
214         float h = tile.texture.size.Y;
215
216         face.vertices[0] = video::S3DVertex(vertex_pos[0], v3f(0,1,0), c,
217                         core::vector2d<f32>(x0+w*abs_scale, y0+h));
218         face.vertices[1] = video::S3DVertex(vertex_pos[1], v3f(0,1,0), c,
219                         core::vector2d<f32>(x0, y0+h));
220         face.vertices[2] = video::S3DVertex(vertex_pos[2], v3f(0,1,0), c,
221                         core::vector2d<f32>(x0, y0));
222         face.vertices[3] = video::S3DVertex(vertex_pos[3], v3f(0,1,0), c,
223                         core::vector2d<f32>(x0+w*abs_scale, y0));
224
225         face.tile = tile;
226         //DEBUG
227         //f->tile = TILE_STONE;
228         
229         dest.push_back(face);
230         //return f;
231 }
232         
233 /*
234         Gets node tile from any place relative to block.
235         Returns TILE_NODE if doesn't exist or should not be drawn.
236 */
237 TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
238                 NodeModMap &temp_mods)
239 {
240         TileSpec spec;
241         spec = mn.getTile(face_dir);
242         
243         /*
244                 Check temporary modifications on this node
245         */
246         /*core::map<v3s16, NodeMod>::Node *n;
247         n = m_temp_mods.find(p);
248         // If modified
249         if(n != NULL)
250         {
251                 struct NodeMod mod = n->getValue();*/
252         NodeMod mod;
253         if(temp_mods.get(p, &mod))
254         {
255                 if(mod.type == NODEMOD_CHANGECONTENT)
256                 {
257                         MapNode mn2(mod.param);
258                         spec = mn2.getTile(face_dir);
259                 }
260                 if(mod.type == NODEMOD_CRACK)
261                 {
262                         /*
263                                 Get texture id, translate it to name, append stuff to
264                                 name, get texture id
265                         */
266
267                         // Get original texture name
268                         u32 orig_id = spec.texture.id;
269                         std::string orig_name = g_texturesource->getTextureName(orig_id);
270
271                         // Create new texture name
272                         std::ostringstream os;
273                         os<<orig_name<<"^[crack"<<mod.param;
274
275                         // Get new texture
276                         u32 new_id = g_texturesource->getTextureId(os.str());
277                         
278                         /*dstream<<"MapBlock::getNodeTile(): Switching from "
279                                         <<orig_name<<" to "<<os.str()<<" ("
280                                         <<orig_id<<" to "<<new_id<<")"<<std::endl;*/
281                         
282                         spec.texture = g_texturesource->getTexture(new_id);
283                 }
284         }
285         
286         return spec;
287 }
288
289 u8 getNodeContent(v3s16 p, MapNode mn, NodeModMap &temp_mods)
290 {
291         /*
292                 Check temporary modifications on this node
293         */
294         /*core::map<v3s16, NodeMod>::Node *n;
295         n = m_temp_mods.find(p);
296         // If modified
297         if(n != NULL)
298         {
299                 struct NodeMod mod = n->getValue();*/
300         NodeMod mod;
301         if(temp_mods.get(p, &mod))
302         {
303                 if(mod.type == NODEMOD_CHANGECONTENT)
304                 {
305                         // Overrides content
306                         return mod.param;
307                 }
308                 if(mod.type == NODEMOD_CRACK)
309                 {
310                         /*
311                                 Content doesn't change.
312                                 
313                                 face_contents works just like it should, because
314                                 there should not be faces between differently cracked
315                                 nodes.
316
317                                 If a semi-transparent node is cracked in front an
318                                 another one, it really doesn't matter whether there
319                                 is a cracked face drawn in between or not.
320                         */
321                 }
322         }
323
324         return mn.d;
325 }
326
327 /*
328         startpos:
329         translate_dir: unit vector with only one of x, y or z
330         face_dir: unit vector with only one of x, y or z
331 */
332 void updateFastFaceRow(
333                 u32 daynight_ratio,
334                 v3f posRelative_f,
335                 v3s16 startpos,
336                 u16 length,
337                 v3s16 translate_dir,
338                 v3f translate_dir_f,
339                 v3s16 face_dir,
340                 v3f face_dir_f,
341                 core::array<FastFace> &dest,
342                 NodeModMap &temp_mods,
343                 VoxelManipulator &vmanip,
344                 v3s16 blockpos_nodes)
345 {
346         v3s16 p = startpos;
347         
348         u16 continuous_tiles_count = 0;
349         
350         MapNode n0 = vmanip.getNodeNoEx(blockpos_nodes + p);
351         MapNode n1 = vmanip.getNodeNoEx(blockpos_nodes + p + face_dir);
352         TileSpec tile0 = getNodeTile(n0, p, face_dir, temp_mods);
353         TileSpec tile1 = getNodeTile(n1, p + face_dir, -face_dir, temp_mods);
354         u8 light = getFaceLight(daynight_ratio, n0, n1, face_dir);
355
356         for(u16 j=0; j<length; j++)
357         {
358                 bool next_is_different = true;
359                 
360                 v3s16 p_next;
361                 MapNode n0_next;
362                 MapNode n1_next;
363                 TileSpec tile0_next;
364                 TileSpec tile1_next;
365                 u8 light_next = 0;
366                 
367                 // If at last position, there is nothing to compare to and
368                 // the face must be drawn anyway
369                 if(j != length - 1)
370                 {
371                         p_next = p + translate_dir;
372                         
373                         n0_next = vmanip.getNodeNoEx(blockpos_nodes + p_next);
374                         n1_next = vmanip.getNodeNoEx(blockpos_nodes + p_next + face_dir);
375                         tile0_next = getNodeTile(n0_next, p_next, face_dir, temp_mods);
376                         tile1_next = getNodeTile(n1_next,p_next+face_dir,-face_dir, temp_mods);
377                         light_next = getFaceLight(daynight_ratio, n0_next, n1_next, face_dir);
378
379                         if(tile0_next == tile0
380                                         && tile1_next == tile1
381                                         && light_next == light)
382                         {
383                                 next_is_different = false;
384                         }
385                 }
386
387                 continuous_tiles_count++;
388                 
389                 // This is set to true if the texture doesn't allow more tiling
390                 bool end_of_texture = false;
391                 /*
392                         If there is no texture, it can be tiled infinitely.
393                         If tiled==0, it means the texture can be tiled infinitely.
394                         Otherwise check tiled agains continuous_tiles_count.
395
396                         This check has to be made for both tiles, because this is
397                         a bit hackish and we know which one we're using only when
398                         the decision to make the faces is made.
399                 */
400                 if(tile0.texture.atlas != NULL && tile0.texture.tiled != 0)
401                 {
402                         if(tile0.texture.tiled <= continuous_tiles_count)
403                                 end_of_texture = true;
404                 }
405                 if(tile1.texture.atlas != NULL && tile1.texture.tiled != 0)
406                 {
407                         if(tile1.texture.tiled <= continuous_tiles_count)
408                                 end_of_texture = true;
409                 }
410                 
411                 //end_of_texture = true; //DEBUG
412                 
413                 if(next_is_different || end_of_texture)
414                 {
415                         /*
416                                 Create a face if there should be one
417                         */
418                         //u8 mf = face_contents(tile0, tile1);
419                         // This is hackish
420                         u8 content0 = getNodeContent(p, n0, temp_mods);
421                         u8 content1 = getNodeContent(p + face_dir, n1, temp_mods);
422                         u8 mf = face_contents(content0, content1);
423                         
424                         if(mf != 0)
425                         {
426                                 // Floating point conversion of the position vector
427                                 v3f pf(p.X, p.Y, p.Z);
428                                 // Center point of face (kind of)
429                                 v3f sp = pf - ((f32)continuous_tiles_count / 2. - 0.5) * translate_dir_f;
430                                 v3f scale(1,1,1);
431                                 if(translate_dir.X != 0){
432                                         scale.X = continuous_tiles_count;
433                                 }
434                                 if(translate_dir.Y != 0){
435                                         scale.Y = continuous_tiles_count;
436                                 }
437                                 if(translate_dir.Z != 0){
438                                         scale.Z = continuous_tiles_count;
439                                 }
440                                 
441                                 //FastFace *f;
442
443                                 // If node at sp (tile0) is more solid
444                                 if(mf == 1)
445                                 {
446                                         makeFastFace(tile0, decode_light(light),
447                                                         sp, face_dir, scale,
448                                                         posRelative_f, dest);
449                                 }
450                                 // If node at sp is less solid (mf == 2)
451                                 else
452                                 {
453                                         makeFastFace(tile1, decode_light(light),
454                                                         sp+face_dir_f, -face_dir, scale,
455                                                         posRelative_f, dest);
456                                 }
457                                 //dest.push_back(f);
458                         }
459
460                         continuous_tiles_count = 0;
461                         n0 = n0_next;
462                         n1 = n1_next;
463                         tile0 = tile0_next;
464                         tile1 = tile1_next;
465                         light = light_next;
466                 }
467                 
468                 p = p_next;
469         }
470 }
471
472 /*
473         This is used because CMeshBuffer::append() is very slow
474 */
475 struct PreMeshBuffer
476 {
477         video::SMaterial material;
478         core::array<u16> indices;
479         core::array<video::S3DVertex> vertices;
480 };
481
482 class MeshCollector
483 {
484 public:
485         void append(
486                         video::SMaterial material,
487                         const video::S3DVertex* const vertices,
488                         u32 numVertices,
489                         const u16* const indices,
490                         u32 numIndices
491                 )
492         {
493                 PreMeshBuffer *p = NULL;
494                 for(u32 i=0; i<m_prebuffers.size(); i++)
495                 {
496                         PreMeshBuffer &pp = m_prebuffers[i];
497                         if(pp.material != material)
498                                 continue;
499
500                         p = &pp;
501                         break;
502                 }
503
504                 if(p == NULL)
505                 {
506                         PreMeshBuffer pp;
507                         pp.material = material;
508                         m_prebuffers.push_back(pp);
509                         p = &m_prebuffers[m_prebuffers.size()-1];
510                 }
511
512                 u32 vertex_count = p->vertices.size();
513                 for(u32 i=0; i<numIndices; i++)
514                 {
515                         u32 j = indices[i] + vertex_count;
516                         if(j > 65535)
517                         {
518                                 dstream<<"FIXME: Meshbuffer ran out of indices"<<std::endl;
519                                 // NOTE: Fix is to just add an another MeshBuffer
520                         }
521                         p->indices.push_back(j);
522                 }
523                 for(u32 i=0; i<numVertices; i++)
524                 {
525                         p->vertices.push_back(vertices[i]);
526                 }
527         }
528
529         void fillMesh(scene::SMesh *mesh)
530         {
531                 /*dstream<<"Filling mesh with "<<m_prebuffers.size()
532                                 <<" meshbuffers"<<std::endl;*/
533                 for(u32 i=0; i<m_prebuffers.size(); i++)
534                 {
535                         PreMeshBuffer &p = m_prebuffers[i];
536
537                         /*dstream<<"p.vertices.size()="<<p.vertices.size()
538                                         <<", p.indices.size()="<<p.indices.size()
539                                         <<std::endl;*/
540                         
541                         // Create meshbuffer
542                         
543                         // This is a "Standard MeshBuffer",
544                         // it's a typedeffed CMeshBuffer<video::S3DVertex>
545                         scene::SMeshBuffer *buf = new scene::SMeshBuffer();
546                         // Set material
547                         buf->Material = p.material;
548                         //((scene::SMeshBuffer*)buf)->Material = p.material;
549                         // Use VBO
550                         //buf->setHardwareMappingHint(scene::EHM_STATIC);
551                         // Add to mesh
552                         mesh->addMeshBuffer(buf);
553                         // Mesh grabbed it
554                         buf->drop();
555
556                         buf->append(p.vertices.pointer(), p.vertices.size(),
557                                         p.indices.pointer(), p.indices.size());
558                 }
559         }
560
561 private:
562         core::array<PreMeshBuffer> m_prebuffers;
563 };
564
565 scene::SMesh* makeMapBlockMesh(MeshMakeData *data)
566 {
567         // 4-21ms for MAP_BLOCKSIZE=16
568         // 24-155ms for MAP_BLOCKSIZE=32
569         //TimeTaker timer1("makeMapBlockMesh()");
570
571         core::array<FastFace> fastfaces_new;
572
573         v3s16 blockpos_nodes = data->m_blockpos*MAP_BLOCKSIZE;
574         
575         // floating point conversion
576         v3f posRelative_f(blockpos_nodes.X, blockpos_nodes.Y, blockpos_nodes.Z);
577         
578         /*
579                 Some settings
580         */
581         bool new_style_water = g_settings.getBool("new_style_water");
582         bool new_style_leaves = g_settings.getBool("new_style_leaves");
583         
584         float node_water_level = 1.0;
585         if(new_style_water)
586                 node_water_level = 0.85;
587         
588         /*
589                 We are including the faces of the trailing edges of the block.
590                 This means that when something changes, the caller must
591                 also update the meshes of the blocks at the leading edges.
592
593                 NOTE: This is the slowest part of this method.
594         */
595         
596         {
597                 // 4-23ms for MAP_BLOCKSIZE=16
598                 //TimeTaker timer2("updateMesh() collect");
599
600                 /*
601                         Go through every y,z and get top faces in rows of x+
602                 */
603                 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
604                         for(s16 z=0; z<MAP_BLOCKSIZE; z++){
605                                 updateFastFaceRow(data->m_daynight_ratio, posRelative_f,
606                                                 v3s16(0,y,z), MAP_BLOCKSIZE,
607                                                 v3s16(1,0,0), //dir
608                                                 v3f  (1,0,0),
609                                                 v3s16(0,1,0), //face dir
610                                                 v3f  (0,1,0),
611                                                 fastfaces_new,
612                                                 data->m_temp_mods,
613                                                 data->m_vmanip,
614                                                 blockpos_nodes);
615                         }
616                 }
617                 /*
618                         Go through every x,y and get right faces in rows of z+
619                 */
620                 for(s16 x=0; x<MAP_BLOCKSIZE; x++){
621                         for(s16 y=0; y<MAP_BLOCKSIZE; y++){
622                                 updateFastFaceRow(data->m_daynight_ratio, posRelative_f,
623                                                 v3s16(x,y,0), MAP_BLOCKSIZE,
624                                                 v3s16(0,0,1),
625                                                 v3f  (0,0,1),
626                                                 v3s16(1,0,0),
627                                                 v3f  (1,0,0),
628                                                 fastfaces_new,
629                                                 data->m_temp_mods,
630                                                 data->m_vmanip,
631                                                 blockpos_nodes);
632                         }
633                 }
634                 /*
635                         Go through every y,z and get back faces in rows of x+
636                 */
637                 for(s16 z=0; z<MAP_BLOCKSIZE; z++){
638                         for(s16 y=0; y<MAP_BLOCKSIZE; y++){
639                                 updateFastFaceRow(data->m_daynight_ratio, posRelative_f,
640                                                 v3s16(0,y,z), MAP_BLOCKSIZE,
641                                                 v3s16(1,0,0),
642                                                 v3f  (1,0,0),
643                                                 v3s16(0,0,1),
644                                                 v3f  (0,0,1),
645                                                 fastfaces_new,
646                                                 data->m_temp_mods,
647                                                 data->m_vmanip,
648                                                 blockpos_nodes);
649                         }
650                 }
651         }
652
653         // End of slow part
654
655         /*
656                 Convert FastFaces to SMesh
657         */
658
659         MeshCollector collector;
660
661         if(fastfaces_new.size() > 0)
662         {
663                 // avg 0ms (100ms spikes when loading textures the first time)
664                 //TimeTaker timer2("updateMesh() mesh building");
665
666                 video::SMaterial material;
667                 material.setFlag(video::EMF_LIGHTING, false);
668                 material.setFlag(video::EMF_BILINEAR_FILTER, false);
669                 material.setFlag(video::EMF_FOG_ENABLE, true);
670                 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_OFF);
671                 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_SIMPLE);
672
673                 for(u32 i=0; i<fastfaces_new.size(); i++)
674                 {
675                         FastFace &f = fastfaces_new[i];
676
677                         const u16 indices[] = {0,1,2,2,3,0};
678                         
679                         //video::ITexture *texture = g_irrlicht->getTexture(f.tile.spec);
680                         video::ITexture *texture = f.tile.texture.atlas;
681                         if(texture == NULL)
682                                 continue;
683
684                         material.setTexture(0, texture);
685                         
686                         f.tile.applyMaterialOptions(material);
687                         
688                         collector.append(material, f.vertices, 4, indices, 6);
689                 }
690         }
691
692         /*
693                 Add special graphics:
694                 - torches
695                 - flowing water
696         */
697
698         // 0ms
699         //TimeTaker timer2("updateMesh() adding special stuff");
700
701         // Flowing water material
702         video::SMaterial material_water1;
703         material_water1.setFlag(video::EMF_LIGHTING, false);
704         //material_water1.setFlag(video::EMF_BACK_FACE_CULLING, false);
705         material_water1.setFlag(video::EMF_BILINEAR_FILTER, false);
706         material_water1.setFlag(video::EMF_FOG_ENABLE, true);
707         material_water1.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
708         //TODO
709         //material_water1.setTexture(0, g_irrlicht->getTexture("water.png"));
710         AtlasPointer pa_water1 = g_texturesource->getTexture(
711                         g_texturesource->getTextureId("water.png"));
712         material_water1.setTexture(0, pa_water1.atlas);
713
714         // New-style leaves material
715         video::SMaterial material_leaves1;
716         material_leaves1.setFlag(video::EMF_LIGHTING, false);
717         //material_leaves1.setFlag(video::EMF_BACK_FACE_CULLING, false);
718         material_leaves1.setFlag(video::EMF_BILINEAR_FILTER, false);
719         material_leaves1.setFlag(video::EMF_FOG_ENABLE, true);
720         material_leaves1.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
721         //TODO
722         //material_leaves1.setTexture(0, g_irrlicht->getTexture("leaves.png"));
723         AtlasPointer pa_leaves1 = g_texturesource->getTexture(
724                         g_texturesource->getTextureId("leaves.png"));
725         material_leaves1.setTexture(0, pa_leaves1.atlas);
726
727         for(s16 z=0; z<MAP_BLOCKSIZE; z++)
728         for(s16 y=0; y<MAP_BLOCKSIZE; y++)
729         for(s16 x=0; x<MAP_BLOCKSIZE; x++)
730         {
731                 v3s16 p(x,y,z);
732
733                 MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes+p);
734                 
735                 /*
736                         Add torches to mesh
737                 */
738                 if(n.d == CONTENT_TORCH)
739                 {
740                         video::SColor c(255,255,255,255);
741
742                         // Wall at X+ of node
743                         video::S3DVertex vertices[4] =
744                         {
745                                 video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c, 0,1),
746                                 video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c, 1,1),
747                                 video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0),
748                                 video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, 0,0),
749                         };
750
751                         v3s16 dir = unpackDir(n.dir);
752
753                         for(s32 i=0; i<4; i++)
754                         {
755                                 if(dir == v3s16(1,0,0))
756                                         vertices[i].Pos.rotateXZBy(0);
757                                 if(dir == v3s16(-1,0,0))
758                                         vertices[i].Pos.rotateXZBy(180);
759                                 if(dir == v3s16(0,0,1))
760                                         vertices[i].Pos.rotateXZBy(90);
761                                 if(dir == v3s16(0,0,-1))
762                                         vertices[i].Pos.rotateXZBy(-90);
763                                 if(dir == v3s16(0,-1,0))
764                                         vertices[i].Pos.rotateXZBy(45);
765                                 if(dir == v3s16(0,1,0))
766                                         vertices[i].Pos.rotateXZBy(-45);
767
768                                 vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
769                         }
770
771                         // Set material
772                         video::SMaterial material;
773                         material.setFlag(video::EMF_LIGHTING, false);
774                         material.setFlag(video::EMF_BACK_FACE_CULLING, false);
775                         material.setFlag(video::EMF_BILINEAR_FILTER, false);
776                         //material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
777                         material.MaterialType
778                                         = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
779
780                         if(dir == v3s16(0,-1,0))
781                                 material.setTexture(0,
782                                                 g_texturesource->getTextureRaw("torch_on_floor.png"));
783                         else if(dir == v3s16(0,1,0))
784                                 material.setTexture(0,
785                                                 g_texturesource->getTextureRaw("torch_on_ceiling.png"));
786                         // For backwards compatibility
787                         else if(dir == v3s16(0,0,0))
788                                 material.setTexture(0,
789                                                 g_texturesource->getTextureRaw("torch_on_floor.png"));
790                         else
791                                 material.setTexture(0, 
792                                                 g_texturesource->getTextureRaw("torch.png"));
793
794                         u16 indices[] = {0,1,2,2,3,0};
795                         // Add to mesh collector
796                         collector.append(material, vertices, 4, indices, 6);
797                 }
798                 /*
799                         Signs on walls
800                 */
801                 if(n.d == CONTENT_SIGN_WALL)
802                 {
803                         u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
804                         video::SColor c(255,l,l,l);
805                                 
806                         float d = (float)BS/16;
807                         // Wall at X+ of node
808                         video::S3DVertex vertices[4] =
809                         {
810                                 video::S3DVertex(BS/2-d,-BS/2,-BS/2, 0,0,0, c, 0,1),
811                                 video::S3DVertex(BS/2-d,-BS/2,BS/2, 0,0,0, c, 1,1),
812                                 video::S3DVertex(BS/2-d,BS/2,BS/2, 0,0,0, c, 1,0),
813                                 video::S3DVertex(BS/2-d,BS/2,-BS/2, 0,0,0, c, 0,0),
814                         };
815
816                         v3s16 dir = unpackDir(n.dir);
817
818                         for(s32 i=0; i<4; i++)
819                         {
820                                 if(dir == v3s16(1,0,0))
821                                         vertices[i].Pos.rotateXZBy(0);
822                                 if(dir == v3s16(-1,0,0))
823                                         vertices[i].Pos.rotateXZBy(180);
824                                 if(dir == v3s16(0,0,1))
825                                         vertices[i].Pos.rotateXZBy(90);
826                                 if(dir == v3s16(0,0,-1))
827                                         vertices[i].Pos.rotateXZBy(-90);
828                                 if(dir == v3s16(0,-1,0))
829                                         vertices[i].Pos.rotateXYBy(-90);
830                                 if(dir == v3s16(0,1,0))
831                                         vertices[i].Pos.rotateXYBy(90);
832
833                                 vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
834                         }
835
836                         // Set material
837                         video::SMaterial material;
838                         material.setFlag(video::EMF_LIGHTING, false);
839                         material.setFlag(video::EMF_BACK_FACE_CULLING, false);
840                         material.setFlag(video::EMF_BILINEAR_FILTER, false);
841                         material.setFlag(video::EMF_FOG_ENABLE, true);
842                         //material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
843                         material.MaterialType
844                                         = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
845
846                         material.setTexture(0, 
847                                         g_texturesource->getTextureRaw("sign_wall.png"));
848
849                         u16 indices[] = {0,1,2,2,3,0};
850                         // Add to mesh collector
851                         collector.append(material, vertices, 4, indices, 6);
852                 }
853                 /*
854                         Add flowing water to mesh
855                 */
856                 else if(n.d == CONTENT_WATER)
857                 {
858                         bool top_is_water = false;
859                         MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
860                         if(n.d == CONTENT_WATER || n.d == CONTENT_WATERSOURCE)
861                                 top_is_water = true;
862                         
863                         u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
864                         video::SColor c(WATER_ALPHA,l,l,l);
865                         
866                         // Neighbor water levels (key = relative position)
867                         // Includes current node
868                         core::map<v3s16, f32> neighbor_levels;
869                         core::map<v3s16, u8> neighbor_contents;
870                         core::map<v3s16, u8> neighbor_flags;
871                         const u8 neighborflag_top_is_water = 0x01;
872                         v3s16 neighbor_dirs[9] = {
873                                 v3s16(0,0,0),
874                                 v3s16(0,0,1),
875                                 v3s16(0,0,-1),
876                                 v3s16(1,0,0),
877                                 v3s16(-1,0,0),
878                                 v3s16(1,0,1),
879                                 v3s16(-1,0,-1),
880                                 v3s16(1,0,-1),
881                                 v3s16(-1,0,1),
882                         };
883                         for(u32 i=0; i<9; i++)
884                         {
885                                 u8 content = CONTENT_AIR;
886                                 float level = -0.5 * BS;
887                                 u8 flags = 0;
888                                 // Check neighbor
889                                 v3s16 p2 = p + neighbor_dirs[i];
890                                 MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
891                                 if(n2.d != CONTENT_IGNORE)
892                                 {
893                                         content = n2.d;
894
895                                         if(n2.d == CONTENT_WATERSOURCE)
896                                                 level = (-0.5+node_water_level) * BS;
897                                         else if(n2.d == CONTENT_WATER)
898                                                 level = (-0.5 + ((float)n2.param2 + 0.5) / 8.0
899                                                                 * node_water_level) * BS;
900
901                                         // Check node above neighbor.
902                                         // NOTE: This doesn't get executed if neighbor
903                                         //       doesn't exist
904                                         p2.Y += 1;
905                                         n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
906                                         if(n2.d == CONTENT_WATERSOURCE || n2.d == CONTENT_WATER)
907                                                 flags |= neighborflag_top_is_water;
908                                 }
909                                 
910                                 neighbor_levels.insert(neighbor_dirs[i], level);
911                                 neighbor_contents.insert(neighbor_dirs[i], content);
912                                 neighbor_flags.insert(neighbor_dirs[i], flags);
913                         }
914
915                         //float water_level = (-0.5 + ((float)n.param2 + 0.5) / 8.0) * BS;
916                         //float water_level = neighbor_levels[v3s16(0,0,0)];
917
918                         // Corner heights (average between four waters)
919                         f32 corner_levels[4];
920                         
921                         v3s16 halfdirs[4] = {
922                                 v3s16(0,0,0),
923                                 v3s16(1,0,0),
924                                 v3s16(1,0,1),
925                                 v3s16(0,0,1),
926                         };
927                         for(u32 i=0; i<4; i++)
928                         {
929                                 v3s16 cornerdir = halfdirs[i];
930                                 float cornerlevel = 0;
931                                 u32 valid_count = 0;
932                                 for(u32 j=0; j<4; j++)
933                                 {
934                                         v3s16 neighbordir = cornerdir - halfdirs[j];
935                                         u8 content = neighbor_contents[neighbordir];
936                                         // Special case for source nodes
937                                         if(content == CONTENT_WATERSOURCE)
938                                         {
939                                                 cornerlevel = (-0.5+node_water_level)*BS;
940                                                 valid_count = 1;
941                                                 break;
942                                         }
943                                         else if(content == CONTENT_WATER)
944                                         {
945                                                 cornerlevel += neighbor_levels[neighbordir];
946                                                 valid_count++;
947                                         }
948                                         else if(content == CONTENT_AIR)
949                                         {
950                                                 cornerlevel += -0.5*BS;
951                                                 valid_count++;
952                                         }
953                                 }
954                                 if(valid_count > 0)
955                                         cornerlevel /= valid_count;
956                                 corner_levels[i] = cornerlevel;
957                         }
958
959                         /*
960                                 Generate sides
961                         */
962
963                         v3s16 side_dirs[4] = {
964                                 v3s16(1,0,0),
965                                 v3s16(-1,0,0),
966                                 v3s16(0,0,1),
967                                 v3s16(0,0,-1),
968                         };
969                         s16 side_corners[4][2] = {
970                                 {1, 2},
971                                 {3, 0},
972                                 {2, 3},
973                                 {0, 1},
974                         };
975                         for(u32 i=0; i<4; i++)
976                         {
977                                 v3s16 dir = side_dirs[i];
978
979                                 /*
980                                         If our topside is water and neighbor's topside
981                                         is water, don't draw side face
982                                 */
983                                 if(top_is_water &&
984                                                 neighbor_flags[dir] & neighborflag_top_is_water)
985                                         continue;
986
987                                 u8 neighbor_content = neighbor_contents[dir];
988                                 
989                                 // Don't draw face if neighbor is not air or water
990                                 if(neighbor_content != CONTENT_AIR
991                                                 && neighbor_content != CONTENT_WATER)
992                                         continue;
993                                 
994                                 bool neighbor_is_water = (neighbor_content == CONTENT_WATER);
995                                 
996                                 // Don't draw any faces if neighbor is water and top is water
997                                 if(neighbor_is_water == true && top_is_water == false)
998                                         continue;
999                                 
1000                                 video::S3DVertex vertices[4] =
1001                                 {
1002                                         /*video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,1),
1003                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,1),
1004                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
1005                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/
1006                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
1007                                                         pa_water1.x0(), pa_water1.y1()),
1008                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
1009                                                         pa_water1.x1(), pa_water1.y1()),
1010                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
1011                                                         pa_water1.x1(), pa_water1.y0()),
1012                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
1013                                                         pa_water1.x0(), pa_water1.y0()),
1014                                 };
1015                                 
1016                                 /*
1017                                         If our topside is water, set upper border of face
1018                                         at upper border of node
1019                                 */
1020                                 if(top_is_water)
1021                                 {
1022                                         vertices[2].Pos.Y = 0.5*BS;
1023                                         vertices[3].Pos.Y = 0.5*BS;
1024                                 }
1025                                 /*
1026                                         Otherwise upper position of face is corner levels
1027                                 */
1028                                 else
1029                                 {
1030                                         vertices[2].Pos.Y = corner_levels[side_corners[i][0]];
1031                                         vertices[3].Pos.Y = corner_levels[side_corners[i][1]];
1032                                 }
1033                                 
1034                                 /*
1035                                         If neighbor is water, lower border of face is corner
1036                                         water levels
1037                                 */
1038                                 if(neighbor_is_water)
1039                                 {
1040                                         vertices[0].Pos.Y = corner_levels[side_corners[i][1]];
1041                                         vertices[1].Pos.Y = corner_levels[side_corners[i][0]];
1042                                 }
1043                                 /*
1044                                         If neighbor is not water, lower border of face is
1045                                         lower border of node
1046                                 */
1047                                 else
1048                                 {
1049                                         vertices[0].Pos.Y = -0.5*BS;
1050                                         vertices[1].Pos.Y = -0.5*BS;
1051                                 }
1052                                 
1053                                 for(s32 j=0; j<4; j++)
1054                                 {
1055                                         if(dir == v3s16(0,0,1))
1056                                                 vertices[j].Pos.rotateXZBy(0);
1057                                         if(dir == v3s16(0,0,-1))
1058                                                 vertices[j].Pos.rotateXZBy(180);
1059                                         if(dir == v3s16(-1,0,0))
1060                                                 vertices[j].Pos.rotateXZBy(90);
1061                                         if(dir == v3s16(1,0,-0))
1062                                                 vertices[j].Pos.rotateXZBy(-90);
1063
1064                                         vertices[j].Pos += intToFloat(p + blockpos_nodes, BS);
1065                                 }
1066
1067                                 u16 indices[] = {0,1,2,2,3,0};
1068                                 // Add to mesh collector
1069                                 collector.append(material_water1, vertices, 4, indices, 6);
1070                         }
1071                         
1072                         /*
1073                                 Generate top side, if appropriate
1074                         */
1075                         
1076                         if(top_is_water == false)
1077                         {
1078                                 video::S3DVertex vertices[4] =
1079                                 {
1080                                         /*video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,1),
1081                                         video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, 1,1),
1082                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
1083                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/
1084                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
1085                                                         pa_water1.x0(), pa_water1.y1()),
1086                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
1087                                                         pa_water1.x1(), pa_water1.y1()),
1088                                         video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c,
1089                                                         pa_water1.x1(), pa_water1.y0()),
1090                                         video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c,
1091                                                         pa_water1.x0(), pa_water1.y0()),
1092                                 };
1093                                 
1094                                 // This fixes a strange bug
1095                                 s32 corner_resolve[4] = {3,2,1,0};
1096
1097                                 for(s32 i=0; i<4; i++)
1098                                 {
1099                                         //vertices[i].Pos.Y += water_level;
1100                                         //vertices[i].Pos.Y += neighbor_levels[v3s16(0,0,0)];
1101                                         s32 j = corner_resolve[i];
1102                                         vertices[i].Pos.Y += corner_levels[j];
1103                                         vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
1104                                 }
1105
1106                                 u16 indices[] = {0,1,2,2,3,0};
1107                                 // Add to mesh collector
1108                                 collector.append(material_water1, vertices, 4, indices, 6);
1109                         }
1110                 }
1111                 /*
1112                         Add water sources to mesh if using new style
1113                 */
1114                 else if(n.d == CONTENT_WATERSOURCE && new_style_water)
1115                 {
1116                         //bool top_is_water = false;
1117                         bool top_is_air = false;
1118                         MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
1119                         /*if(n.d == CONTENT_WATER || n.d == CONTENT_WATERSOURCE)
1120                                 top_is_water = true;*/
1121                         if(n.d == CONTENT_AIR)
1122                                 top_is_air = true;
1123                         
1124                         /*if(top_is_water == true)
1125                                 continue;*/
1126                         if(top_is_air == false)
1127                                 continue;
1128
1129                         u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
1130                         video::SColor c(WATER_ALPHA,l,l,l);
1131                         
1132                         video::S3DVertex vertices[4] =
1133                         {
1134                                 /*video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,1),
1135                                 video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, 1,1),
1136                                 video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
1137                                 video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/
1138                                 video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
1139                                                 pa_water1.x0(), pa_water1.y1()),
1140                                 video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
1141                                                 pa_water1.x1(), pa_water1.y1()),
1142                                 video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c,
1143                                                 pa_water1.x1(), pa_water1.y0()),
1144                                 video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c,
1145                                                 pa_water1.x0(), pa_water1.y0()),
1146                         };
1147
1148                         for(s32 i=0; i<4; i++)
1149                         {
1150                                 vertices[i].Pos.Y += (-0.5+node_water_level)*BS;
1151                                 vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
1152                         }
1153
1154                         u16 indices[] = {0,1,2,2,3,0};
1155                         // Add to mesh collector
1156                         collector.append(material_water1, vertices, 4, indices, 6);
1157                 }
1158                 /*
1159                         Add leaves if using new style
1160                 */
1161                 else if(n.d == CONTENT_LEAVES && new_style_leaves)
1162                 {
1163                         /*u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));*/
1164                         u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio)));
1165                         video::SColor c(255,l,l,l);
1166
1167                         for(u32 j=0; j<6; j++)
1168                         {
1169                                 video::S3DVertex vertices[4] =
1170                                 {
1171                                         /*video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, 0,1),
1172                                         video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, 1,1),
1173                                         video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, 1,0),
1174                                         video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c, 0,0),*/
1175                                         video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c,
1176                                                 pa_leaves1.x0(), pa_leaves1.y1()),
1177                                         video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c,
1178                                                 pa_leaves1.x1(), pa_leaves1.y1()),
1179                                         video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c,
1180                                                 pa_leaves1.x1(), pa_leaves1.y0()),
1181                                         video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c,
1182                                                 pa_leaves1.x0(), pa_leaves1.y0()),
1183                                 };
1184
1185                                 if(j == 0)
1186                                 {
1187                                         for(u16 i=0; i<4; i++)
1188                                                 vertices[i].Pos.rotateXZBy(0);
1189                                 }
1190                                 else if(j == 1)
1191                                 {
1192                                         for(u16 i=0; i<4; i++)
1193                                                 vertices[i].Pos.rotateXZBy(180);
1194                                 }
1195                                 else if(j == 2)
1196                                 {
1197                                         for(u16 i=0; i<4; i++)
1198                                                 vertices[i].Pos.rotateXZBy(-90);
1199                                 }
1200                                 else if(j == 3)
1201                                 {
1202                                         for(u16 i=0; i<4; i++)
1203                                                 vertices[i].Pos.rotateXZBy(90);
1204                                 }
1205                                 else if(j == 4)
1206                                 {
1207                                         for(u16 i=0; i<4; i++)
1208                                                 vertices[i].Pos.rotateYZBy(-90);
1209                                 }
1210                                 else if(j == 5)
1211                                 {
1212                                         for(u16 i=0; i<4; i++)
1213                                                 vertices[i].Pos.rotateYZBy(90);
1214                                 }
1215
1216                                 for(u16 i=0; i<4; i++)
1217                                 {
1218                                         vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
1219                                 }
1220
1221                                 u16 indices[] = {0,1,2,2,3,0};
1222                                 // Add to mesh collector
1223                                 collector.append(material_leaves1, vertices, 4, indices, 6);
1224                         }
1225                 }
1226         }
1227
1228         /*
1229                 Add stuff from collector to mesh
1230         */
1231         
1232         scene::SMesh *mesh_new = NULL;
1233         mesh_new = new scene::SMesh();
1234         
1235         collector.fillMesh(mesh_new);
1236
1237         /*
1238                 Do some stuff to the mesh
1239         */
1240
1241         mesh_new->recalculateBoundingBox();
1242
1243         /*
1244                 Delete new mesh if it is empty
1245         */
1246
1247         if(mesh_new->getMeshBufferCount() == 0)
1248         {
1249                 mesh_new->drop();
1250                 mesh_new = NULL;
1251         }
1252
1253         if(mesh_new)
1254         {
1255 #if 0
1256                 // Usually 1-700 faces and 1-7 materials
1257                 std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
1258                                 <<"and uses "<<mesh_new->getMeshBufferCount()
1259                                 <<" materials (meshbuffers)"<<std::endl;
1260 #endif
1261
1262                 // Use VBO for mesh (this just would set this for ever buffer)
1263                 // This will lead to infinite memory usage because or irrlicht.
1264                 //mesh_new->setHardwareMappingHint(scene::EHM_STATIC);
1265
1266                 /*
1267                         NOTE: If that is enabled, some kind of a queue to the main
1268                         thread should be made which would call irrlicht to delete
1269                         the hardware buffer and then delete the mesh
1270                 */
1271         }
1272
1273         return mesh_new;
1274         
1275         //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
1276 }
1277
1278 #endif // !SERVER
1279
1280 /*
1281         MapBlock
1282 */
1283
1284 MapBlock::MapBlock(NodeContainer *parent, v3s16 pos, bool dummy):
1285                 m_parent(parent),
1286                 m_pos(pos),
1287                 changed(true),
1288                 is_underground(false),
1289                 m_lighting_expired(true),
1290                 m_day_night_differs(false),
1291                 //m_not_fully_generated(false),
1292                 m_objects(this)
1293 {
1294         data = NULL;
1295         if(dummy == false)
1296                 reallocate();
1297         
1298         m_spawn_timer = -10000;
1299
1300 #ifndef SERVER
1301         m_mesh_expired = false;
1302         mesh_mutex.Init();
1303         mesh = NULL;
1304         m_temp_mods_mutex.Init();
1305 #endif
1306 }
1307
1308 MapBlock::~MapBlock()
1309 {
1310 #ifndef SERVER
1311         {
1312                 JMutexAutoLock lock(mesh_mutex);
1313                 
1314                 if(mesh)
1315                 {
1316                         mesh->drop();
1317                         mesh = NULL;
1318                 }
1319         }
1320 #endif
1321
1322         if(data)
1323                 delete[] data;
1324 }
1325
1326 bool MapBlock::isValidPositionParent(v3s16 p)
1327 {
1328         if(isValidPosition(p))
1329         {
1330                 return true;
1331         }
1332         else{
1333                 return m_parent->isValidPosition(getPosRelative() + p);
1334         }
1335 }
1336
1337 MapNode MapBlock::getNodeParent(v3s16 p)
1338 {
1339         if(isValidPosition(p) == false)
1340         {
1341                 return m_parent->getNode(getPosRelative() + p);
1342         }
1343         else
1344         {
1345                 if(data == NULL)
1346                         throw InvalidPositionException();
1347                 return data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X];
1348         }
1349 }
1350
1351 void MapBlock::setNodeParent(v3s16 p, MapNode & n)
1352 {
1353         if(isValidPosition(p) == false)
1354         {
1355                 m_parent->setNode(getPosRelative() + p, n);
1356         }
1357         else
1358         {
1359                 if(data == NULL)
1360                         throw InvalidPositionException();
1361                 data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X] = n;
1362         }
1363 }
1364
1365 MapNode MapBlock::getNodeParentNoEx(v3s16 p)
1366 {
1367         if(isValidPosition(p) == false)
1368         {
1369                 try{
1370                         return m_parent->getNode(getPosRelative() + p);
1371                 }
1372                 catch(InvalidPositionException &e)
1373                 {
1374                         return MapNode(CONTENT_IGNORE);
1375                 }
1376         }
1377         else
1378         {
1379                 if(data == NULL)
1380                 {
1381                         return MapNode(CONTENT_IGNORE);
1382                 }
1383                 return data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X];
1384         }
1385 }
1386
1387 #ifndef SERVER
1388
1389 #if 1
1390 void MapBlock::updateMesh(u32 daynight_ratio)
1391 {
1392 #if 0
1393         /*
1394                 DEBUG: If mesh has been generated, don't generate it again
1395         */
1396         {
1397                 JMutexAutoLock meshlock(mesh_mutex);
1398                 if(mesh != NULL)
1399                         return;
1400         }
1401 #endif
1402
1403         MeshMakeData data;
1404         data.fill(daynight_ratio, this);
1405         
1406         scene::SMesh *mesh_new = makeMapBlockMesh(&data);
1407         
1408         /*
1409                 Replace the mesh
1410         */
1411
1412         replaceMesh(mesh_new);
1413
1414 }
1415 #endif
1416
1417 void MapBlock::replaceMesh(scene::SMesh *mesh_new)
1418 {
1419         mesh_mutex.Lock();
1420
1421         //scene::SMesh *mesh_old = mesh[daynight_i];
1422         //mesh[daynight_i] = mesh_new;
1423
1424         scene::SMesh *mesh_old = mesh;
1425         mesh = mesh_new;
1426         setMeshExpired(false);
1427         
1428         if(mesh_old != NULL)
1429         {
1430                 // Remove hardware buffers of meshbuffers of mesh
1431                 // NOTE: No way, this runs in a different thread and everything
1432                 /*u32 c = mesh_old->getMeshBufferCount();
1433                 for(u32 i=0; i<c; i++)
1434                 {
1435                         IMeshBuffer *buf = mesh_old->getMeshBuffer(i);
1436                 }*/
1437                 
1438                 /*dstream<<"mesh_old->getReferenceCount()="
1439                                 <<mesh_old->getReferenceCount()<<std::endl;
1440                 u32 c = mesh_old->getMeshBufferCount();
1441                 for(u32 i=0; i<c; i++)
1442                 {
1443                         scene::IMeshBuffer *buf = mesh_old->getMeshBuffer(i);
1444                         dstream<<"buf->getReferenceCount()="
1445                                         <<buf->getReferenceCount()<<std::endl;
1446                 }*/
1447
1448                 // Drop the mesh
1449                 mesh_old->drop();
1450
1451                 //delete mesh_old;
1452         }
1453
1454         mesh_mutex.Unlock();
1455 }
1456         
1457 #endif // !SERVER
1458
1459 /*
1460         Propagates sunlight down through the block.
1461         Doesn't modify nodes that are not affected by sunlight.
1462         
1463         Returns false if sunlight at bottom block is invalid
1464         Returns true if bottom block doesn't exist.
1465
1466         If there is a block above, continues from it.
1467         If there is no block above, assumes there is sunlight, unless
1468         is_underground is set or highest node is water.
1469
1470         At the moment, all sunlighted nodes are added to light_sources.
1471         - SUGG: This could be optimized
1472
1473         Turns sunglighted mud into grass.
1474
1475         if remove_light==true, sets non-sunlighted nodes black.
1476
1477         if black_air_left!=NULL, it is set to true if non-sunlighted
1478         air is left in block.
1479 */
1480 bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources,
1481                 bool remove_light, bool *black_air_left,
1482                 bool grow_grass)
1483 {
1484         // Whether the sunlight at the top of the bottom block is valid
1485         bool block_below_is_valid = true;
1486         
1487         v3s16 pos_relative = getPosRelative();
1488         
1489         for(s16 x=0; x<MAP_BLOCKSIZE; x++)
1490         {
1491                 for(s16 z=0; z<MAP_BLOCKSIZE; z++)
1492                 {
1493 #if 1
1494                         bool no_sunlight = false;
1495                         bool no_top_block = false;
1496                         // Check if node above block has sunlight
1497                         try{
1498                                 MapNode n = getNodeParent(v3s16(x, MAP_BLOCKSIZE, z));
1499                                 if(n.getLight(LIGHTBANK_DAY) != LIGHT_SUN)
1500                                 {
1501                                         no_sunlight = true;
1502                                 }
1503                         }
1504                         catch(InvalidPositionException &e)
1505                         {
1506                                 no_top_block = true;
1507                                 
1508                                 // NOTE: This makes over-ground roofed places sunlighted
1509                                 // Assume sunlight, unless is_underground==true
1510                                 if(is_underground)
1511                                 {
1512                                         no_sunlight = true;
1513                                 }
1514                                 else
1515                                 {
1516                                         MapNode n = getNode(v3s16(x, MAP_BLOCKSIZE-1, z));
1517                                         if(n.d == CONTENT_WATER || n.d == CONTENT_WATERSOURCE)
1518                                         {
1519                                                 no_sunlight = true;
1520                                         }
1521                                 }
1522                                 // NOTE: As of now, this just would make everything dark.
1523                                 // No sunlight here
1524                                 //no_sunlight = true;
1525                         }
1526 #endif
1527 #if 0 // Doesn't work; nothing gets light.
1528                         bool no_sunlight = true;
1529                         bool no_top_block = false;
1530                         // Check if node above block has sunlight
1531                         try{
1532                                 MapNode n = getNodeParent(v3s16(x, MAP_BLOCKSIZE, z));
1533                                 if(n.getLight(LIGHTBANK_DAY) == LIGHT_SUN)
1534                                 {
1535                                         no_sunlight = false;
1536                                 }
1537                         }
1538                         catch(InvalidPositionException &e)
1539                         {
1540                                 no_top_block = true;
1541                         }
1542 #endif
1543
1544                         /*std::cout<<"("<<x<<","<<z<<"): "
1545                                         <<"no_top_block="<<no_top_block
1546                                         <<", is_underground="<<is_underground
1547                                         <<", no_sunlight="<<no_sunlight
1548                                         <<std::endl;*/
1549                 
1550                         s16 y = MAP_BLOCKSIZE-1;
1551                         
1552                         // This makes difference to diminishing in water.
1553                         bool stopped_to_solid_object = false;
1554                         
1555                         u8 current_light = no_sunlight ? 0 : LIGHT_SUN;
1556
1557                         for(; y >= 0; y--)
1558                         {
1559                                 v3s16 pos(x, y, z);
1560                                 MapNode &n = getNodeRef(pos);
1561                                 
1562                                 if(current_light == 0)
1563                                 {
1564                                         // Do nothing
1565                                 }
1566                                 else if(current_light == LIGHT_SUN && n.sunlight_propagates())
1567                                 {
1568                                         // Do nothing: Sunlight is continued
1569                                 }
1570                                 else if(n.light_propagates() == false)
1571                                 {
1572                                         if(grow_grass)
1573                                         {
1574                                                 bool upper_is_air = false;
1575                                                 try
1576                                                 {
1577                                                         if(getNodeParent(pos+v3s16(0,1,0)).d == CONTENT_AIR)
1578                                                                 upper_is_air = true;
1579                                                 }
1580                                                 catch(InvalidPositionException &e)
1581                                                 {
1582                                                 }
1583                                                 // Turn mud into grass
1584                                                 if(upper_is_air && n.d == CONTENT_MUD
1585                                                                 && current_light == LIGHT_SUN)
1586                                                 {
1587                                                         n.d = CONTENT_GRASS;
1588                                                 }
1589                                         }
1590
1591                                         // A solid object is on the way.
1592                                         stopped_to_solid_object = true;
1593                                         
1594                                         // Light stops.
1595                                         current_light = 0;
1596                                 }
1597                                 else
1598                                 {
1599                                         // Diminish light
1600                                         current_light = diminish_light(current_light);
1601                                 }
1602
1603                                 u8 old_light = n.getLight(LIGHTBANK_DAY);
1604
1605                                 if(current_light > old_light || remove_light)
1606                                 {
1607                                         n.setLight(LIGHTBANK_DAY, current_light);
1608                                 }
1609                                 
1610                                 if(diminish_light(current_light) != 0)
1611                                 {
1612                                         light_sources.insert(pos_relative + pos, true);
1613                                 }
1614
1615                                 if(current_light == 0 && stopped_to_solid_object)
1616                                 {
1617                                         if(black_air_left)
1618                                         {
1619                                                 *black_air_left = true;
1620                                         }
1621                                 }
1622                         }
1623
1624                         // Whether or not the block below should see LIGHT_SUN
1625                         bool sunlight_should_go_down = (current_light == LIGHT_SUN);
1626
1627                         /*
1628                                 If the block below hasn't already been marked invalid:
1629
1630                                 Check if the node below the block has proper sunlight at top.
1631                                 If not, the block below is invalid.
1632                                 
1633                                 Ignore non-transparent nodes as they always have no light
1634                         */
1635                         try
1636                         {
1637                         if(block_below_is_valid)
1638                         {
1639                                 MapNode n = getNodeParent(v3s16(x, -1, z));
1640                                 if(n.light_propagates())
1641                                 {
1642                                         if(n.getLight(LIGHTBANK_DAY) == LIGHT_SUN
1643                                                         && sunlight_should_go_down == false)
1644                                                 block_below_is_valid = false;
1645                                         else if(n.getLight(LIGHTBANK_DAY) != LIGHT_SUN
1646                                                         && sunlight_should_go_down == true)
1647                                                 block_below_is_valid = false;
1648                                 }
1649                         }//if
1650                         }//try
1651                         catch(InvalidPositionException &e)
1652                         {
1653                                 /*std::cout<<"InvalidBlockException for bottom block node"
1654                                                 <<std::endl;*/
1655                                 // Just no block below, no need to panic.
1656                         }
1657                 }
1658         }
1659
1660         return block_below_is_valid;
1661 }
1662
1663
1664 void MapBlock::copyTo(VoxelManipulator &dst)
1665 {
1666         v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE);
1667         VoxelArea data_area(v3s16(0,0,0), data_size - v3s16(1,1,1));
1668         
1669         // Copy from data to VoxelManipulator
1670         dst.copyFrom(data, data_area, v3s16(0,0,0),
1671                         getPosRelative(), data_size);
1672 }
1673
1674 void MapBlock::copyFrom(VoxelManipulator &dst)
1675 {
1676         v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE);
1677         VoxelArea data_area(v3s16(0,0,0), data_size - v3s16(1,1,1));
1678         
1679         // Copy from VoxelManipulator to data
1680         dst.copyTo(data, data_area, v3s16(0,0,0),
1681                         getPosRelative(), data_size);
1682 }
1683
1684 void MapBlock::stepObjects(float dtime, bool server, u32 daynight_ratio)
1685 {
1686         /*
1687                 Step objects
1688         */
1689         m_objects.step(dtime, server, daynight_ratio);
1690         
1691         /*
1692                 Spawn some objects at random.
1693
1694                 Use dayNightDiffed() to approximate being near ground level
1695         */
1696         if(m_spawn_timer < -999)
1697         {
1698                 m_spawn_timer = 60;
1699         }
1700         if(dayNightDiffed() == true && getObjectCount() == 0)
1701         {
1702                 m_spawn_timer -= dtime;
1703                 if(m_spawn_timer <= 0.0)
1704                 {
1705                         m_spawn_timer += myrand() % 300;
1706                         
1707                         v2s16 p2d(
1708                                 (myrand()%(MAP_BLOCKSIZE-1))+0,
1709                                 (myrand()%(MAP_BLOCKSIZE-1))+0
1710                         );
1711
1712                         s16 y = getGroundLevel(p2d);
1713                         
1714                         if(y >= 0)
1715                         {
1716                                 v3s16 p(p2d.X, y+1, p2d.Y);
1717
1718                                 if(getNode(p).d == CONTENT_AIR
1719                                                 && getNode(p).getLightBlend(daynight_ratio) <= 11)
1720                                 {
1721                                         RatObject *obj = new RatObject(NULL, -1, intToFloat(p, BS));
1722                                         addObject(obj);
1723                                 }
1724                         }
1725                 }
1726         }
1727
1728         setChangedFlag();
1729 }
1730
1731
1732 void MapBlock::updateDayNightDiff()
1733 {
1734         if(data == NULL)
1735         {
1736                 m_day_night_differs = false;
1737                 return;
1738         }
1739
1740         bool differs = false;
1741
1742         /*
1743                 Check if any lighting value differs
1744         */
1745         for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++)
1746         {
1747                 MapNode &n = data[i];
1748                 if(n.getLight(LIGHTBANK_DAY) != n.getLight(LIGHTBANK_NIGHT))
1749                 {
1750                         differs = true;
1751                         break;
1752                 }
1753         }
1754
1755         /*
1756                 If some lighting values differ, check if the whole thing is
1757                 just air. If it is, differ = false
1758         */
1759         if(differs)
1760         {
1761                 bool only_air = true;
1762                 for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++)
1763                 {
1764                         MapNode &n = data[i];
1765                         if(n.d != CONTENT_AIR)
1766                         {
1767                                 only_air = false;
1768                                 break;
1769                         }
1770                 }
1771                 if(only_air)
1772                         differs = false;
1773         }
1774
1775         // Set member variable
1776         m_day_night_differs = differs;
1777 }
1778
1779 s16 MapBlock::getGroundLevel(v2s16 p2d)
1780 {
1781         if(isDummy())
1782                 return -3;
1783         try
1784         {
1785                 s16 y = MAP_BLOCKSIZE-1;
1786                 for(; y>=0; y--)
1787                 {
1788                         //if(is_ground_content(getNodeRef(p2d.X, y, p2d.Y).d))
1789                         if(content_features(getNodeRef(p2d.X, y, p2d.Y).d).walkable)
1790                         {
1791                                 if(y == MAP_BLOCKSIZE-1)
1792                                         return -2;
1793                                 else
1794                                         return y;
1795                         }
1796                 }
1797                 return -1;
1798         }
1799         catch(InvalidPositionException &e)
1800         {
1801                 return -3;
1802         }
1803 }
1804
1805 /*
1806         Serialization
1807 */
1808
1809 void MapBlock::serialize(std::ostream &os, u8 version)
1810 {
1811         if(!ser_ver_supported(version))
1812                 throw VersionMismatchException("ERROR: MapBlock format not supported");
1813         
1814         if(data == NULL)
1815         {
1816                 throw SerializationError("ERROR: Not writing dummy block.");
1817         }
1818         
1819         // These have no compression
1820         if(version <= 3 || version == 5 || version == 6)
1821         {
1822                 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1823                 
1824                 u32 buflen = 1 + nodecount * MapNode::serializedLength(version);
1825                 SharedBuffer<u8> dest(buflen);
1826
1827                 dest[0] = is_underground;
1828                 for(u32 i=0; i<nodecount; i++)
1829                 {
1830                         u32 s = 1 + i * MapNode::serializedLength(version);
1831                         data[i].serialize(&dest[s], version);
1832                 }
1833                 
1834                 os.write((char*)*dest, dest.getSize());
1835         }
1836         else if(version <= 10)
1837         {
1838                 /*
1839                         With compression.
1840                         Compress the materials and the params separately.
1841                 */
1842                 
1843                 // First byte
1844                 os.write((char*)&is_underground, 1);
1845
1846                 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1847
1848                 // Get and compress materials
1849                 SharedBuffer<u8> materialdata(nodecount);
1850                 for(u32 i=0; i<nodecount; i++)
1851                 {
1852                         materialdata[i] = data[i].d;
1853                 }
1854                 compress(materialdata, os, version);
1855
1856                 // Get and compress lights
1857                 SharedBuffer<u8> lightdata(nodecount);
1858                 for(u32 i=0; i<nodecount; i++)
1859                 {
1860                         lightdata[i] = data[i].param;
1861                 }
1862                 compress(lightdata, os, version);
1863                 
1864                 if(version >= 10)
1865                 {
1866                         // Get and compress param2
1867                         SharedBuffer<u8> param2data(nodecount);
1868                         for(u32 i=0; i<nodecount; i++)
1869                         {
1870                                 param2data[i] = data[i].param2;
1871                         }
1872                         compress(param2data, os, version);
1873                 }
1874         }
1875         // All other versions (newest)
1876         else
1877         {
1878                 // First byte
1879                 u8 flags = 0;
1880                 if(is_underground)
1881                         flags |= 0x01;
1882                 if(m_day_night_differs)
1883                         flags |= 0x02;
1884                 if(m_lighting_expired)
1885                         flags |= 0x04;
1886                 os.write((char*)&flags, 1);
1887
1888                 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1889
1890                 /*
1891                         Get data
1892                 */
1893
1894                 SharedBuffer<u8> databuf(nodecount*3);
1895
1896                 // Get contents
1897                 for(u32 i=0; i<nodecount; i++)
1898                 {
1899                         databuf[i] = data[i].d;
1900                 }
1901
1902                 // Get params
1903                 for(u32 i=0; i<nodecount; i++)
1904                 {
1905                         databuf[i+nodecount] = data[i].param;
1906                 }
1907
1908                 // Get param2
1909                 for(u32 i=0; i<nodecount; i++)
1910                 {
1911                         databuf[i+nodecount*2] = data[i].param2;
1912                 }
1913
1914                 /*
1915                         Compress data to output stream
1916                 */
1917
1918                 compress(databuf, os, version);
1919                 
1920                 /*
1921                         NodeMetadata
1922                 */
1923                 if(version >= 14)
1924                 {
1925                         std::ostringstream oss(std::ios_base::binary);
1926                         m_node_metadata.serialize(oss);
1927                         os<<serializeString(oss.str());
1928                 }
1929         }
1930 }
1931
1932 void MapBlock::deSerialize(std::istream &is, u8 version)
1933 {
1934         if(!ser_ver_supported(version))
1935                 throw VersionMismatchException("ERROR: MapBlock format not supported");
1936
1937         // These have no compression
1938         if(version <= 3 || version == 5 || version == 6)
1939         {
1940                 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1941                 char tmp;
1942                 is.read(&tmp, 1);
1943                 if(is.gcount() != 1)
1944                         throw SerializationError
1945                                         ("MapBlock::deSerialize: no enough input data");
1946                 is_underground = tmp;
1947                 for(u32 i=0; i<nodecount; i++)
1948                 {
1949                         s32 len = MapNode::serializedLength(version);
1950                         SharedBuffer<u8> d(len);
1951                         is.read((char*)*d, len);
1952                         if(is.gcount() != len)
1953                                 throw SerializationError
1954                                                 ("MapBlock::deSerialize: no enough input data");
1955                         data[i].deSerialize(*d, version);
1956                 }
1957         }
1958         else if(version <= 10)
1959         {
1960                 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1961
1962                 u8 t8;
1963                 is.read((char*)&t8, 1);
1964                 is_underground = t8;
1965
1966                 {
1967                         // Uncompress and set material data
1968                         std::ostringstream os(std::ios_base::binary);
1969                         decompress(is, os, version);
1970                         std::string s = os.str();
1971                         if(s.size() != nodecount)
1972                                 throw SerializationError
1973                                                 ("MapBlock::deSerialize: invalid format");
1974                         for(u32 i=0; i<s.size(); i++)
1975                         {
1976                                 data[i].d = s[i];
1977                         }
1978                 }
1979                 {
1980                         // Uncompress and set param data
1981                         std::ostringstream os(std::ios_base::binary);
1982                         decompress(is, os, version);
1983                         std::string s = os.str();
1984                         if(s.size() != nodecount)
1985                                 throw SerializationError
1986                                                 ("MapBlock::deSerialize: invalid format");
1987                         for(u32 i=0; i<s.size(); i++)
1988                         {
1989                                 data[i].param = s[i];
1990                         }
1991                 }
1992         
1993                 if(version >= 10)
1994                 {
1995                         // Uncompress and set param2 data
1996                         std::ostringstream os(std::ios_base::binary);
1997                         decompress(is, os, version);
1998                         std::string s = os.str();
1999                         if(s.size() != nodecount)
2000                                 throw SerializationError
2001                                                 ("MapBlock::deSerialize: invalid format");
2002                         for(u32 i=0; i<s.size(); i++)
2003                         {
2004                                 data[i].param2 = s[i];
2005                         }
2006                 }
2007         }
2008         // All other versions (newest)
2009         else
2010         {
2011                 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
2012
2013                 u8 flags;
2014                 is.read((char*)&flags, 1);
2015                 is_underground = (flags & 0x01) ? true : false;
2016                 m_day_night_differs = (flags & 0x02) ? true : false;
2017                 m_lighting_expired = (flags & 0x04) ? true : false;
2018
2019                 // Uncompress data
2020                 std::ostringstream os(std::ios_base::binary);
2021                 decompress(is, os, version);
2022                 std::string s = os.str();
2023                 if(s.size() != nodecount*3)
2024                         throw SerializationError
2025                                         ("MapBlock::deSerialize: invalid format");
2026
2027                 // Set contents
2028                 for(u32 i=0; i<nodecount; i++)
2029                 {
2030                         data[i].d = s[i];
2031                 }
2032                 // Set params
2033                 for(u32 i=0; i<nodecount; i++)
2034                 {
2035                         data[i].param = s[i+nodecount];
2036                 }
2037                 // Set param2
2038                 for(u32 i=0; i<nodecount; i++)
2039                 {
2040                         data[i].param2 = s[i+nodecount*2];
2041                 }
2042                 
2043                 /*
2044                         NodeMetadata
2045                 */
2046                 if(version >= 14)
2047                 {
2048                         // Ignore errors
2049                         try{
2050                                 std::string data = deSerializeString(is);
2051                                 std::istringstream iss(data, std::ios_base::binary);
2052                                 m_node_metadata.deSerialize(iss);
2053                         }
2054                         catch(SerializationError &e)
2055                         {
2056                                 dstream<<"WARNING: MapBlock::deSerialize(): Ignoring an error"
2057                                                 <<" while deserializing node metadata"<<std::endl;
2058                         }
2059                 }
2060         }
2061         
2062         /*
2063                 Translate nodes as specified in the translate_to fields of
2064                 node features
2065         */
2066         for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++)
2067         {
2068                 MapNode &n = data[i];
2069
2070                 MapNode *translate_to = content_features(n.d).translate_to;
2071                 if(translate_to)
2072                 {
2073                         dstream<<"MapBlock: WARNING: Translating node "<<n.d<<" to "
2074                                         <<translate_to->d<<std::endl;
2075                         n = *translate_to;
2076                 }
2077         }
2078 }
2079
2080
2081 //END