3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
31 MapBlock::MapBlock(Map *parent, v3s16 pos, bool dummy):
34 m_modified(MOD_STATE_WRITE_NEEDED),
35 is_underground(false),
36 m_lighting_expired(true),
37 m_day_night_differs(false),
40 m_timestamp(BLOCK_TIMESTAMP_UNDEFINED),
47 //m_spawn_timer = -10000;
50 m_mesh_expired = false;
53 m_temp_mods_mutex.Init();
61 JMutexAutoLock lock(mesh_mutex);
75 bool MapBlock::isValidPositionParent(v3s16 p)
77 if(isValidPosition(p))
82 return m_parent->isValidPosition(getPosRelative() + p);
86 MapNode MapBlock::getNodeParent(v3s16 p)
88 if(isValidPosition(p) == false)
90 return m_parent->getNode(getPosRelative() + p);
95 throw InvalidPositionException();
96 return data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X];
100 void MapBlock::setNodeParent(v3s16 p, MapNode & n)
102 if(isValidPosition(p) == false)
104 m_parent->setNode(getPosRelative() + p, n);
109 throw InvalidPositionException();
110 data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X] = n;
114 MapNode MapBlock::getNodeParentNoEx(v3s16 p)
116 if(isValidPosition(p) == false)
119 return m_parent->getNode(getPosRelative() + p);
121 catch(InvalidPositionException &e)
123 return MapNode(CONTENT_IGNORE);
130 return MapNode(CONTENT_IGNORE);
132 return data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X];
139 void MapBlock::updateMesh(u32 daynight_ratio)
143 DEBUG: If mesh has been generated, don't generate it again
146 JMutexAutoLock meshlock(mesh_mutex);
153 data.fill(daynight_ratio, this);
155 scene::SMesh *mesh_new = makeMapBlockMesh(&data);
161 replaceMesh(mesh_new);
166 void MapBlock::replaceMesh(scene::SMesh *mesh_new)
170 //scene::SMesh *mesh_old = mesh[daynight_i];
171 //mesh[daynight_i] = mesh_new;
173 scene::SMesh *mesh_old = mesh;
175 setMeshExpired(false);
179 // Remove hardware buffers of meshbuffers of mesh
180 // NOTE: No way, this runs in a different thread and everything
181 /*u32 c = mesh_old->getMeshBufferCount();
182 for(u32 i=0; i<c; i++)
184 IMeshBuffer *buf = mesh_old->getMeshBuffer(i);
187 /*dstream<<"mesh_old->getReferenceCount()="
188 <<mesh_old->getReferenceCount()<<std::endl;
189 u32 c = mesh_old->getMeshBufferCount();
190 for(u32 i=0; i<c; i++)
192 scene::IMeshBuffer *buf = mesh_old->getMeshBuffer(i);
193 dstream<<"buf->getReferenceCount()="
194 <<buf->getReferenceCount()<<std::endl;
209 Propagates sunlight down through the block.
210 Doesn't modify nodes that are not affected by sunlight.
212 Returns false if sunlight at bottom block is invalid.
213 Returns true if sunlight at bottom block is valid.
214 Returns true if bottom block doesn't exist.
216 If there is a block above, continues from it.
217 If there is no block above, assumes there is sunlight, unless
218 is_underground is set or highest node is water.
220 All sunlighted nodes are added to light_sources.
222 if remove_light==true, sets non-sunlighted nodes black.
224 if black_air_left!=NULL, it is set to true if non-sunlighted
225 air is left in block.
227 bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources,
228 bool remove_light, bool *black_air_left)
230 // Whether the sunlight at the top of the bottom block is valid
231 bool block_below_is_valid = true;
233 v3s16 pos_relative = getPosRelative();
235 for(s16 x=0; x<MAP_BLOCKSIZE; x++)
237 for(s16 z=0; z<MAP_BLOCKSIZE; z++)
240 bool no_sunlight = false;
241 bool no_top_block = false;
242 // Check if node above block has sunlight
244 MapNode n = getNodeParent(v3s16(x, MAP_BLOCKSIZE, z));
245 if(n.getContent() == CONTENT_IGNORE)
248 no_sunlight = is_underground;
250 else if(n.getLight(LIGHTBANK_DAY) != LIGHT_SUN)
255 catch(InvalidPositionException &e)
259 // NOTE: This makes over-ground roofed places sunlighted
260 // Assume sunlight, unless is_underground==true
267 MapNode n = getNode(v3s16(x, MAP_BLOCKSIZE-1, z));
268 //if(n.getContent() == CONTENT_WATER || n.getContent() == CONTENT_WATERSOURCE)
269 if(content_features(n).sunlight_propagates == false)
274 // NOTE: As of now, this just would make everything dark.
276 //no_sunlight = true;
279 #if 0 // Doesn't work; nothing gets light.
280 bool no_sunlight = true;
281 bool no_top_block = false;
282 // Check if node above block has sunlight
284 MapNode n = getNodeParent(v3s16(x, MAP_BLOCKSIZE, z));
285 if(n.getLight(LIGHTBANK_DAY) == LIGHT_SUN)
290 catch(InvalidPositionException &e)
296 /*std::cout<<"("<<x<<","<<z<<"): "
297 <<"no_top_block="<<no_top_block
298 <<", is_underground="<<is_underground
299 <<", no_sunlight="<<no_sunlight
302 s16 y = MAP_BLOCKSIZE-1;
304 // This makes difference to diminishing in water.
305 bool stopped_to_solid_object = false;
307 u8 current_light = no_sunlight ? 0 : LIGHT_SUN;
312 MapNode &n = getNodeRef(pos);
314 if(current_light == 0)
318 else if(current_light == LIGHT_SUN && n.sunlight_propagates())
320 // Do nothing: Sunlight is continued
322 else if(n.light_propagates() == false)
324 /*// DEPRECATED TODO: REMOVE
327 bool upper_is_air = false;
330 if(getNodeParent(pos+v3s16(0,1,0)).getContent() == CONTENT_AIR)
333 catch(InvalidPositionException &e)
336 // Turn mud into grass
337 if(upper_is_air && n.getContent() == CONTENT_MUD
338 && current_light == LIGHT_SUN)
344 // A solid object is on the way.
345 stopped_to_solid_object = true;
353 current_light = diminish_light(current_light);
356 u8 old_light = n.getLight(LIGHTBANK_DAY);
358 if(current_light > old_light || remove_light)
360 n.setLight(LIGHTBANK_DAY, current_light);
363 if(diminish_light(current_light) != 0)
365 light_sources.insert(pos_relative + pos, true);
368 if(current_light == 0 && stopped_to_solid_object)
372 *black_air_left = true;
377 // Whether or not the block below should see LIGHT_SUN
378 bool sunlight_should_go_down = (current_light == LIGHT_SUN);
381 If the block below hasn't already been marked invalid:
383 Check if the node below the block has proper sunlight at top.
384 If not, the block below is invalid.
386 Ignore non-transparent nodes as they always have no light
390 if(block_below_is_valid)
392 MapNode n = getNodeParent(v3s16(x, -1, z));
393 if(n.light_propagates())
395 if(n.getLight(LIGHTBANK_DAY) == LIGHT_SUN
396 && sunlight_should_go_down == false)
397 block_below_is_valid = false;
398 else if(n.getLight(LIGHTBANK_DAY) != LIGHT_SUN
399 && sunlight_should_go_down == true)
400 block_below_is_valid = false;
404 catch(InvalidPositionException &e)
406 /*std::cout<<"InvalidBlockException for bottom block node"
408 // Just no block below, no need to panic.
413 return block_below_is_valid;
417 void MapBlock::copyTo(VoxelManipulator &dst)
419 v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE);
420 VoxelArea data_area(v3s16(0,0,0), data_size - v3s16(1,1,1));
422 // Copy from data to VoxelManipulator
423 dst.copyFrom(data, data_area, v3s16(0,0,0),
424 getPosRelative(), data_size);
427 void MapBlock::copyFrom(VoxelManipulator &dst)
429 v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE);
430 VoxelArea data_area(v3s16(0,0,0), data_size - v3s16(1,1,1));
432 // Copy from VoxelManipulator to data
433 dst.copyTo(data, data_area, v3s16(0,0,0),
434 getPosRelative(), data_size);
437 void MapBlock::stepObjects(float dtime, bool server, u32 daynight_ratio)
442 m_objects.step(dtime, server, daynight_ratio);
448 void MapBlock::updateDayNightDiff()
452 m_day_night_differs = false;
456 bool differs = false;
459 Check if any lighting value differs
461 for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++)
463 MapNode &n = data[i];
464 if(n.getLight(LIGHTBANK_DAY) != n.getLight(LIGHTBANK_NIGHT))
472 If some lighting values differ, check if the whole thing is
473 just air. If it is, differ = false
477 bool only_air = true;
478 for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++)
480 MapNode &n = data[i];
481 if(n.getContent() != CONTENT_AIR)
491 // Set member variable
492 m_day_night_differs = differs;
495 s16 MapBlock::getGroundLevel(v2s16 p2d)
501 s16 y = MAP_BLOCKSIZE-1;
504 MapNode n = getNodeRef(p2d.X, y, p2d.Y);
505 if(content_features(n).walkable)
507 if(y == MAP_BLOCKSIZE-1)
515 catch(InvalidPositionException &e)
525 void MapBlock::serialize(std::ostream &os, u8 version)
527 if(!ser_ver_supported(version))
528 throw VersionMismatchException("ERROR: MapBlock format not supported");
532 throw SerializationError("ERROR: Not writing dummy block.");
535 // These have no compression
536 if(version <= 3 || version == 5 || version == 6)
538 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
540 u32 buflen = 1 + nodecount * MapNode::serializedLength(version);
541 SharedBuffer<u8> dest(buflen);
543 dest[0] = is_underground;
544 for(u32 i=0; i<nodecount; i++)
546 u32 s = 1 + i * MapNode::serializedLength(version);
547 data[i].serialize(&dest[s], version);
550 os.write((char*)*dest, dest.getSize());
552 else if(version <= 10)
556 Compress the materials and the params separately.
560 os.write((char*)&is_underground, 1);
562 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
564 // Get and compress materials
565 SharedBuffer<u8> materialdata(nodecount);
566 for(u32 i=0; i<nodecount; i++)
568 materialdata[i] = data[i].param0;
570 compress(materialdata, os, version);
572 // Get and compress lights
573 SharedBuffer<u8> lightdata(nodecount);
574 for(u32 i=0; i<nodecount; i++)
576 lightdata[i] = data[i].param1;
578 compress(lightdata, os, version);
582 // Get and compress param2
583 SharedBuffer<u8> param2data(nodecount);
584 for(u32 i=0; i<nodecount; i++)
586 param2data[i] = data[i].param2;
588 compress(param2data, os, version);
591 // All other versions (newest)
598 if(m_day_night_differs)
600 if(m_lighting_expired)
604 if(m_generated == false)
607 os.write((char*)&flags, 1);
609 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
616 SharedBuffer<u8> databuf_nodelist(nodecount*3);
617 for(u32 i=0; i<nodecount; i++)
619 data[i].serialize(&databuf_nodelist[i*3], version);
622 // Create buffer with different parameters sorted
623 SharedBuffer<u8> databuf(nodecount*3);
624 for(u32 i=0; i<nodecount; i++)
626 databuf[i] = databuf_nodelist[i*3];
627 databuf[i+nodecount] = databuf_nodelist[i*3+1];
628 databuf[i+nodecount*2] = databuf_nodelist[i*3+2];
632 Compress data to output stream
635 compress(databuf, os, version);
645 std::ostringstream oss(std::ios_base::binary);
646 m_node_metadata.serialize(oss);
647 os<<serializeString(oss.str());
649 // This will happen if the string is longer than 65535
650 catch(SerializationError &e)
652 // Use an empty string
653 os<<serializeString("");
658 std::ostringstream oss(std::ios_base::binary);
659 m_node_metadata.serialize(oss);
660 compressZlib(oss.str(), os);
661 //os<<serializeLongString(oss.str());
667 void MapBlock::deSerialize(std::istream &is, u8 version)
669 if(!ser_ver_supported(version))
670 throw VersionMismatchException("ERROR: MapBlock format not supported");
672 // These have no lighting info
675 setLightingExpired(true);
678 // These have no "generated" field
684 // These have no compression
685 if(version <= 3 || version == 5 || version == 6)
687 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
691 throw SerializationError
692 ("MapBlock::deSerialize: no enough input data");
693 is_underground = tmp;
694 for(u32 i=0; i<nodecount; i++)
696 s32 len = MapNode::serializedLength(version);
697 SharedBuffer<u8> d(len);
698 is.read((char*)*d, len);
699 if(is.gcount() != len)
700 throw SerializationError
701 ("MapBlock::deSerialize: no enough input data");
702 data[i].deSerialize(*d, version);
705 else if(version <= 10)
707 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
710 is.read((char*)&t8, 1);
714 // Uncompress and set material data
715 std::ostringstream os(std::ios_base::binary);
716 decompress(is, os, version);
717 std::string s = os.str();
718 if(s.size() != nodecount)
719 throw SerializationError
720 ("MapBlock::deSerialize: invalid format");
721 for(u32 i=0; i<s.size(); i++)
723 data[i].param0 = s[i];
727 // Uncompress and set param data
728 std::ostringstream os(std::ios_base::binary);
729 decompress(is, os, version);
730 std::string s = os.str();
731 if(s.size() != nodecount)
732 throw SerializationError
733 ("MapBlock::deSerialize: invalid format");
734 for(u32 i=0; i<s.size(); i++)
736 data[i].param1 = s[i];
742 // Uncompress and set param2 data
743 std::ostringstream os(std::ios_base::binary);
744 decompress(is, os, version);
745 std::string s = os.str();
746 if(s.size() != nodecount)
747 throw SerializationError
748 ("MapBlock::deSerialize: invalid format");
749 for(u32 i=0; i<s.size(); i++)
751 data[i].param2 = s[i];
755 // All other versions (newest)
758 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
761 is.read((char*)&flags, 1);
762 is_underground = (flags & 0x01) ? true : false;
763 m_day_night_differs = (flags & 0x02) ? true : false;
764 m_lighting_expired = (flags & 0x04) ? true : false;
766 m_generated = (flags & 0x08) ? false : true;
769 std::ostringstream os(std::ios_base::binary);
770 decompress(is, os, version);
771 std::string s = os.str();
772 if(s.size() != nodecount*3)
773 throw SerializationError
774 ("MapBlock::deSerialize: decompress resulted in size"
775 " other than nodecount*3");
777 // deserialize nodes from buffer
778 for(u32 i=0; i<nodecount; i++)
782 buf[1] = s[i+nodecount];
783 buf[2] = s[i+nodecount*2];
784 data[i].deSerialize(buf, version);
796 std::string data = deSerializeString(is);
797 std::istringstream iss(data, std::ios_base::binary);
798 m_node_metadata.deSerialize(iss);
802 //std::string data = deSerializeLongString(is);
803 std::ostringstream oss(std::ios_base::binary);
804 decompressZlib(is, oss);
805 std::istringstream iss(oss.str(), std::ios_base::binary);
806 m_node_metadata.deSerialize(iss);
809 catch(SerializationError &e)
811 dstream<<"WARNING: MapBlock::deSerialize(): Ignoring an error"
812 <<" while deserializing node metadata"<<std::endl;
818 void MapBlock::serializeDiskExtra(std::ostream &os, u8 version)
820 // Versions up from 9 have block objects.
823 //serializeObjects(os, version); // DEPRECATED
828 // Versions up from 15 have static objects.
831 m_static_objects.serialize(os);
837 writeU32(os, getTimestamp());
841 void MapBlock::deSerializeDiskExtra(std::istream &is, u8 version)
844 Versions up from 9 have block objects.
848 updateObjects(is, version, NULL, 0);
852 Versions up from 15 have static objects.
856 m_static_objects.deSerialize(is);
862 setTimestamp(readU32(is));
866 setTimestamp(BLOCK_TIMESTAMP_UNDEFINED);
871 Get a quick string to describe what a block actually contains
873 std::string analyze_block(MapBlock *block)
880 std::ostringstream desc;
882 v3s16 p = block->getPos();
884 snprintf(spos, 20, "(%2d,%2d,%2d), ", p.X, p.Y, p.Z);
887 switch(block->getModified())
889 case MOD_STATE_CLEAN:
892 case MOD_STATE_WRITE_AT_UNLOAD:
893 desc<<"WRITE_AT_UNLOAD, ";
895 case MOD_STATE_WRITE_NEEDED:
896 desc<<"WRITE_NEEDED, ";
899 desc<<"unknown getModified()="+itos(block->getModified())+", ";
902 if(block->isGenerated())
903 desc<<"is_gen [X], ";
905 desc<<"is_gen [ ], ";
907 if(block->getIsUnderground())
913 if(block->getMeshExpired())
914 desc<<"mesh_exp [X], ";
916 desc<<"mesh_exp [ ], ";
919 if(block->getLightingExpired())
920 desc<<"lighting_exp [X], ";
922 desc<<"lighting_exp [ ], ";
930 // We'll just define the numbers here, don't want to include
932 const content_t content_water = 2;
933 const content_t content_watersource = 9;
934 const content_t content_tree = 0x801;
935 const content_t content_leaves = 0x802;
936 const content_t content_jungletree = 0x815;
938 bool full_ignore = true;
939 bool some_ignore = false;
940 bool full_air = true;
941 bool some_air = false;
944 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
945 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
946 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
949 MapNode n = block->getNode(p);
950 content_t c = n.getContent();
951 if(c == CONTENT_IGNORE)
959 if(c == content_tree || c == content_jungletree
960 || c == content_leaves)
962 if(c == content_water
963 || c == content_watersource)
969 std::ostringstream ss;
972 ss<<"IGNORE (full), ";
986 if(ss.str().size()>=2)
987 desc<<ss.str().substr(0, ss.str().size()-2);
992 return desc.str().substr(0, desc.str().size()-2);