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