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