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