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"
35 // Named by looking towards z+
48 video::S3DVertex vertices[4]; // Precalculated vertices
54 NODEMOD_CHANGECONTENT, //param is content id
55 NODEMOD_CRACK // param is crack progression
60 NodeMod(enum NodeModType a_type=NODEMOD_NONE, u16 a_param=0)
65 bool operator==(const NodeMod &other)
67 return (type == other.type && param == other.param);
69 enum NodeModType type;
77 returns true if the mod was different last time
79 bool set(v3s16 p, const NodeMod &mod)
81 // See if old is different, cancel if it is not different.
82 core::map<v3s16, NodeMod>::Node *n = m_mods.find(p);
85 NodeMod old = n->getValue();
93 m_mods.insert(p, mod);
98 // Returns true if there was one
99 bool get(v3s16 p, NodeMod *mod)
101 core::map<v3s16, NodeMod>::Node *n;
106 *mod = n->getValue();
120 if(m_mods.size() == 0)
125 void copy(NodeModMap &dest)
129 for(core::map<v3s16, NodeMod>::Iterator
130 i = m_mods.getIterator();
131 i.atEnd() == false; i++)
133 dest.m_mods.insert(i.getNode()->getKey(), i.getNode()->getValue());
138 core::map<v3s16, NodeMod> m_mods;
143 NODECONTAINER_ID_MAPBLOCK,
144 NODECONTAINER_ID_MAPSECTOR,
145 NODECONTAINER_ID_MAP,
146 NODECONTAINER_ID_MAPBLOCKCACHE,
147 NODECONTAINER_ID_VOXELMANIPULATOR,
153 virtual bool isValidPosition(v3s16 p) = 0;
154 virtual MapNode getNode(v3s16 p) = 0;
155 virtual void setNode(v3s16 p, MapNode & n) = 0;
156 virtual u16 nodeContainerId() const = 0;
159 class MapBlock : public NodeContainer
162 MapBlock(NodeContainer *parent, v3s16 pos, bool dummy=false);
165 virtual u16 nodeContainerId() const
167 return NODECONTAINER_ID_MAPBLOCK;
170 NodeContainer * getParent()
179 u32 l = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
180 data = new MapNode[l];
181 for(u32 i=0; i<l; i++){
193 return (data == NULL);
201 bool getChangedFlag()
205 void resetChangedFlag()
209 void setChangedFlag()
214 bool getIsUnderground()
216 return is_underground;
219 void setIsUnderground(bool a_is_underground)
221 is_underground = a_is_underground;
226 void setMeshExpired(bool expired)
228 m_mesh_expired = expired;
231 bool getMeshExpired()
233 return m_mesh_expired;
237 void setLightingExpired(bool expired)
239 m_lighting_expired = expired;
242 bool getLightingExpired()
244 return m_lighting_expired;
249 if(m_lighting_expired)
265 v3s16 getPosRelative()
267 return m_pos * MAP_BLOCKSIZE;
270 core::aabbox3d<s16> getBox()
272 return core::aabbox3d<s16>(getPosRelative(),
274 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
279 Regular MapNode get-setters
282 bool isValidPosition(v3s16 p)
286 return (p.X >= 0 && p.X < MAP_BLOCKSIZE
287 && p.Y >= 0 && p.Y < MAP_BLOCKSIZE
288 && p.Z >= 0 && p.Z < MAP_BLOCKSIZE);
291 MapNode getNode(s16 x, s16 y, s16 z)
294 throw InvalidPositionException();
295 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
296 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
297 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
298 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
301 MapNode getNode(v3s16 p)
303 return getNode(p.X, p.Y, p.Z);
306 void setNode(s16 x, s16 y, s16 z, MapNode & n)
309 throw InvalidPositionException();
310 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
311 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
312 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
313 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
317 void setNode(v3s16 p, MapNode & n)
319 setNode(p.X, p.Y, p.Z, n);
323 Non-checking variants of the above
326 MapNode getNodeNoCheck(s16 x, s16 y, s16 z)
329 throw InvalidPositionException();
330 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
333 MapNode getNodeNoCheck(v3s16 p)
335 return getNodeNoCheck(p.X, p.Y, p.Z);
338 void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
341 throw InvalidPositionException();
342 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
346 void setNodeNoCheck(v3s16 p, MapNode & n)
348 setNodeNoCheck(p.X, p.Y, p.Z, n);
352 These functions consult the parent container if the position
353 is not valid on this MapBlock.
355 bool isValidPositionParent(v3s16 p);
356 MapNode getNodeParent(v3s16 p);
357 void setNodeParent(v3s16 p, MapNode & n);
358 MapNode getNodeParentNoEx(v3s16 p);
360 void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
362 for(u16 z=0; z<d; z++)
363 for(u16 y=0; y<h; y++)
364 for(u16 x=0; x<w; x++)
365 setNode(x0+x, y0+y, z0+z, node);
369 Graphics-related methods
372 // A quick version with nodes passed as parameters
373 u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
375 // A more convenient version
376 u8 getFaceLight(u32 daynight_ratio, v3s16 p, v3s16 face_dir)
378 return getFaceLight(daynight_ratio,
379 getNodeParentNoEx(p),
380 getNodeParentNoEx(p + face_dir),
386 static void makeFastFace(TileSpec tile, u8 light, v3f p,
387 v3s16 dir, v3f scale, v3f posRelative_f,
388 core::array<FastFace> &dest);
390 TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
391 NodeModMap &temp_mods);
392 u8 getNodeContent(v3s16 p, MapNode mn,
393 NodeModMap &temp_mods);
396 Generates the FastFaces of a node row. This has a
397 ridiculous amount of parameters because that way they
398 can be precalculated by the caller.
400 translate_dir: unit vector with only one of x, y or z
401 face_dir: unit vector with only one of x, y or z
403 void updateFastFaceRow(
412 core::array<FastFace> &dest,
413 NodeModMap &temp_mods);
416 Thread-safely updates the whole mesh of the mapblock.
418 void updateMesh(u32 daynight_ratio);
422 // See comments in mapblock.cpp
423 bool propagateSunlight(core::map<v3s16, bool> & light_sources,
424 bool remove_light=false, bool *black_air_left=NULL,
425 bool grow_grass=false);
427 // Copies data to VoxelManipulator to getPosRelative()
428 void copyTo(VoxelManipulator &dst);
429 // Copies data from VoxelManipulator getPosRelative()
430 void copyFrom(VoxelManipulator &dst);
436 void serializeObjects(std::ostream &os, u8 version)
438 m_objects.serialize(os, version);
440 // If smgr!=NULL, new objects are added to the scene
441 void updateObjects(std::istream &is, u8 version,
442 scene::ISceneManager *smgr, u32 daynight_ratio)
444 m_objects.update(is, version, smgr, daynight_ratio);
454 void addObject(MapBlockObject *object)
455 throw(ContainerFullException, AlreadyExistsException)
457 m_objects.add(object);
461 void removeObject(s16 id)
463 m_objects.remove(id);
467 MapBlockObject * getObject(s16 id)
469 return m_objects.get(id);
471 JMutexAutoLock * getObjectLock()
473 return m_objects.getLock();
477 Moves objects, deletes objects and spawns new objects
479 void stepObjects(float dtime, bool server, u32 daynight_ratio);
481 /*void wrapObject(MapBlockObject *object)
483 m_objects.wrapObject(object);
488 // origin is relative to block
489 void getObjects(v3f origin, f32 max_d,
490 core::array<DistanceSortedObject> &dest)
492 m_objects.getObjects(origin, max_d, dest);
497 return m_objects.getCount();
502 Methods for setting temporary modifications to nodes for
505 returns true if the mod was different last time
507 bool setTempMod(v3s16 p, const NodeMod &mod)
509 /*dstream<<"setTempMod called on block"
510 <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
511 <<", mod.type="<<mod.type
512 <<", mod.param="<<mod.param
514 JMutexAutoLock lock(m_temp_mods_mutex);
516 return m_temp_mods.set(p, mod);
518 // Returns true if there was one
519 bool getTempMod(v3s16 p, NodeMod *mod)
521 JMutexAutoLock lock(m_temp_mods_mutex);
523 return m_temp_mods.get(p, mod);
525 bool clearTempMod(v3s16 p)
527 JMutexAutoLock lock(m_temp_mods_mutex);
529 return m_temp_mods.clear(p);
533 JMutexAutoLock lock(m_temp_mods_mutex);
535 return m_temp_mods.clear();
540 Update day-night lighting difference flag.
542 Sets m_day_night_differs to appropriate value.
544 These methods don't care about neighboring blocks.
545 It means that to know if a block really doesn't need a mesh
546 update between day and night, the neighboring blocks have
547 to be taken into account. Use Map::dayNightDiffed().
549 void updateDayNightDiff();
551 bool dayNightDiffed()
553 return m_day_night_differs;
561 Tries to measure ground level.
566 0...MAP_BLOCKSIZE-1 = ground level
568 s16 getGroundLevel(v2s16 p2d);
574 // Doesn't write version by itself
575 void serialize(std::ostream &os, u8 version);
577 void deSerialize(std::istream &is, u8 version);
585 Used only internally, because changes can't be tracked
588 MapNode & getNodeRef(s16 x, s16 y, s16 z)
591 throw InvalidPositionException();
592 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
593 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
594 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
595 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
597 MapNode & getNodeRef(v3s16 &p)
599 return getNodeRef(p.X, p.Y, p.Z);
604 Public member variables
614 Private member variables
617 // Parent container (practically the Map)
618 // Not a MapSector, it is just a structural element.
619 NodeContainer *m_parent;
620 // Position in blocks on parent
624 If NULL, block is a dummy block.
625 Dummy blocks are used for caching not-found-on-disk blocks.
630 - On the server, this is used for telling whether the
631 block has been changed from the one on disk.
632 - On the client, this is used for nothing.
637 When propagating sunlight and the above block doesn't exist,
638 sunlight is assumed if this is false.
640 In practice this is set to true if the block is completely
641 undeground with nothing visible above the ground except
647 Set to true if changes has been made that make the old lighting
648 values wrong but the lighting hasn't been actually updated.
650 If this is false, lighting is exactly right.
651 If this is true, lighting might be wrong or right.
653 bool m_lighting_expired;
655 // Whether day and night lighting differs
656 bool m_day_night_differs;
658 MapBlockObjectList m_objects;
660 // Object spawning stuff
665 Set to true if the mesh has been ordered to be updated
666 sometime in the background.
667 In practice this is set when the day/night lighting switches.
671 // Temporary modifications to nodes
672 // These are only used when drawing
673 NodeModMap m_temp_mods;
674 JMutex m_temp_mods_mutex;
678 inline bool blockpos_over_limit(v3s16 p)
681 (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
682 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
683 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
684 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
685 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
686 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
690 Returns the position of the block where the node is located
692 inline v3s16 getNodeBlockPos(v3s16 p)
694 return getContainerPos(p, MAP_BLOCKSIZE);
697 inline v2s16 getNodeSectorPos(v2s16 p)
699 return getContainerPos(p, MAP_BLOCKSIZE);
702 inline s16 getNodeBlockY(s16 y)
704 return getContainerPos(y, MAP_BLOCKSIZE);