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"
38 #include "loadstatus.h"
41 #include "mapsector.h"
42 #include "constants.h"
47 A cache for short-term fast access to map data
49 NOTE: This doesn't really make anything more efficient
50 NOTE: Use VoxelManipulator, if possible
51 TODO: Get rid of this?
53 class MapBlockPointerCache : public NodeContainer
56 MapBlockPointerCache(Map *map);
57 ~MapBlockPointerCache();
59 virtual u16 nodeContainerId() const
61 return NODECONTAINER_ID_MAPBLOCKCACHE;
64 MapBlock * getBlockNoCreate(v3s16 p);
66 // virtual from NodeContainer
67 bool isValidPosition(v3s16 p)
69 v3s16 blockpos = getNodeBlockPos(p);
72 blockref = getBlockNoCreate(blockpos);
74 catch(InvalidPositionException &e)
81 // virtual from NodeContainer
82 MapNode getNode(v3s16 p)
84 v3s16 blockpos = getNodeBlockPos(p);
85 MapBlock * blockref = getBlockNoCreate(blockpos);
86 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
88 return blockref->getNodeNoCheck(relpos);
91 // virtual from NodeContainer
92 void setNode(v3s16 p, MapNode & n)
94 v3s16 blockpos = getNodeBlockPos(p);
95 MapBlock * block = getBlockNoCreate(blockpos);
96 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
97 block->setNodeNoCheck(relpos, n);
98 m_modified_blocks[blockpos] = block;
101 core::map<v3s16, MapBlock*> m_modified_blocks;
105 core::map<v3s16, MapBlock*> m_blocks;
107 u32 m_from_cache_count;
108 u32 m_from_map_count;
117 m_count_mutex.Init();
118 m_cache_mutex.Init();
119 m_waitcache_mutex.Init();
124 dstream<<"cacheCreated() begin"<<std::endl;
125 JMutexAutoLock waitcachelock(m_waitcache_mutex);
126 JMutexAutoLock countlock(m_count_mutex);
128 // If this is the first cache, grab the cache lock
130 m_cache_mutex.Lock();
134 dstream<<"cacheCreated() end"<<std::endl;
139 dstream<<"cacheRemoved() begin"<<std::endl;
140 JMutexAutoLock countlock(m_count_mutex);
146 // If this is the last one, release the cache lock
148 m_cache_mutex.Unlock();
150 dstream<<"cacheRemoved() end"<<std::endl;
154 This lock should be taken when removing stuff that can be
155 pointed by the cache.
157 You'll want to grab this in a SharedPtr.
159 JMutexAutoLock * waitCaches()
161 //dstream<<"waitCaches() begin"<<std::endl;
162 JMutexAutoLock waitcachelock(m_waitcache_mutex);
163 JMutexAutoLock *lock = new JMutexAutoLock(m_cache_mutex);
164 //dstream<<"waitCaches() end"<<std::endl;
169 // Count of existing caches
171 JMutex m_count_mutex;
172 // This is locked always when there are some caches
173 JMutex m_cache_mutex;
174 // Locked so that when waitCaches() is called, no more caches are created
175 JMutex m_waitcache_mutex;
178 #define MAPTYPE_BASE 0
179 #define MAPTYPE_SERVER 1
180 #define MAPTYPE_CLIENT 2
182 class Map : public NodeContainer, public Heightmappish
186 std::ostream &m_dout;
188 core::map<v2s16, MapSector*> m_sectors;
189 JMutex m_sector_mutex;
191 v3f m_camera_position;
192 v3f m_camera_direction;
193 JMutex m_camera_mutex;
195 // Be sure to set this to NULL when the cached sector is deleted
196 MapSector *m_sector_cache;
197 v2s16 m_sector_cache_p;
199 WrapperHeightmap m_hwrapper;
203 v3s16 drawoffset; // for drawbox()
206 Used by MapBlockPointerCache.
208 waitCaches() can be called to remove all caches before continuing
210 CacheLock m_blockcachelock;
212 Map(std::ostream &dout);
215 virtual u16 nodeContainerId() const
217 return NODECONTAINER_ID_MAP;
220 virtual s32 mapType() const
225 void updateCamera(v3f pos, v3f dir)
227 JMutexAutoLock lock(m_camera_mutex);
228 m_camera_position = pos;
229 m_camera_direction = dir;
232 /*void StartUpdater()
239 updater.setRun(false);
240 while(updater.IsRunning())
244 bool UpdaterIsRunning()
246 return updater.IsRunning();
249 static core::aabbox3d<f32> getNodeBox(v3s16 p)
251 return core::aabbox3d<f32>(
252 (float)p.X * BS - 0.5*BS,
253 (float)p.Y * BS - 0.5*BS,
254 (float)p.Z * BS - 0.5*BS,
255 (float)p.X * BS + 0.5*BS,
256 (float)p.Y * BS + 0.5*BS,
257 (float)p.Z * BS + 0.5*BS
261 //bool sectorExists(v2s16 p);
262 MapSector * getSectorNoGenerate(v2s16 p2d);
264 This is overloaded by ClientMap and ServerMap to allow
265 their differing fetch methods.
267 virtual MapSector * emergeSector(v2s16 p) = 0;
269 // Returns InvalidPositionException if not found
270 MapBlock * getBlockNoCreate(v3s16 p);
271 //virtual MapBlock * getBlock(v3s16 p, bool generate=true);
273 // Returns InvalidPositionException if not found
274 f32 getGroundHeight(v2s16 p, bool generate=false);
275 void setGroundHeight(v2s16 p, f32 y, bool generate=false);
277 // Returns InvalidPositionException if not found
278 bool isNodeUnderground(v3s16 p);
280 // virtual from NodeContainer
281 bool isValidPosition(v3s16 p)
283 v3s16 blockpos = getNodeBlockPos(p);
286 blockref = getBlockNoCreate(blockpos);
288 catch(InvalidPositionException &e)
293 /*v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
294 bool is_valid = blockref->isValidPosition(relpos);
298 // virtual from NodeContainer
299 MapNode getNode(v3s16 p)
301 v3s16 blockpos = getNodeBlockPos(p);
302 MapBlock * blockref = getBlockNoCreate(blockpos);
303 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
305 return blockref->getNodeNoCheck(relpos);
308 // virtual from NodeContainer
309 void setNode(v3s16 p, MapNode & n)
311 v3s16 blockpos = getNodeBlockPos(p);
312 MapBlock * blockref = getBlockNoCreate(blockpos);
313 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
314 blockref->setNodeNoCheck(relpos, n);
317 /*MapNode getNodeGenerate(v3s16 p)
319 v3s16 blockpos = getNodeBlockPos(p);
320 MapBlock * blockref = getBlock(blockpos);
321 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
323 return blockref->getNode(relpos);
326 /*void setNodeGenerate(v3s16 p, MapNode & n)
328 v3s16 blockpos = getNodeBlockPos(p);
329 MapBlock * blockref = getBlock(blockpos);
330 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
331 blockref->setNode(relpos, n);
334 void unspreadLight(core::map<v3s16, u8> & from_nodes,
335 core::map<v3s16, bool> & light_sources,
336 core::map<v3s16, MapBlock*> & modified_blocks);
338 void unLightNeighbors(v3s16 pos, u8 lightwas,
339 core::map<v3s16, bool> & light_sources,
340 core::map<v3s16, MapBlock*> & modified_blocks);
342 void spreadLight(core::map<v3s16, bool> & from_nodes,
343 core::map<v3s16, MapBlock*> & modified_blocks);
345 void lightNeighbors(v3s16 pos,
346 core::map<v3s16, MapBlock*> & modified_blocks);
348 v3s16 getBrightestNeighbour(v3s16 p);
350 s16 propagateSunlight(v3s16 start,
351 core::map<v3s16, MapBlock*> & modified_blocks);
353 void updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
354 core::map<v3s16, MapBlock*> & modified_blocks);
357 These handle lighting but not faces.
359 void addNodeAndUpdate(v3s16 p, MapNode n,
360 core::map<v3s16, MapBlock*> &modified_blocks);
361 void removeNodeAndUpdate(v3s16 p,
362 core::map<v3s16, MapBlock*> &modified_blocks);
365 Updates the faces of the given block and blocks on the
368 void updateMeshes(v3s16 blockpos);
370 //core::aabbox3d<s16> getDisplayedBlockArea();
372 //bool updateChangedVisibleArea();
374 virtual void save(bool only_changed){assert(0);};
379 void timerUpdate(float dtime);
381 // Takes cache into account
382 // sector mutex should be locked when calling
383 void deleteSectors(core::list<v2s16> &list, bool only_blocks);
385 // Returns count of deleted sectors
386 u32 deleteUnusedSectors(float timeout, bool only_blocks=false,
387 core::list<v3s16> *deleted_blocks=NULL);
389 // For debug printing
390 virtual void PrintInfo(std::ostream &out);
393 // Master heightmap parameters
399 randmax = "constant 70.0";
400 randfactor = "constant 0.6";
401 base = "linear 0 80 0";
405 std::string randfactor;
415 ravines_amount = 1.0;
416 //max_objects_in_block = 30;
419 float ravines_amount;
420 //u16 max_objects_in_block;
423 class ServerMap : public Map
427 savedir: directory to which map data should be saved
429 ServerMap(std::string savedir, HMParams hmp, MapParams mp);
434 return MAPTYPE_SERVER;
438 Forcefully get a sector from somewhere
440 MapSector * emergeSector(v2s16 p);
442 Forcefully get a block from somewhere.
445 - InvalidPositionException: possible if only_from_disk==true
448 - All already existing blocks that were modified are added.
449 - If found on disk, nothing will be added.
450 - If generated, the new block will not be included.
452 lighting_invalidated_blocks:
453 - All blocks that have heavy-to-calculate lighting changes
455 - updateLighting() should be called for these.
457 - A block that is in changed_blocks may not be in
458 lighting_invalidated_blocks.
460 MapBlock * emergeBlock(
463 core::map<v3s16, MapBlock*> &changed_blocks,
464 core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
467 void createDir(std::string path);
468 void createSaveDir();
469 // returns something like "xxxxxxxx"
470 std::string getSectorSubDir(v2s16 pos);
471 // returns something like "map/sectors/xxxxxxxx"
472 std::string getSectorDir(v2s16 pos);
473 std::string createSectorDir(v2s16 pos);
474 // dirname: final directory name
475 v2s16 getSectorPos(std::string dirname);
476 v3s16 getBlockPos(std::string sectordir, std::string blockfile);
478 void save(bool only_changed);
481 void saveMasterHeightmap();
482 void loadMasterHeightmap();
484 // The sector mutex should be locked when calling most of these
486 // This only saves sector-specific data such as the heightmap
488 void saveSectorMeta(ServerMapSector *sector);
489 MapSector* loadSectorMeta(std::string dirname);
491 // Full load of a sector including all blocks.
492 // returns true on success, false on failure.
493 bool loadSectorFull(v2s16 p2d);
494 // If sector is not found in memory, try to load it from disk.
495 // Returns true if sector now resides in memory
496 //bool deFlushSector(v2s16 p2d);
498 void saveBlock(MapBlock *block);
499 // This will generate a sector with getSector if not found.
500 void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector);
502 // Gets from master heightmap
503 void getSectorCorners(v2s16 p2d, s16 *corners);
505 // For debug printing
506 virtual void PrintInfo(std::ostream &out);
509 UnlimitedHeightmap *m_heightmap;
512 std::string m_savedir;
513 bool m_map_saving_enabled;
518 class ClientMap : public Map, public scene::ISceneNode
523 video::SMaterial *materials,
524 scene::ISceneNode* parent,
525 scene::ISceneManager* mgr,
533 return MAPTYPE_CLIENT;
537 Forcefully get a sector from somewhere
539 MapSector * emergeSector(v2s16 p);
541 void deSerializeSector(v2s16 p2d, std::istream &is);
547 virtual void OnRegisterSceneNode()
551 //SceneManager->registerNodeForRendering(this, scene::ESNRP_SKY_BOX);
552 SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
553 SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
556 ISceneNode::OnRegisterSceneNode();
559 virtual void render()
561 video::IVideoDriver* driver = SceneManager->getVideoDriver();
562 driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
563 renderMap(driver, m_materials, SceneManager->getSceneNodeRenderPass());
566 virtual const core::aabbox3d<f32>& getBoundingBox() const
571 void renderMap(video::IVideoDriver* driver,
572 video::SMaterial *materials, s32 pass);
574 // Update master heightmap mesh
577 // For debug printing
578 virtual void PrintInfo(std::ostream &out);
583 video::SMaterial *m_materials;
585 core::aabbox3d<f32> m_box;
587 // This is the master heightmap mesh