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