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.
20 #ifndef MAPBLOCK_HEADER
21 #define MAPBLOCK_HEADER
24 #include <jmutexautolock.h>
27 #include "common_irrlicht.h"
29 #include "exceptions.h"
30 #include "serialization.h"
31 #include "constants.h"
33 #include "nodemetadata.h"
34 #include "staticobject.h"
35 #include "mapblock_nodemod.h"
37 #include "mapblock_mesh.h"
42 #define BLOCK_TIMESTAMP_UNDEFINED 0xffffffff
44 /*// Named by looking towards z+
56 // Has not been modified.
59 // Has been modified, and will be saved when being unloaded.
60 MOD_STATE_WRITE_AT_UNLOAD = 2,
62 // Has been modified, and will be saved as soon as possible.
63 MOD_STATE_WRITE_NEEDED = 4,
67 // NOTE: If this is enabled, set MapBlock to be initialized with
69 /*enum BlockGenerationStatus
71 // Completely non-generated (filled with CONTENT_IGNORE).
73 // Trees or similar might have been blitted from other blocks to here.
74 // Otherwise, the block contains CONTENT_IGNORE
75 BLOCKGEN_FROM_NEIGHBORS=2,
76 // Has been generated, but some neighbors might put some stuff in here
77 // when they are generated.
78 // Does not contain any CONTENT_IGNORE
79 BLOCKGEN_SELF_GENERATED=4,
80 // The block and all its neighbors have been generated
81 BLOCKGEN_FULLY_GENERATED=6
87 NODECONTAINER_ID_MAPBLOCK,
88 NODECONTAINER_ID_MAPSECTOR,
90 NODECONTAINER_ID_MAPBLOCKCACHE,
91 NODECONTAINER_ID_VOXELMANIPULATOR,
97 virtual bool isValidPosition(v3s16 p) = 0;
98 virtual MapNode getNode(v3s16 p) = 0;
99 virtual void setNode(v3s16 p, MapNode & n) = 0;
100 virtual u16 nodeContainerId() const = 0;
102 MapNode getNodeNoEx(v3s16 p)
107 catch(InvalidPositionException &e){
108 return MapNode(CONTENT_IGNORE);
118 class MapBlock /*: public NodeContainer*/
121 MapBlock(Map *parent, v3s16 pos, bool dummy=false);
124 /*virtual u16 nodeContainerId() const
126 return NODECONTAINER_ID_MAPBLOCK;
138 u32 l = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
139 data = new MapNode[l];
140 for(u32 i=0; i<l; i++){
141 //data[i] = MapNode();
142 data[i] = MapNode(CONTENT_IGNORE);
144 raiseModified(MOD_STATE_WRITE_NEEDED);
153 return (data == NULL);
162 This is called internally or externally after the block is
163 modified, so that the block is saved and possibly not deleted from
166 // DEPRECATED, use *Modified()
167 void setChangedFlag()
169 //dstream<<"Deprecated setChangedFlag() called"<<std::endl;
170 raiseModified(MOD_STATE_WRITE_NEEDED);
172 // DEPRECATED, use *Modified()
173 void resetChangedFlag()
175 //dstream<<"Deprecated resetChangedFlag() called"<<std::endl;
178 // DEPRECATED, use *Modified()
179 bool getChangedFlag()
181 //dstream<<"Deprecated getChangedFlag() called"<<std::endl;
182 if(getModified() == MOD_STATE_CLEAN)
188 // m_modified methods
189 void raiseModified(u32 mod)
191 m_modified = MYMAX(m_modified, mod);
199 m_modified = MOD_STATE_CLEAN;
202 // is_underground getter/setter
203 bool getIsUnderground()
205 return is_underground;
207 void setIsUnderground(bool a_is_underground)
209 is_underground = a_is_underground;
210 raiseModified(MOD_STATE_WRITE_NEEDED);
214 void setMeshExpired(bool expired)
216 m_mesh_expired = expired;
219 bool getMeshExpired()
221 return m_mesh_expired;
225 void setLightingExpired(bool expired)
227 if(expired != m_lighting_expired){
228 m_lighting_expired = expired;
229 raiseModified(MOD_STATE_WRITE_NEEDED);
232 bool getLightingExpired()
234 return m_lighting_expired;
241 void setGenerated(bool b)
243 if(b != m_generated){
244 raiseModified(MOD_STATE_WRITE_NEEDED);
251 if(m_lighting_expired)
267 v3s16 getPosRelative()
269 return m_pos * MAP_BLOCKSIZE;
272 core::aabbox3d<s16> getBox()
274 return core::aabbox3d<s16>(getPosRelative(),
276 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
281 Regular MapNode get-setters
284 bool isValidPosition(v3s16 p)
288 return (p.X >= 0 && p.X < MAP_BLOCKSIZE
289 && p.Y >= 0 && p.Y < MAP_BLOCKSIZE
290 && p.Z >= 0 && p.Z < MAP_BLOCKSIZE);
293 MapNode getNode(s16 x, s16 y, s16 z)
296 throw InvalidPositionException();
297 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
298 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
299 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
300 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
303 MapNode getNode(v3s16 p)
305 return getNode(p.X, p.Y, p.Z);
308 MapNode getNodeNoEx(v3s16 p)
311 return getNode(p.X, p.Y, p.Z);
312 }catch(InvalidPositionException &e){
313 return MapNode(CONTENT_IGNORE);
317 void setNode(s16 x, s16 y, s16 z, MapNode & n)
320 throw InvalidPositionException();
321 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
322 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
323 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
324 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
325 raiseModified(MOD_STATE_WRITE_NEEDED);
328 void setNode(v3s16 p, MapNode & n)
330 setNode(p.X, p.Y, p.Z, n);
334 Non-checking variants of the above
337 MapNode getNodeNoCheck(s16 x, s16 y, s16 z)
340 throw InvalidPositionException();
341 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
344 MapNode getNodeNoCheck(v3s16 p)
346 return getNodeNoCheck(p.X, p.Y, p.Z);
349 void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
352 throw InvalidPositionException();
353 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
354 raiseModified(MOD_STATE_WRITE_NEEDED);
357 void setNodeNoCheck(v3s16 p, MapNode & n)
359 setNodeNoCheck(p.X, p.Y, p.Z, n);
363 These functions consult the parent container if the position
364 is not valid on this MapBlock.
366 bool isValidPositionParent(v3s16 p);
367 MapNode getNodeParent(v3s16 p);
368 void setNodeParent(v3s16 p, MapNode & n);
369 MapNode getNodeParentNoEx(v3s16 p);
371 void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
373 for(u16 z=0; z<d; z++)
374 for(u16 y=0; y<h; y++)
375 for(u16 x=0; x<w; x++)
376 setNode(x0+x, y0+y, z0+z, node);
380 Graphics-related methods
383 /*// A quick version with nodes passed as parameters
384 u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
386 /*// A more convenient version
387 u8 getFaceLight(u32 daynight_ratio, v3s16 p, v3s16 face_dir)
389 return getFaceLight(daynight_ratio,
390 getNodeParentNoEx(p),
391 getNodeParentNoEx(p + face_dir),
394 u8 getFaceLight2(u32 daynight_ratio, v3s16 p, v3s16 face_dir)
396 return getFaceLight(daynight_ratio,
397 getNodeParentNoEx(p),
398 getNodeParentNoEx(p + face_dir),
402 #ifndef SERVER // Only on client
406 Thread-safely updates the whole mesh of the mapblock.
407 NOTE: Prefer generating the mesh separately and then using
410 void updateMesh(u32 daynight_ratio);
412 // Replace the mesh with a new one
413 void replaceMesh(scene::SMesh *mesh_new);
416 // See comments in mapblock.cpp
417 bool propagateSunlight(core::map<v3s16, bool> & light_sources,
418 bool remove_light=false, bool *black_air_left=NULL);
420 // Copies data to VoxelManipulator to getPosRelative()
421 void copyTo(VoxelManipulator &dst);
422 // Copies data from VoxelManipulator getPosRelative()
423 void copyFrom(VoxelManipulator &dst);
425 #ifndef SERVER // Only on client
427 Methods for setting temporary modifications to nodes for
430 returns true if the mod was different last time
432 bool setTempMod(v3s16 p, const NodeMod &mod)
434 /*dstream<<"setTempMod called on block"
435 <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
436 <<", mod.type="<<mod.type
437 <<", mod.param="<<mod.param
439 JMutexAutoLock lock(m_temp_mods_mutex);
441 return m_temp_mods.set(p, mod);
443 // Returns true if there was one
444 bool getTempMod(v3s16 p, NodeMod *mod)
446 JMutexAutoLock lock(m_temp_mods_mutex);
448 return m_temp_mods.get(p, mod);
450 bool clearTempMod(v3s16 p)
452 JMutexAutoLock lock(m_temp_mods_mutex);
454 return m_temp_mods.clear(p);
458 JMutexAutoLock lock(m_temp_mods_mutex);
460 return m_temp_mods.clear();
462 void copyTempMods(NodeModMap &dst)
464 JMutexAutoLock lock(m_temp_mods_mutex);
465 m_temp_mods.copy(dst);
470 Update day-night lighting difference flag.
472 Sets m_day_night_differs to appropriate value.
474 These methods don't care about neighboring blocks.
475 It means that to know if a block really doesn't need a mesh
476 update between day and night, the neighboring blocks have
477 to be taken into account. Use Map::dayNightDiffed().
479 void updateDayNightDiff();
481 bool dayNightDiffed()
483 return m_day_night_differs;
491 Tries to measure ground level.
496 0...MAP_BLOCKSIZE-1 = ground level
498 s16 getGroundLevel(v2s16 p2d);
501 Timestamp (see m_timestamp)
502 NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
504 void setTimestamp(u32 time)
507 raiseModified(MOD_STATE_WRITE_AT_UNLOAD);
509 void setTimestampNoChangedFlag(u32 time)
521 void resetUsageTimer()
525 void incrementUsageTimer(float dtime)
527 m_usage_timer += dtime;
531 return m_usage_timer;
538 // These don't write or read version by itself
539 void serialize(std::ostream &os, u8 version);
540 void deSerialize(std::istream &is, u8 version);
541 // Used after the basic ones when writing on disk (serverside)
542 void serializeDiskExtra(std::ostream &os, u8 version);
543 void deSerializeDiskExtra(std::istream &is, u8 version);
551 Used only internally, because changes can't be tracked
554 MapNode & getNodeRef(s16 x, s16 y, s16 z)
557 throw InvalidPositionException();
558 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
559 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
560 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
561 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
563 MapNode & getNodeRef(v3s16 &p)
565 return getNodeRef(p.X, p.Y, p.Z);
570 Public member variables
573 #ifndef SERVER // Only on client
578 NodeMetadataList m_node_metadata;
579 StaticObjectList m_static_objects;
583 Private member variables
586 // NOTE: Lots of things rely on this being the Map
588 // Position in blocks on parent
592 If NULL, block is a dummy block.
593 Dummy blocks are used for caching not-found-on-disk blocks.
598 - On the server, this is used for telling whether the
599 block has been modified from the one on disk.
600 - On the client, this is used for nothing.
605 When propagating sunlight and the above block doesn't exist,
606 sunlight is assumed if this is false.
608 In practice this is set to true if the block is completely
609 undeground with nothing visible above the ground except
615 Set to true if changes has been made that make the old lighting
616 values wrong but the lighting hasn't been actually updated.
618 If this is false, lighting is exactly right.
619 If this is true, lighting might be wrong or right.
621 bool m_lighting_expired;
623 // Whether day and night lighting differs
624 bool m_day_night_differs;
628 #ifndef SERVER // Only on client
630 Set to true if the mesh has been ordered to be updated
631 sometime in the background.
632 In practice this is set when the day/night lighting switches.
636 // Temporary modifications to nodes
637 // These are only used when drawing
638 NodeModMap m_temp_mods;
639 JMutex m_temp_mods_mutex;
643 When block is removed from active blocks, this is set to gametime.
644 Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
649 When the block is accessed, this is set to 0.
650 Map will unload the block when this reaches a timeout.
655 inline bool blockpos_over_limit(v3s16 p)
658 (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
659 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
660 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
661 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
662 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
663 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
667 Returns the position of the block where the node is located
669 inline v3s16 getNodeBlockPos(v3s16 p)
671 return getContainerPos(p, MAP_BLOCKSIZE);
674 inline v2s16 getNodeSectorPos(v2s16 p)
676 return getContainerPos(p, MAP_BLOCKSIZE);
679 inline s16 getNodeBlockY(s16 y)
681 return getContainerPos(y, MAP_BLOCKSIZE);
685 Get a quick string to describe what a block actually contains
687 std::string analyze_block(MapBlock *block);