eb459fbcaf80421ed5682997080fdfc59fe2db32
[oweals/minetest.git] / src / map.h
1 /*
2 (c) 2010 Perttu Ahola <celeron55@gmail.com>
3 */
4
5 #ifndef MAP_HEADER
6 #define MAP_HEADER
7
8 #include <jmutex.h>
9 #include <jthread.h>
10 #include <iostream>
11 #include <malloc.h>
12
13 #ifdef _WIN32
14         #include <windows.h>
15         #define sleep_s(x) Sleep((x*1000))
16 #else
17         #include <unistd.h>
18         #define sleep_s(x) sleep(x)
19 #endif
20
21 #include "common_irrlicht.h"
22 #include "heightmap.h"
23 #include "loadstatus.h"
24 #include "mapnode.h"
25 #include "mapblock.h"
26 #include "mapsector.h"
27 #include "constants.h"
28
29 class Map;
30
31 /*
32         A cache for short-term fast access to map data
33
34         NOTE: This doesn't really make anything more efficient
35         NOTE: Use VoxelManipulator, if possible
36         TODO: Get rid of this?
37 */
38 class MapBlockPointerCache : public NodeContainer
39 {
40 public:
41         MapBlockPointerCache(Map *map);
42         ~MapBlockPointerCache();
43
44         virtual u16 nodeContainerId() const
45         {
46                 return NODECONTAINER_ID_MAPBLOCKCACHE;
47         }
48
49         MapBlock * getBlockNoCreate(v3s16 p);
50
51         // virtual from NodeContainer
52         bool isValidPosition(v3s16 p)
53         {
54                 v3s16 blockpos = getNodeBlockPos(p);
55                 MapBlock *blockref;
56                 try{
57                         blockref = getBlockNoCreate(blockpos);
58                 }
59                 catch(InvalidPositionException &e)
60                 {
61                         return false;
62                 }
63                 return true;
64         }
65         
66         // virtual from NodeContainer
67         MapNode getNode(v3s16 p)
68         {
69                 v3s16 blockpos = getNodeBlockPos(p);
70                 MapBlock * blockref = getBlockNoCreate(blockpos);
71                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
72
73                 return blockref->getNodeNoCheck(relpos);
74         }
75
76         // virtual from NodeContainer
77         void setNode(v3s16 p, MapNode & n)
78         {
79                 v3s16 blockpos = getNodeBlockPos(p);
80                 MapBlock * block = getBlockNoCreate(blockpos);
81                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
82                 block->setNodeNoCheck(relpos, n);
83                 m_modified_blocks[blockpos] = block;
84         }
85
86         core::map<v3s16, MapBlock*> m_modified_blocks;
87         
88 private:
89         Map *m_map;
90         core::map<v3s16, MapBlock*> m_blocks;
91
92         u32 m_from_cache_count;
93         u32 m_from_map_count;
94 };
95
96 class CacheLock
97 {
98 public:
99         CacheLock()
100         {
101                 m_count = 0;
102                 m_count_mutex.Init();
103                 m_cache_mutex.Init();
104                 m_waitcache_mutex.Init();
105         }
106
107         void cacheCreated()
108         {
109                 JMutexAutoLock waitcachelock(m_waitcache_mutex);
110                 JMutexAutoLock countlock(m_count_mutex);
111
112                 // If this is the first cache, grab the cache lock
113                 if(m_count == 0)
114                         m_cache_mutex.Lock();
115                         
116                 m_count++;
117         }
118
119         void cacheRemoved()
120         {
121                 JMutexAutoLock countlock(m_count_mutex);
122
123                 assert(m_count > 0);
124
125                 m_count--;
126                 
127                 // If this is the last one, release the cache lock
128                 if(m_count == 0)
129                         m_cache_mutex.Unlock();
130         }
131
132         /*
133                 This lock should be taken when removing stuff that can be
134                 pointed by the cache.
135
136                 You'll want to grab this in a SharedPtr.
137         */
138         JMutexAutoLock * waitCaches()
139         {
140                 JMutexAutoLock waitcachelock(m_waitcache_mutex);
141                 return new JMutexAutoLock(m_cache_mutex);
142         }
143
144 private:
145         // Count of existing caches
146         u32 m_count;
147         JMutex m_count_mutex;
148         // This is locked always when there are some caches
149         JMutex m_cache_mutex;
150         // Locked so that when waitCaches() is called, no more caches are created
151         JMutex m_waitcache_mutex;
152 };
153
154 #define MAPTYPE_BASE 0
155 #define MAPTYPE_SERVER 1
156 #define MAPTYPE_CLIENT 2
157
158 class Map : public NodeContainer, public Heightmappish
159 {
160 protected:
161
162         std::ostream &m_dout;
163
164         core::map<v2s16, MapSector*> m_sectors;
165         JMutex m_sector_mutex;
166
167         v3f m_camera_position;
168         v3f m_camera_direction;
169         JMutex m_camera_mutex;
170
171         // Be sure to set this to NULL when the cached sector is deleted 
172         MapSector *m_sector_cache;
173         v2s16 m_sector_cache_p;
174
175         WrapperHeightmap m_hwrapper;
176
177 public:
178
179         v3s16 drawoffset; // for drawbox()
180         
181         /*
182                 Used by MapBlockPointerCache.
183
184                 waitCaches() can be called to remove all caches before continuing
185         */
186         CacheLock m_blockcachelock;
187
188         Map(std::ostream &dout);
189         virtual ~Map();
190
191         virtual u16 nodeContainerId() const
192         {
193                 return NODECONTAINER_ID_MAP;
194         }
195
196         virtual s32 mapType() const
197         {
198                 return MAPTYPE_BASE;
199         }
200
201         void updateCamera(v3f pos, v3f dir)
202         {
203                 JMutexAutoLock lock(m_camera_mutex);
204                 m_camera_position = pos;
205                 m_camera_direction = dir;
206         }
207
208         /*void StartUpdater()
209         {
210                 updater.Start();
211         }
212
213         void StopUpdater()
214         {
215                 updater.setRun(false);
216                 while(updater.IsRunning())
217                         sleep_s(1);
218         }
219
220         bool UpdaterIsRunning()
221         {
222                 return updater.IsRunning();
223         }*/
224
225         static core::aabbox3d<f32> getNodeBox(v3s16 p)
226         {
227                 return core::aabbox3d<f32>(
228                         (float)p.X * BS - 0.5*BS,
229                         (float)p.Y * BS - 0.5*BS,
230                         (float)p.Z * BS - 0.5*BS,
231                         (float)p.X * BS + 0.5*BS,
232                         (float)p.Y * BS + 0.5*BS,
233                         (float)p.Z * BS + 0.5*BS
234                 );
235         }
236
237         //bool sectorExists(v2s16 p);
238         MapSector * getSectorNoGenerate(v2s16 p2d);
239         /*
240                 This is overloaded by ClientMap and ServerMap to allow
241                 their differing fetch methods.
242         */
243         virtual MapSector * emergeSector(v2s16 p) = 0;
244         
245         // Returns InvalidPositionException if not found
246         MapBlock * getBlockNoCreate(v3s16 p);
247         //virtual MapBlock * getBlock(v3s16 p, bool generate=true);
248         
249         // Returns InvalidPositionException if not found
250         f32 getGroundHeight(v2s16 p, bool generate=false);
251         void setGroundHeight(v2s16 p, f32 y, bool generate=false);
252
253         // Returns InvalidPositionException if not found
254         bool isNodeUnderground(v3s16 p);
255         
256         // virtual from NodeContainer
257         bool isValidPosition(v3s16 p)
258         {
259                 v3s16 blockpos = getNodeBlockPos(p);
260                 MapBlock *blockref;
261                 try{
262                         blockref = getBlockNoCreate(blockpos);
263                 }
264                 catch(InvalidPositionException &e)
265                 {
266                         return false;
267                 }
268                 return true;
269                 /*v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
270                 bool is_valid = blockref->isValidPosition(relpos);
271                 return is_valid;*/
272         }
273         
274         // virtual from NodeContainer
275         MapNode getNode(v3s16 p)
276         {
277                 v3s16 blockpos = getNodeBlockPos(p);
278                 MapBlock * blockref = getBlockNoCreate(blockpos);
279                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
280
281                 return blockref->getNodeNoCheck(relpos);
282         }
283
284         // virtual from NodeContainer
285         void setNode(v3s16 p, MapNode & n)
286         {
287                 v3s16 blockpos = getNodeBlockPos(p);
288                 MapBlock * blockref = getBlockNoCreate(blockpos);
289                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
290                 blockref->setNodeNoCheck(relpos, n);
291         }
292
293         /*MapNode getNodeGenerate(v3s16 p)
294         {
295                 v3s16 blockpos = getNodeBlockPos(p);
296                 MapBlock * blockref = getBlock(blockpos);
297                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
298
299                 return blockref->getNode(relpos);
300         }*/
301
302         /*void setNodeGenerate(v3s16 p, MapNode & n)
303         {
304                 v3s16 blockpos = getNodeBlockPos(p);
305                 MapBlock * blockref = getBlock(blockpos);
306                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
307                 blockref->setNode(relpos, n);
308         }*/
309
310         void unspreadLight(core::map<v3s16, u8> & from_nodes,
311                         core::map<v3s16, bool> & light_sources,
312                         core::map<v3s16, MapBlock*> & modified_blocks);
313
314         void unLightNeighbors(v3s16 pos, u8 lightwas,
315                         core::map<v3s16, bool> & light_sources,
316                         core::map<v3s16, MapBlock*> & modified_blocks);
317         
318         void spreadLight(core::map<v3s16, bool> & from_nodes,
319                         core::map<v3s16, MapBlock*> & modified_blocks);
320         
321         void lightNeighbors(v3s16 pos,
322                         core::map<v3s16, MapBlock*> & modified_blocks);
323
324         v3s16 getBrightestNeighbour(v3s16 p);
325
326         s16 propagateSunlight(v3s16 start,
327                         core::map<v3s16, MapBlock*> & modified_blocks);
328         
329         void updateLighting(core::map<v3s16, MapBlock*>  & a_blocks,
330                         core::map<v3s16, MapBlock*> & modified_blocks);
331                         
332         /*
333                 These handle lighting but not faces.
334         */
335         void addNodeAndUpdate(v3s16 p, MapNode n,
336                         core::map<v3s16, MapBlock*> &modified_blocks);
337         void removeNodeAndUpdate(v3s16 p,
338                         core::map<v3s16, MapBlock*> &modified_blocks);
339         
340         /*
341                 Updates the faces of the given block and blocks on the
342                 leading edge.
343         */
344         void updateMeshes(v3s16 blockpos);
345
346         //core::aabbox3d<s16> getDisplayedBlockArea();
347
348         //bool updateChangedVisibleArea();
349         
350         virtual void save(bool only_changed){assert(0);};
351
352         /*
353                 Updates usage timers
354         */
355         void timerUpdate(float dtime);
356         
357         // Takes cache into account
358         // sector mutex should be locked when calling
359         void deleteSectors(core::list<v2s16> &list, bool only_blocks);
360         
361         // Returns count of deleted sectors
362         u32 deleteUnusedSectors(float timeout, bool only_blocks=false,
363                         core::list<v3s16> *deleted_blocks=NULL);
364
365         // For debug printing
366         virtual void PrintInfo(std::ostream &out);
367 };
368
369 // Master heightmap parameters
370 struct HMParams
371 {
372         HMParams()
373         {
374                 blocksize = 64;
375                 randmax = "constant 70.0";
376                 randfactor = "constant 0.6";
377                 base = "linear 0 80 0";
378         }
379         s16 blocksize;
380         std::string randmax;
381         std::string randfactor;
382         std::string base;
383 };
384
385 // Map parameters
386 struct MapParams
387 {
388         MapParams()
389         {
390                 plants_amount = 1.0;
391                 //max_objects_in_block = 30;
392         }
393         float plants_amount;
394         //u16 max_objects_in_block;
395 };
396
397 class ServerMap : public Map
398 {
399 public:
400         /*
401                 savedir: directory to which map data should be saved
402         */
403         ServerMap(std::string savedir, HMParams hmp, MapParams mp);
404         ~ServerMap();
405
406         s32 mapType() const
407         {
408                 return MAPTYPE_SERVER;
409         }
410
411         /*
412                 Forcefully get a sector from somewhere
413         */
414         MapSector * emergeSector(v2s16 p);
415         /*
416                 Forcefully get a block from somewhere.
417
418                 Exceptions:
419                 - InvalidPositionException: possible if only_from_disk==true
420                 
421                 changed_blocks:
422                 - All already existing blocks that were modified are added.
423                         - If found on disk, nothing will be added.
424                         - If generated, the new block will not be included.
425
426                 lighting_invalidated_blocks:
427                 - All blocks that have heavy-to-calculate lighting changes
428                   are added.
429                         - updateLighting() should be called for these.
430                 
431                 - A block that is in changed_blocks may not be in
432                   lighting_invalidated_blocks.
433         */
434         MapBlock * emergeBlock(
435                         v3s16 p,
436                         bool only_from_disk,
437                         core::map<v3s16, MapBlock*> &changed_blocks,
438                         core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
439         );
440
441         void createDir(std::string path);
442         void createSaveDir();
443         // returns something like "xxxxxxxx"
444         std::string getSectorSubDir(v2s16 pos);
445         // returns something like "map/sectors/xxxxxxxx"
446         std::string getSectorDir(v2s16 pos);
447         std::string createSectorDir(v2s16 pos);
448         // dirname: final directory name
449         v2s16 getSectorPos(std::string dirname);
450         v3s16 getBlockPos(std::string sectordir, std::string blockfile);
451
452         void save(bool only_changed);
453         void loadAll();
454
455         void saveMasterHeightmap();
456         void loadMasterHeightmap();
457
458         // The sector mutex should be locked when calling most of these
459         
460         // This only saves sector-specific data such as the heightmap
461         // (no MapBlocks)
462         void saveSectorMeta(ServerMapSector *sector);
463         MapSector* loadSectorMeta(std::string dirname);
464         
465         // Full load of a sector including all blocks.
466         // returns true on success, false on failure.
467         bool loadSectorFull(v2s16 p2d);
468         // If sector is not found in memory, try to load it from disk.
469         // Returns true if sector now resides in memory
470         //bool deFlushSector(v2s16 p2d);
471         
472         void saveBlock(MapBlock *block);
473         // This will generate a sector with getSector if not found.
474         void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector);
475
476         // Gets from master heightmap
477         void getSectorCorners(v2s16 p2d, s16 *corners);
478
479         // For debug printing
480         virtual void PrintInfo(std::ostream &out);
481
482 private:
483         UnlimitedHeightmap *m_heightmap;
484         MapParams m_params;
485
486         std::string m_savedir;
487         bool m_map_saving_enabled;
488 };
489
490 class Client;
491
492 class ClientMap : public Map, public scene::ISceneNode
493 {
494 public:
495         ClientMap(
496                         Client *client,
497                         video::SMaterial *materials,
498                         scene::ISceneNode* parent,
499                         scene::ISceneManager* mgr,
500                         s32 id
501         );
502
503         ~ClientMap();
504
505         s32 mapType() const
506         {
507                 return MAPTYPE_CLIENT;
508         }
509
510         /*
511                 Forcefully get a sector from somewhere
512         */
513         MapSector * emergeSector(v2s16 p);
514
515         void deSerializeSector(v2s16 p2d, std::istream &is);
516
517         /*
518                 ISceneNode methods
519         */
520
521         virtual void OnRegisterSceneNode()
522         {
523                 if(IsVisible)
524                 {
525                         //SceneManager->registerNodeForRendering(this, scene::ESNRP_SKY_BOX);
526                         SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
527                         SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
528                 }
529
530                 ISceneNode::OnRegisterSceneNode();
531         }
532
533         virtual void render()
534         {
535                 video::IVideoDriver* driver = SceneManager->getVideoDriver();
536                 driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
537                 renderMap(driver, m_materials, SceneManager->getSceneNodeRenderPass());
538         }
539         
540         virtual const core::aabbox3d<f32>& getBoundingBox() const
541         {
542                 return m_box;
543         }
544
545         void renderMap(video::IVideoDriver* driver,
546                 video::SMaterial *materials, s32 pass);
547
548         // Update master heightmap mesh
549         void updateMesh();
550
551         // For debug printing
552         virtual void PrintInfo(std::ostream &out);
553         
554 private:
555         Client *m_client;
556         
557         video::SMaterial *m_materials;
558
559         core::aabbox3d<f32> m_box;
560         
561         // This is the master heightmap mesh
562         scene::SMesh *mesh;
563         JMutex mesh_mutex;
564 };
565
566 #endif
567