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.
30 #define sleep_s(x) Sleep((x*1000))
33 #define sleep_s(x) sleep(x)
36 #include "common_irrlicht.h"
37 //#include "heightmap.h"
40 #include "mapsector.h"
41 #include "constants.h"
45 #define MAPTYPE_BASE 0
46 #define MAPTYPE_SERVER 1
47 #define MAPTYPE_CLIENT 2
49 class Map : public NodeContainer
53 Map(std::ostream &dout);
56 virtual u16 nodeContainerId() const
58 return NODECONTAINER_ID_MAP;
61 virtual s32 mapType() const
71 void updateCamera(v3f pos, v3f dir)
73 JMutexAutoLock lock(m_camera_mutex);
74 m_camera_position = pos;
75 m_camera_direction = dir;
78 static core::aabbox3d<f32> getNodeBox(v3s16 p)
80 return core::aabbox3d<f32>(
81 (float)p.X * BS - 0.5*BS,
82 (float)p.Y * BS - 0.5*BS,
83 (float)p.Z * BS - 0.5*BS,
84 (float)p.X * BS + 0.5*BS,
85 (float)p.Y * BS + 0.5*BS,
86 (float)p.Z * BS + 0.5*BS
90 // On failure returns NULL
91 MapSector * getSectorNoGenerateNoExNoLock(v2s16 p2d);
92 // On failure returns NULL
93 MapSector * getSectorNoGenerateNoEx(v2s16 p2d);
94 // On failure throws InvalidPositionException
95 MapSector * getSectorNoGenerate(v2s16 p2d);
96 // Gets an existing sector or creates an empty one
97 //MapSector * getSectorCreate(v2s16 p2d);
100 This is overloaded by ClientMap and ServerMap to allow
101 their differing fetch methods.
103 virtual MapSector * emergeSector(v2s16 p){ return NULL; }
104 virtual MapSector * emergeSector(v2s16 p,
105 core::map<v3s16, MapBlock*> &changed_blocks){ return NULL; }
107 // Returns InvalidPositionException if not found
108 MapBlock * getBlockNoCreate(v3s16 p);
109 // Returns NULL if not found
110 MapBlock * getBlockNoCreateNoEx(v3s16 p);
111 // Gets an existing block or creates an empty one
112 //MapBlock * getBlockCreate(v3s16 p);
114 // Returns InvalidPositionException if not found
115 f32 getGroundHeight(v2s16 p, bool generate=false);
116 void setGroundHeight(v2s16 p, f32 y, bool generate=false);
118 // Returns InvalidPositionException if not found
119 bool isNodeUnderground(v3s16 p);
121 // virtual from NodeContainer
122 bool isValidPosition(v3s16 p)
124 v3s16 blockpos = getNodeBlockPos(p);
127 blockref = getBlockNoCreate(blockpos);
129 catch(InvalidPositionException &e)
134 /*v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
135 bool is_valid = blockref->isValidPosition(relpos);
139 // virtual from NodeContainer
140 // throws InvalidPositionException if not found
141 MapNode getNode(v3s16 p)
143 v3s16 blockpos = getNodeBlockPos(p);
144 MapBlock * blockref = getBlockNoCreate(blockpos);
145 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
147 return blockref->getNodeNoCheck(relpos);
150 // virtual from NodeContainer
151 // throws InvalidPositionException if not found
152 void setNode(v3s16 p, MapNode & n)
154 v3s16 blockpos = getNodeBlockPos(p);
155 MapBlock * blockref = getBlockNoCreate(blockpos);
156 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
157 blockref->setNodeNoCheck(relpos, n);
160 /*MapNode getNodeGenerate(v3s16 p)
162 v3s16 blockpos = getNodeBlockPos(p);
163 MapBlock * blockref = getBlock(blockpos);
164 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
166 return blockref->getNode(relpos);
169 /*void setNodeGenerate(v3s16 p, MapNode & n)
171 v3s16 blockpos = getNodeBlockPos(p);
172 MapBlock * blockref = getBlock(blockpos);
173 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
174 blockref->setNode(relpos, n);
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 void expireMeshes(bool only_daynight_diffed);
219 Update the faces of the given block and blocks on the
222 void updateMeshes(v3s16 blockpos, u32 daynight_ratio);
224 // Update meshes that touch the node
225 //void updateNodeMeshes(v3s16 nodepos, u32 daynight_ratio);
229 Takes the blocks at the edges into account
231 bool dayNightDiffed(v3s16 blockpos);
233 //core::aabbox3d<s16> getDisplayedBlockArea();
235 //bool updateChangedVisibleArea();
237 virtual void save(bool only_changed){assert(0);};
242 void timerUpdate(float dtime);
244 // Takes cache into account
245 // sector mutex should be locked when calling
246 void deleteSectors(core::list<v2s16> &list, bool only_blocks);
248 // Returns count of deleted sectors
249 u32 deleteUnusedSectors(float timeout, bool only_blocks=false,
250 core::list<v3s16> *deleted_blocks=NULL);
252 // For debug printing
253 virtual void PrintInfo(std::ostream &out);
255 void transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks);
263 std::ostream &m_dout;
265 core::map<v2s16, MapSector*> m_sectors;
266 JMutex m_sector_mutex;
268 v3f m_camera_position;
269 v3f m_camera_direction;
270 JMutex m_camera_mutex;
272 // Be sure to set this to NULL when the cached sector is deleted
273 MapSector *m_sector_cache;
274 v2s16 m_sector_cache_p;
276 //WrapperHeightmap m_hwrapper;
278 // Queued transforming water nodes
279 UniqueQueue<v3s16> m_transforming_liquid;
285 This is the only map class that is able to generate map.
288 class ServerMap : public Map
292 savedir: directory to which map data should be saved
294 ServerMap(std::string savedir);
299 return MAPTYPE_SERVER;
306 // Returns the position of the chunk where the sector is in
307 v2s16 sector_to_chunk(v2s16 sectorpos)
309 sectorpos.X += m_chunksize / 2;
310 sectorpos.Y += m_chunksize / 2;
311 v2s16 chunkpos = getContainerPos(sectorpos, m_chunksize);
315 // Returns the position of the (0,0) sector of the chunk
316 v2s16 chunk_to_sector(v2s16 chunkpos)
319 chunkpos.X * m_chunksize,
320 chunkpos.Y * m_chunksize
322 sectorpos.X -= m_chunksize / 2;
323 sectorpos.Y -= m_chunksize / 2;
330 MapChunk *getChunk(v2s16 chunkpos)
332 core::map<v2s16, MapChunk*>::Node *n;
333 n = m_chunks.find(chunkpos);
336 return n->getValue();
340 True if the chunk and its neighbors are fully generated.
341 It means the chunk will not be touched in the future by the
342 generator. If false, generateChunk will make it true.
344 bool chunkNonVolatile(v2s16 chunkpos)
346 /*for(s16 x=-1; x<=1; x++)
347 for(s16 y=-1; y<=1; y++)*/
351 v2s16 chunkpos0 = chunkpos + v2s16(x,y);
352 MapChunk *chunk = getChunk(chunkpos);
355 if(chunk->getGenLevel() != GENERATED_FULLY)
364 All chunks touching this one can be altered also.
366 MapChunk* generateChunkRaw(v2s16 chunkpos,
367 core::map<v3s16, MapBlock*> &changed_blocks,
371 Generate a chunk and its neighbors so that it won't be touched
374 MapChunk* generateChunk(v2s16 chunkpos,
375 core::map<v3s16, MapBlock*> &changed_blocks);
380 This is mainly called by generateChunkRaw.
382 //ServerMapSector * generateSector(v2s16 p);
385 Get a sector from somewhere.
387 - Check disk (loads blocks also)
390 ServerMapSector * createSector(v2s16 p);
393 Get a sector from somewhere.
395 - Check disk (loads blocks also)
398 MapSector * emergeSector(v2s16 p,
399 core::map<v3s16, MapBlock*> &changed_blocks);
401 MapSector * emergeSector(v2s16 p)
403 core::map<v3s16, MapBlock*> changed_blocks;
404 return emergeSector(p, changed_blocks);
407 MapBlock * generateBlock(
409 MapBlock *original_dummy,
410 ServerMapSector *sector,
411 core::map<v3s16, MapBlock*> &changed_blocks,
412 core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
416 Get a block from somewhere.
420 MapBlock * createBlock(v3s16 p);
423 only_from_disk, changed_blocks and lighting_invalidated_blocks
424 are not properly used by the new map generator.
426 MapBlock * emergeBlock(
429 core::map<v3s16, MapBlock*> &changed_blocks,
430 core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
435 Forcefully get a block from somewhere.
438 - InvalidPositionException: possible if only_from_disk==true
441 - All already existing blocks that were modified are added.
442 - If found on disk, nothing will be added.
443 - If generated, the new block will not be included.
445 lighting_invalidated_blocks:
446 - All blocks that have heavy-to-calculate lighting changes
448 - updateLighting() should be called for these.
450 - A block that is in changed_blocks may not be in
451 lighting_invalidated_blocks.
453 MapBlock * emergeBlock(
456 core::map<v3s16, MapBlock*> &changed_blocks,
457 core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
462 Misc. helper functions for fiddling with directory and file
465 void createDir(std::string path);
466 void createSaveDir();
467 // returns something like "xxxxxxxx"
468 std::string getSectorSubDir(v2s16 pos);
469 // returns something like "map/sectors/xxxxxxxx"
470 std::string getSectorDir(v2s16 pos);
471 std::string createSectorDir(v2s16 pos);
472 // dirname: final directory name
473 v2s16 getSectorPos(std::string dirname);
474 v3s16 getBlockPos(std::string sectordir, std::string blockfile);
476 void save(bool only_changed);
479 // Saves map seed and possibly other stuff
483 void saveChunkMeta();
484 void loadChunkMeta();
486 // The sector mutex should be locked when calling most of these
488 // This only saves sector-specific data such as the heightmap
490 // DEPRECATED? Sectors have no metadata anymore.
491 void saveSectorMeta(ServerMapSector *sector);
492 MapSector* loadSectorMeta(std::string dirname);
494 // Full load of a sector including all blocks.
495 // returns true on success, false on failure.
496 bool loadSectorFull(v2s16 p2d);
497 // If sector is not found in memory, try to load it from disk.
498 // Returns true if sector now resides in memory
499 //bool deFlushSector(v2s16 p2d);
501 void saveBlock(MapBlock *block);
502 // This will generate a sector with getSector if not found.
503 void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector);
505 // Gets from master heightmap
507 void getSectorCorners(v2s16 p2d, s16 *corners);
509 // For debug printing
510 virtual void PrintInfo(std::ostream &out);
512 bool isSavingEnabled(){ return m_map_saving_enabled; }
515 // Seed used for all kinds of randomness
518 std::string m_savedir;
519 bool m_map_saving_enabled;
521 // Chunk size in MapSectors
524 core::map<v2s16, MapChunk*> m_chunks;
533 struct MapDrawControl
538 wanted_max_blocks(0),
541 blocks_would_have_drawn(0)
544 // Overrides limits by drawing everything
546 // Wanted drawing range
548 // Maximum number of blocks to draw
549 u32 wanted_max_blocks;
550 // Blocks in this range are drawn regardless of number of blocks drawn
551 float wanted_min_range;
552 // Number of blocks rendered is written here by the renderer
554 // Number of blocks that would have been drawn in wanted_range
555 u32 blocks_would_have_drawn;
563 This is the only map class that is able to render itself on screen.
566 class ClientMap : public Map, public scene::ISceneNode
571 MapDrawControl &control,
572 scene::ISceneNode* parent,
573 scene::ISceneManager* mgr,
581 return MAPTYPE_CLIENT;
590 Forcefully get a sector from somewhere
592 MapSector * emergeSector(v2s16 p);
594 void deSerializeSector(v2s16 p2d, std::istream &is);
600 virtual void OnRegisterSceneNode();
602 virtual void render()
604 video::IVideoDriver* driver = SceneManager->getVideoDriver();
605 driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
606 renderMap(driver, SceneManager->getSceneNodeRenderPass());
609 virtual const core::aabbox3d<f32>& getBoundingBox() const
614 void renderMap(video::IVideoDriver* driver, s32 pass);
617 Methods for setting temporary modifications to nodes for
620 Returns true if something changed.
622 All blocks whose mesh could have been changed are inserted
625 bool setTempMod(v3s16 p, NodeMod mod,
626 core::map<v3s16, MapBlock*> *affected_blocks=NULL);
627 bool clearTempMod(v3s16 p,
628 core::map<v3s16, MapBlock*> *affected_blocks=NULL);
629 // Efficient implementation needs a cache of TempMods
630 //void clearTempMods();
632 // For debug printing
633 virtual void PrintInfo(std::ostream &out);
638 core::aabbox3d<f32> m_box;
640 // This is the master heightmap mesh
641 //scene::SMesh *mesh;
644 MapDrawControl &m_control;
649 class MapVoxelManipulator : public VoxelManipulator
652 MapVoxelManipulator(Map *map);
653 virtual ~MapVoxelManipulator();
657 VoxelManipulator::clear();
658 m_loaded_blocks.clear();
661 virtual void emerge(VoxelArea a, s32 caller_id=-1);
663 void blitBack(core::map<v3s16, MapBlock*> & modified_blocks);
669 value = block existed when loaded
671 core::map<v3s16, bool> m_loaded_blocks;
674 class ManualMapVoxelManipulator : public MapVoxelManipulator
677 ManualMapVoxelManipulator(Map *map);
678 virtual ~ManualMapVoxelManipulator();
680 virtual void emerge(VoxelArea a, s32 caller_id=-1);
682 void initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max);
684 // This is much faster with big chunks of generated data
685 void blitBackAll(core::map<v3s16, MapBlock*> * modified_blocks);