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"
32 #include "mapblockobject.h"
34 #include "nodemetadata.h"
35 #include "staticobject.h"
36 #include "mapblock_nodemod.h"
38 #include "mapblock_mesh.h"
42 #define BLOCK_TIMESTAMP_UNDEFINED 0xffffffff
44 /*// Named by looking towards z+
56 NODECONTAINER_ID_MAPBLOCK,
57 NODECONTAINER_ID_MAPSECTOR,
59 NODECONTAINER_ID_MAPBLOCKCACHE,
60 NODECONTAINER_ID_VOXELMANIPULATOR,
66 virtual bool isValidPosition(v3s16 p) = 0;
67 virtual MapNode getNode(v3s16 p) = 0;
68 virtual void setNode(v3s16 p, MapNode & n) = 0;
69 virtual u16 nodeContainerId() const = 0;
71 MapNode getNodeNoEx(v3s16 p)
76 catch(InvalidPositionException &e){
77 return MapNode(CONTENT_IGNORE);
86 class MapBlock : public NodeContainer
89 MapBlock(NodeContainer *parent, v3s16 pos, bool dummy=false);
92 virtual u16 nodeContainerId() const
94 return NODECONTAINER_ID_MAPBLOCK;
97 NodeContainer * getParent()
106 u32 l = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
107 data = new MapNode[l];
108 for(u32 i=0; i<l; i++){
120 return (data == NULL);
129 This is called internally or externally after the block is
130 modified, so that the block is saved and possibly not deleted from
133 void setChangedFlag()
137 void resetChangedFlag()
141 bool getChangedFlag()
146 bool getIsUnderground()
148 return is_underground;
150 void setIsUnderground(bool a_is_underground)
152 is_underground = a_is_underground;
157 void setMeshExpired(bool expired)
159 m_mesh_expired = expired;
162 bool getMeshExpired()
164 return m_mesh_expired;
168 void setLightingExpired(bool expired)
170 m_lighting_expired = expired;
173 bool getLightingExpired()
175 return m_lighting_expired;
178 /*bool isFullyGenerated()
180 return !m_not_fully_generated;
182 void setFullyGenerated(bool b)
185 m_not_fully_generated = !b;
190 if(m_lighting_expired)
206 v3s16 getPosRelative()
208 return m_pos * MAP_BLOCKSIZE;
211 core::aabbox3d<s16> getBox()
213 return core::aabbox3d<s16>(getPosRelative(),
215 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
220 Regular MapNode get-setters
223 bool isValidPosition(v3s16 p)
227 return (p.X >= 0 && p.X < MAP_BLOCKSIZE
228 && p.Y >= 0 && p.Y < MAP_BLOCKSIZE
229 && p.Z >= 0 && p.Z < MAP_BLOCKSIZE);
232 MapNode getNode(s16 x, s16 y, s16 z)
235 throw InvalidPositionException();
236 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
237 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
238 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
239 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
242 MapNode getNode(v3s16 p)
244 return getNode(p.X, p.Y, p.Z);
247 MapNode getNodeNoEx(v3s16 p)
250 return getNode(p.X, p.Y, p.Z);
251 }catch(InvalidPositionException &e){
252 return MapNode(CONTENT_IGNORE);
256 void setNode(s16 x, s16 y, s16 z, MapNode & n)
259 throw InvalidPositionException();
260 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
261 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
262 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
263 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
267 void setNode(v3s16 p, MapNode & n)
269 setNode(p.X, p.Y, p.Z, n);
273 Non-checking variants of the above
276 MapNode getNodeNoCheck(s16 x, s16 y, s16 z)
279 throw InvalidPositionException();
280 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
283 MapNode getNodeNoCheck(v3s16 p)
285 return getNodeNoCheck(p.X, p.Y, p.Z);
288 void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
291 throw InvalidPositionException();
292 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
296 void setNodeNoCheck(v3s16 p, MapNode & n)
298 setNodeNoCheck(p.X, p.Y, p.Z, n);
302 These functions consult the parent container if the position
303 is not valid on this MapBlock.
305 bool isValidPositionParent(v3s16 p);
306 MapNode getNodeParent(v3s16 p);
307 void setNodeParent(v3s16 p, MapNode & n);
308 MapNode getNodeParentNoEx(v3s16 p);
310 void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
312 for(u16 z=0; z<d; z++)
313 for(u16 y=0; y<h; y++)
314 for(u16 x=0; x<w; x++)
315 setNode(x0+x, y0+y, z0+z, node);
319 Graphics-related methods
322 /*// A quick version with nodes passed as parameters
323 u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
325 /*// A more convenient version
326 u8 getFaceLight(u32 daynight_ratio, v3s16 p, v3s16 face_dir)
328 return getFaceLight(daynight_ratio,
329 getNodeParentNoEx(p),
330 getNodeParentNoEx(p + face_dir),
333 u8 getFaceLight2(u32 daynight_ratio, v3s16 p, v3s16 face_dir)
335 return getFaceLight(daynight_ratio,
336 getNodeParentNoEx(p),
337 getNodeParentNoEx(p + face_dir),
341 #ifndef SERVER // Only on client
345 Thread-safely updates the whole mesh of the mapblock.
346 NOTE: Prefer generating the mesh separately and then using
349 void updateMesh(u32 daynight_ratio);
351 // Replace the mesh with a new one
352 void replaceMesh(scene::SMesh *mesh_new);
355 // See comments in mapblock.cpp
356 bool propagateSunlight(core::map<v3s16, bool> & light_sources,
357 bool remove_light=false, bool *black_air_left=NULL);
359 // Copies data to VoxelManipulator to getPosRelative()
360 void copyTo(VoxelManipulator &dst);
361 // Copies data from VoxelManipulator getPosRelative()
362 void copyFrom(VoxelManipulator &dst);
369 void serializeObjects(std::ostream &os, u8 version)
371 m_objects.serialize(os, version);
373 // If smgr!=NULL, new objects are added to the scene
374 void updateObjects(std::istream &is, u8 version,
375 scene::ISceneManager *smgr, u32 daynight_ratio)
377 m_objects.update(is, version, smgr, daynight_ratio);
387 void addObject(MapBlockObject *object)
388 throw(ContainerFullException, AlreadyExistsException)
390 m_objects.add(object);
394 void removeObject(s16 id)
396 m_objects.remove(id);
400 MapBlockObject * getObject(s16 id)
402 return m_objects.get(id);
404 JMutexAutoLock * getObjectLock()
406 return m_objects.getLock();
410 Moves objects, deletes objects and spawns new objects
412 void stepObjects(float dtime, bool server, u32 daynight_ratio);
414 // origin is relative to block
415 void getObjects(v3f origin, f32 max_d,
416 core::array<DistanceSortedObject> &dest)
418 m_objects.getObjects(origin, max_d, dest);
423 return m_objects.getCount();
426 #ifndef SERVER // Only on client
428 Methods for setting temporary modifications to nodes for
431 returns true if the mod was different last time
433 bool setTempMod(v3s16 p, const NodeMod &mod)
435 /*dstream<<"setTempMod called on block"
436 <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
437 <<", mod.type="<<mod.type
438 <<", mod.param="<<mod.param
440 JMutexAutoLock lock(m_temp_mods_mutex);
442 return m_temp_mods.set(p, mod);
444 // Returns true if there was one
445 bool getTempMod(v3s16 p, NodeMod *mod)
447 JMutexAutoLock lock(m_temp_mods_mutex);
449 return m_temp_mods.get(p, mod);
451 bool clearTempMod(v3s16 p)
453 JMutexAutoLock lock(m_temp_mods_mutex);
455 return m_temp_mods.clear(p);
459 JMutexAutoLock lock(m_temp_mods_mutex);
461 return m_temp_mods.clear();
463 void copyTempMods(NodeModMap &dst)
465 JMutexAutoLock lock(m_temp_mods_mutex);
466 m_temp_mods.copy(dst);
471 Update day-night lighting difference flag.
473 Sets m_day_night_differs to appropriate value.
475 These methods don't care about neighboring blocks.
476 It means that to know if a block really doesn't need a mesh
477 update between day and night, the neighboring blocks have
478 to be taken into account. Use Map::dayNightDiffed().
480 void updateDayNightDiff();
482 bool dayNightDiffed()
484 return m_day_night_differs;
492 Tries to measure ground level.
497 0...MAP_BLOCKSIZE-1 = ground level
499 s16 getGroundLevel(v2s16 p2d);
502 Timestamp (see m_timestamp)
503 NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
505 void setTimestamp(u32 time)
510 void setTimestampNoChangedFlag(u32 time)
523 // These don't write or read version by itself
524 void serialize(std::ostream &os, u8 version);
525 void deSerialize(std::istream &is, u8 version);
526 // Used after the basic ones when writing on disk (serverside)
527 void serializeDiskExtra(std::ostream &os, u8 version);
528 void deSerializeDiskExtra(std::istream &is, u8 version);
536 Used only internally, because changes can't be tracked
539 MapNode & getNodeRef(s16 x, s16 y, s16 z)
542 throw InvalidPositionException();
543 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
544 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
545 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
546 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
548 MapNode & getNodeRef(v3s16 &p)
550 return getNodeRef(p.X, p.Y, p.Z);
555 Public member variables
558 #ifndef SERVER // Only on client
563 NodeMetadataList m_node_metadata;
564 StaticObjectList m_static_objects;
568 Private member variables
571 // NOTE: Lots of things rely on this being the Map
572 NodeContainer *m_parent;
573 // Position in blocks on parent
577 If NULL, block is a dummy block.
578 Dummy blocks are used for caching not-found-on-disk blocks.
583 - On the server, this is used for telling whether the
584 block has been changed from the one on disk.
585 - On the client, this is used for nothing.
590 When propagating sunlight and the above block doesn't exist,
591 sunlight is assumed if this is false.
593 In practice this is set to true if the block is completely
594 undeground with nothing visible above the ground except
600 Set to true if changes has been made that make the old lighting
601 values wrong but the lighting hasn't been actually updated.
603 If this is false, lighting is exactly right.
604 If this is true, lighting might be wrong or right.
606 bool m_lighting_expired;
608 // Whether day and night lighting differs
609 bool m_day_night_differs;
612 MapBlockObjectList m_objects;
614 #ifndef SERVER // Only on client
616 Set to true if the mesh has been ordered to be updated
617 sometime in the background.
618 In practice this is set when the day/night lighting switches.
622 // Temporary modifications to nodes
623 // These are only used when drawing
624 NodeModMap m_temp_mods;
625 JMutex m_temp_mods_mutex;
629 When block is removed from active blocks, this is set to gametime.
630 Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
635 inline bool blockpos_over_limit(v3s16 p)
638 (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
639 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
640 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
641 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
642 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
643 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
647 Returns the position of the block where the node is located
649 inline v3s16 getNodeBlockPos(v3s16 p)
651 return getContainerPos(p, MAP_BLOCKSIZE);
654 inline v2s16 getNodeSectorPos(v2s16 p)
656 return getContainerPos(p, MAP_BLOCKSIZE);
659 inline s16 getNodeBlockY(s16 y)
661 return getContainerPos(y, MAP_BLOCKSIZE);