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.
29 #define sleep_s(x) Sleep((x*1000))
32 #define sleep_s(x) sleep(x)
35 #include "common_irrlicht.h"
38 #include "mapsector.h"
39 #include "constants.h"
43 #define MAPTYPE_BASE 0
44 #define MAPTYPE_SERVER 1
45 #define MAPTYPE_CLIENT 2
47 class Map : public NodeContainer
51 Map(std::ostream &dout);
54 virtual u16 nodeContainerId() const
56 return NODECONTAINER_ID_MAP;
59 virtual s32 mapType() const
65 Drop (client) or delete (server) the map.
72 void updateCamera(v3f pos, v3f dir)
74 JMutexAutoLock lock(m_camera_mutex);
75 m_camera_position = pos;
76 m_camera_direction = dir;
79 static core::aabbox3d<f32> getNodeBox(v3s16 p)
81 return core::aabbox3d<f32>(
82 (float)p.X * BS - 0.5*BS,
83 (float)p.Y * BS - 0.5*BS,
84 (float)p.Z * BS - 0.5*BS,
85 (float)p.X * BS + 0.5*BS,
86 (float)p.Y * BS + 0.5*BS,
87 (float)p.Z * BS + 0.5*BS
91 // On failure returns NULL
92 MapSector * getSectorNoGenerateNoExNoLock(v2s16 p2d);
93 // On failure returns NULL
94 MapSector * getSectorNoGenerateNoEx(v2s16 p2d);
95 // On failure throws InvalidPositionException
96 MapSector * getSectorNoGenerate(v2s16 p2d);
97 // Gets an existing sector or creates an empty one
98 //MapSector * getSectorCreate(v2s16 p2d);
101 This is overloaded by ClientMap and ServerMap to allow
102 their differing fetch methods.
104 virtual MapSector * emergeSector(v2s16 p){ return NULL; }
105 virtual MapSector * emergeSector(v2s16 p,
106 core::map<v3s16, MapBlock*> &changed_blocks){ return NULL; }
108 // Returns InvalidPositionException if not found
109 MapBlock * getBlockNoCreate(v3s16 p);
110 // Returns NULL if not found
111 MapBlock * getBlockNoCreateNoEx(v3s16 p);
112 // Gets an existing block or creates an empty one
113 //MapBlock * getBlockCreate(v3s16 p);
115 // Returns InvalidPositionException if not found
116 f32 getGroundHeight(v2s16 p, bool generate=false);
117 void setGroundHeight(v2s16 p, f32 y, bool generate=false);
119 // Returns InvalidPositionException if not found
120 bool isNodeUnderground(v3s16 p);
122 // virtual from NodeContainer
123 bool isValidPosition(v3s16 p)
125 v3s16 blockpos = getNodeBlockPos(p);
128 blockref = getBlockNoCreate(blockpos);
130 catch(InvalidPositionException &e)
135 /*v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
136 bool is_valid = blockref->isValidPosition(relpos);
140 // virtual from NodeContainer
141 // throws InvalidPositionException if not found
142 MapNode getNode(v3s16 p)
144 v3s16 blockpos = getNodeBlockPos(p);
145 MapBlock * blockref = getBlockNoCreate(blockpos);
146 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
148 return blockref->getNodeNoCheck(relpos);
151 // virtual from NodeContainer
152 // throws InvalidPositionException if not found
153 void setNode(v3s16 p, MapNode & n)
155 v3s16 blockpos = getNodeBlockPos(p);
156 MapBlock * blockref = getBlockNoCreate(blockpos);
157 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
158 blockref->setNodeNoCheck(relpos, n);
161 // Returns a CONTENT_IGNORE node if not found
162 MapNode getNodeNoEx(v3s16 p)
165 v3s16 blockpos = getNodeBlockPos(p);
166 MapBlock * blockref = getBlockNoCreate(blockpos);
167 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
169 return blockref->getNodeNoCheck(relpos);
171 catch(InvalidPositionException &e)
173 return MapNode(CONTENT_IGNORE);
177 void unspreadLight(enum LightBank bank,
178 core::map<v3s16, u8> & from_nodes,
179 core::map<v3s16, bool> & light_sources,
180 core::map<v3s16, MapBlock*> & modified_blocks);
182 void unLightNeighbors(enum LightBank bank,
183 v3s16 pos, u8 lightwas,
184 core::map<v3s16, bool> & light_sources,
185 core::map<v3s16, MapBlock*> & modified_blocks);
187 void spreadLight(enum LightBank bank,
188 core::map<v3s16, bool> & from_nodes,
189 core::map<v3s16, MapBlock*> & modified_blocks);
191 void lightNeighbors(enum LightBank bank,
193 core::map<v3s16, MapBlock*> & modified_blocks);
195 v3s16 getBrightestNeighbour(enum LightBank bank, v3s16 p);
197 s16 propagateSunlight(v3s16 start,
198 core::map<v3s16, MapBlock*> & modified_blocks);
200 void updateLighting(enum LightBank bank,
201 core::map<v3s16, MapBlock*> & a_blocks,
202 core::map<v3s16, MapBlock*> & modified_blocks);
204 void updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
205 core::map<v3s16, MapBlock*> & modified_blocks);
208 These handle lighting but not faces.
210 void addNodeAndUpdate(v3s16 p, MapNode n,
211 core::map<v3s16, MapBlock*> &modified_blocks);
212 void removeNodeAndUpdate(v3s16 p,
213 core::map<v3s16, MapBlock*> &modified_blocks);
216 Takes the blocks at the edges into account
218 bool dayNightDiffed(v3s16 blockpos);
220 //core::aabbox3d<s16> getDisplayedBlockArea();
222 //bool updateChangedVisibleArea();
224 virtual void save(bool only_changed){assert(0);};
229 void timerUpdate(float dtime);
231 // Takes cache into account
232 // sector mutex should be locked when calling
233 void deleteSectors(core::list<v2s16> &list, bool only_blocks);
235 // Returns count of deleted sectors
236 u32 deleteUnusedSectors(float timeout, bool only_blocks=false,
237 core::list<v3s16> *deleted_blocks=NULL);
239 // For debug printing
240 virtual void PrintInfo(std::ostream &out);
242 void transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks);
250 std::ostream &m_dout;
252 core::map<v2s16, MapSector*> m_sectors;
253 JMutex m_sector_mutex;
255 v3f m_camera_position;
256 v3f m_camera_direction;
257 JMutex m_camera_mutex;
259 // Be sure to set this to NULL when the cached sector is deleted
260 MapSector *m_sector_cache;
261 v2s16 m_sector_cache_p;
263 //WrapperHeightmap m_hwrapper;
265 // Queued transforming water nodes
266 UniqueQueue<v3s16> m_transforming_liquid;
272 This is the only map class that is able to generate map.
275 class ServerMap : public Map
279 savedir: directory to which map data should be saved
281 ServerMap(std::string savedir);
286 return MAPTYPE_SERVER;
293 // Returns the position of the chunk where the sector is in
294 v2s16 sector_to_chunk(v2s16 sectorpos)
296 sectorpos.X += m_chunksize / 2;
297 sectorpos.Y += m_chunksize / 2;
298 v2s16 chunkpos = getContainerPos(sectorpos, m_chunksize);
302 // Returns the position of the (0,0) sector of the chunk
303 v2s16 chunk_to_sector(v2s16 chunkpos)
306 chunkpos.X * m_chunksize,
307 chunkpos.Y * m_chunksize
309 sectorpos.X -= m_chunksize / 2;
310 sectorpos.Y -= m_chunksize / 2;
317 MapChunk *getChunk(v2s16 chunkpos)
319 core::map<v2s16, MapChunk*>::Node *n;
320 n = m_chunks.find(chunkpos);
323 return n->getValue();
327 True if the chunk and its neighbors are fully generated.
328 It means the chunk will not be touched in the future by the
329 generator. If false, generateChunk will make it true.
331 bool chunkNonVolatile(v2s16 chunkpos)
333 /*for(s16 x=-1; x<=1; x++)
334 for(s16 y=-1; y<=1; y++)*/
338 v2s16 chunkpos0 = chunkpos + v2s16(x,y);
339 MapChunk *chunk = getChunk(chunkpos);
342 if(chunk->getGenLevel() != GENERATED_FULLY)
351 All chunks touching this one can be altered also.
353 MapChunk* generateChunkRaw(v2s16 chunkpos,
354 core::map<v3s16, MapBlock*> &changed_blocks,
358 Generate a chunk and its neighbors so that it won't be touched
361 MapChunk* generateChunk(v2s16 chunkpos,
362 core::map<v3s16, MapBlock*> &changed_blocks);
367 This is mainly called by generateChunkRaw.
369 //ServerMapSector * generateSector(v2s16 p);
372 Get a sector from somewhere.
374 - Check disk (loads blocks also)
377 ServerMapSector * createSector(v2s16 p);
380 Get a sector from somewhere.
382 - Check disk (loads blocks also)
385 MapSector * emergeSector(v2s16 p,
386 core::map<v3s16, MapBlock*> &changed_blocks);
388 MapSector * emergeSector(v2s16 p)
390 core::map<v3s16, MapBlock*> changed_blocks;
391 return emergeSector(p, changed_blocks);
394 MapBlock * generateBlock(
396 MapBlock *original_dummy,
397 ServerMapSector *sector,
398 core::map<v3s16, MapBlock*> &changed_blocks,
399 core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
403 Get a block from somewhere.
407 MapBlock * createBlock(v3s16 p);
410 only_from_disk, changed_blocks and lighting_invalidated_blocks
411 are not properly used by the new map generator.
413 MapBlock * emergeBlock(
416 core::map<v3s16, MapBlock*> &changed_blocks,
417 core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
422 Forcefully get a block from somewhere.
425 - InvalidPositionException: possible if only_from_disk==true
428 - All already existing blocks that were modified are added.
429 - If found on disk, nothing will be added.
430 - If generated, the new block will not be included.
432 lighting_invalidated_blocks:
433 - All blocks that have heavy-to-calculate lighting changes
435 - updateLighting() should be called for these.
437 - A block that is in changed_blocks may not be in
438 lighting_invalidated_blocks.
440 MapBlock * emergeBlock(
443 core::map<v3s16, MapBlock*> &changed_blocks,
444 core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
449 Misc. helper functions for fiddling with directory and file
452 void createDir(std::string path);
453 void createSaveDir();
454 // returns something like "xxxxxxxx"
455 std::string getSectorSubDir(v2s16 pos);
456 // returns something like "map/sectors/xxxxxxxx"
457 std::string getSectorDir(v2s16 pos);
458 std::string createSectorDir(v2s16 pos);
459 // dirname: final directory name
460 v2s16 getSectorPos(std::string dirname);
461 v3s16 getBlockPos(std::string sectordir, std::string blockfile);
463 void save(bool only_changed);
466 // Saves map seed and possibly other stuff
470 void saveChunkMeta();
471 void loadChunkMeta();
473 // The sector mutex should be locked when calling most of these
475 // This only saves sector-specific data such as the heightmap
477 // DEPRECATED? Sectors have no metadata anymore.
478 void saveSectorMeta(ServerMapSector *sector);
479 MapSector* loadSectorMeta(std::string dirname);
481 // Full load of a sector including all blocks.
482 // returns true on success, false on failure.
483 bool loadSectorFull(v2s16 p2d);
484 // If sector is not found in memory, try to load it from disk.
485 // Returns true if sector now resides in memory
486 //bool deFlushSector(v2s16 p2d);
488 void saveBlock(MapBlock *block);
489 // This will generate a sector with getSector if not found.
490 void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector);
492 // Gets from master heightmap
494 void getSectorCorners(v2s16 p2d, s16 *corners);
496 // For debug printing
497 virtual void PrintInfo(std::ostream &out);
499 bool isSavingEnabled(){ return m_map_saving_enabled; }
502 // Seed used for all kinds of randomness
505 std::string m_savedir;
506 bool m_map_saving_enabled;
508 // Chunk size in MapSectors
511 core::map<v2s16, MapChunk*> m_chunks;
520 struct MapDrawControl
525 wanted_max_blocks(0),
528 blocks_would_have_drawn(0)
531 // Overrides limits by drawing everything
533 // Wanted drawing range
535 // Maximum number of blocks to draw
536 u32 wanted_max_blocks;
537 // Blocks in this range are drawn regardless of number of blocks drawn
538 float wanted_min_range;
539 // Number of blocks rendered is written here by the renderer
541 // Number of blocks that would have been drawn in wanted_range
542 u32 blocks_would_have_drawn;
550 This is the only map class that is able to render itself on screen.
553 class ClientMap : public Map, public scene::ISceneNode
558 MapDrawControl &control,
559 scene::ISceneNode* parent,
560 scene::ISceneManager* mgr,
568 return MAPTYPE_CLIENT;
577 Forcefully get a sector from somewhere
579 MapSector * emergeSector(v2s16 p);
581 void deSerializeSector(v2s16 p2d, std::istream &is);
587 virtual void OnRegisterSceneNode();
589 virtual void render()
591 video::IVideoDriver* driver = SceneManager->getVideoDriver();
592 driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
593 renderMap(driver, SceneManager->getSceneNodeRenderPass());
596 virtual const core::aabbox3d<f32>& getBoundingBox() const
601 void renderMap(video::IVideoDriver* driver, s32 pass);
604 Methods for setting temporary modifications to nodes for
607 Returns true if something changed.
609 All blocks whose mesh could have been changed are inserted
612 bool setTempMod(v3s16 p, NodeMod mod,
613 core::map<v3s16, MapBlock*> *affected_blocks=NULL);
614 bool clearTempMod(v3s16 p,
615 core::map<v3s16, MapBlock*> *affected_blocks=NULL);
616 // Efficient implementation needs a cache of TempMods
617 //void clearTempMods();
619 void expireMeshes(bool only_daynight_diffed);
622 Update the faces of the given block and blocks on the
625 void updateMeshes(v3s16 blockpos, u32 daynight_ratio);
627 // Update meshes that touch the node
628 //void updateNodeMeshes(v3s16 nodepos, u32 daynight_ratio);
630 // For debug printing
631 virtual void PrintInfo(std::ostream &out);
636 core::aabbox3d<f32> m_box;
638 // This is the master heightmap mesh
639 //scene::SMesh *mesh;
642 MapDrawControl &m_control;
647 class MapVoxelManipulator : public VoxelManipulator
650 MapVoxelManipulator(Map *map);
651 virtual ~MapVoxelManipulator();
655 VoxelManipulator::clear();
656 m_loaded_blocks.clear();
659 virtual void emerge(VoxelArea a, s32 caller_id=-1);
661 void blitBack(core::map<v3s16, MapBlock*> & modified_blocks);
667 value = block existed when loaded
669 core::map<v3s16, bool> m_loaded_blocks;
672 class ManualMapVoxelManipulator : public MapVoxelManipulator
675 ManualMapVoxelManipulator(Map *map);
676 virtual ~ManualMapVoxelManipulator();
678 virtual void emerge(VoxelArea a, s32 caller_id=-1);
680 void initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max);
682 // This is much faster with big chunks of generated data
683 void blitBackAll(core::map<v3s16, MapBlock*> * modified_blocks);