]> git.lizzy.rs Git - dragonfireclient.git/blob - src/map.h
fixed face updating slowness bug
[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                 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                 ravines_amount = 1.0;
392                 //max_objects_in_block = 30;
393         }
394         float plants_amount;
395         float ravines_amount;
396         //u16 max_objects_in_block;
397 };
398
399 class ServerMap : public Map
400 {
401 public:
402         /*
403                 savedir: directory to which map data should be saved
404         */
405         ServerMap(std::string savedir, HMParams hmp, MapParams mp);
406         ~ServerMap();
407
408         s32 mapType() const
409         {
410                 return MAPTYPE_SERVER;
411         }
412
413         /*
414                 Forcefully get a sector from somewhere
415         */
416         MapSector * emergeSector(v2s16 p);
417         /*
418                 Forcefully get a block from somewhere.
419
420                 Exceptions:
421                 - InvalidPositionException: possible if only_from_disk==true
422                 
423                 changed_blocks:
424                 - All already existing blocks that were modified are added.
425                         - If found on disk, nothing will be added.
426                         - If generated, the new block will not be included.
427
428                 lighting_invalidated_blocks:
429                 - All blocks that have heavy-to-calculate lighting changes
430                   are added.
431                         - updateLighting() should be called for these.
432                 
433                 - A block that is in changed_blocks may not be in
434                   lighting_invalidated_blocks.
435         */
436         MapBlock * emergeBlock(
437                         v3s16 p,
438                         bool only_from_disk,
439                         core::map<v3s16, MapBlock*> &changed_blocks,
440                         core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
441         );
442
443         void createDir(std::string path);
444         void createSaveDir();
445         // returns something like "xxxxxxxx"
446         std::string getSectorSubDir(v2s16 pos);
447         // returns something like "map/sectors/xxxxxxxx"
448         std::string getSectorDir(v2s16 pos);
449         std::string createSectorDir(v2s16 pos);
450         // dirname: final directory name
451         v2s16 getSectorPos(std::string dirname);
452         v3s16 getBlockPos(std::string sectordir, std::string blockfile);
453
454         void save(bool only_changed);
455         void loadAll();
456
457         void saveMasterHeightmap();
458         void loadMasterHeightmap();
459
460         // The sector mutex should be locked when calling most of these
461         
462         // This only saves sector-specific data such as the heightmap
463         // (no MapBlocks)
464         void saveSectorMeta(ServerMapSector *sector);
465         MapSector* loadSectorMeta(std::string dirname);
466         
467         // Full load of a sector including all blocks.
468         // returns true on success, false on failure.
469         bool loadSectorFull(v2s16 p2d);
470         // If sector is not found in memory, try to load it from disk.
471         // Returns true if sector now resides in memory
472         //bool deFlushSector(v2s16 p2d);
473         
474         void saveBlock(MapBlock *block);
475         // This will generate a sector with getSector if not found.
476         void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector);
477
478         // Gets from master heightmap
479         void getSectorCorners(v2s16 p2d, s16 *corners);
480
481         // For debug printing
482         virtual void PrintInfo(std::ostream &out);
483
484 private:
485         UnlimitedHeightmap *m_heightmap;
486         MapParams m_params;
487
488         std::string m_savedir;
489         bool m_map_saving_enabled;
490 };
491
492 class Client;
493
494 class ClientMap : public Map, public scene::ISceneNode
495 {
496 public:
497         ClientMap(
498                         Client *client,
499                         video::SMaterial *materials,
500                         scene::ISceneNode* parent,
501                         scene::ISceneManager* mgr,
502                         s32 id
503         );
504
505         ~ClientMap();
506
507         s32 mapType() const
508         {
509                 return MAPTYPE_CLIENT;
510         }
511
512         /*
513                 Forcefully get a sector from somewhere
514         */
515         MapSector * emergeSector(v2s16 p);
516
517         void deSerializeSector(v2s16 p2d, std::istream &is);
518
519         /*
520                 ISceneNode methods
521         */
522
523         virtual void OnRegisterSceneNode()
524         {
525                 if(IsVisible)
526                 {
527                         //SceneManager->registerNodeForRendering(this, scene::ESNRP_SKY_BOX);
528                         SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
529                         SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
530                 }
531
532                 ISceneNode::OnRegisterSceneNode();
533         }
534
535         virtual void render()
536         {
537                 video::IVideoDriver* driver = SceneManager->getVideoDriver();
538                 driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
539                 renderMap(driver, m_materials, SceneManager->getSceneNodeRenderPass());
540         }
541         
542         virtual const core::aabbox3d<f32>& getBoundingBox() const
543         {
544                 return m_box;
545         }
546
547         void renderMap(video::IVideoDriver* driver,
548                 video::SMaterial *materials, s32 pass);
549
550         // Update master heightmap mesh
551         void updateMesh();
552
553         // For debug printing
554         virtual void PrintInfo(std::ostream &out);
555         
556 private:
557         Client *m_client;
558         
559         video::SMaterial *m_materials;
560
561         core::aabbox3d<f32> m_box;
562         
563         // This is the master heightmap mesh
564         scene::SMesh *mesh;
565         JMutex mesh_mutex;
566 };
567
568 #endif
569