]> git.lizzy.rs Git - minetest.git/blob - src/map.h
2a3fa5061b30744da0ee7b6db5521112b2bae981
[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         // Returns NULL if not found
278         MapBlock * getBlockNoCreateNoEx(v3s16 p);
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 #ifndef SERVER
380         void expireMeshes(bool only_daynight_diffed);
381         
382         /*
383                 Updates the faces of the given block and blocks on the
384                 leading edge.
385         */
386         void updateMeshes(v3s16 blockpos, u32 daynight_ratio);
387 #endif
388
389         /*
390                 Takes the blocks at the edges into account
391         */
392         bool dayNightDiffed(v3s16 blockpos);
393
394         //core::aabbox3d<s16> getDisplayedBlockArea();
395
396         //bool updateChangedVisibleArea();
397         
398         virtual void save(bool only_changed){assert(0);};
399
400         /*
401                 Updates usage timers
402         */
403         void timerUpdate(float dtime);
404         
405         // Takes cache into account
406         // sector mutex should be locked when calling
407         void deleteSectors(core::list<v2s16> &list, bool only_blocks);
408         
409         // Returns count of deleted sectors
410         u32 deleteUnusedSectors(float timeout, bool only_blocks=false,
411                         core::list<v3s16> *deleted_blocks=NULL);
412
413         // For debug printing
414         virtual void PrintInfo(std::ostream &out);
415 };
416
417 // Master heightmap parameters
418 struct HMParams
419 {
420         HMParams()
421         {
422                 blocksize = 64;
423                 randmax = "constant 70.0";
424                 randfactor = "constant 0.6";
425                 base = "linear 0 80 0";
426         }
427         s16 blocksize;
428         std::string randmax;
429         std::string randfactor;
430         std::string base;
431 };
432
433 // Map parameters
434 struct MapParams
435 {
436         MapParams()
437         {
438                 plants_amount = 1.0;
439                 ravines_amount = 1.0;
440                 //max_objects_in_block = 30;
441         }
442         float plants_amount;
443         float ravines_amount;
444         //u16 max_objects_in_block;
445 };
446
447 class ServerMap : public Map
448 {
449 public:
450         /*
451                 savedir: directory to which map data should be saved
452         */
453         ServerMap(std::string savedir, HMParams hmp, MapParams mp);
454         ~ServerMap();
455
456         s32 mapType() const
457         {
458                 return MAPTYPE_SERVER;
459         }
460
461         /*
462                 Forcefully get a sector from somewhere
463         */
464         MapSector * emergeSector(v2s16 p);
465         /*
466                 Forcefully get a block from somewhere.
467
468                 Exceptions:
469                 - InvalidPositionException: possible if only_from_disk==true
470                 
471                 changed_blocks:
472                 - All already existing blocks that were modified are added.
473                         - If found on disk, nothing will be added.
474                         - If generated, the new block will not be included.
475
476                 lighting_invalidated_blocks:
477                 - All blocks that have heavy-to-calculate lighting changes
478                   are added.
479                         - updateLighting() should be called for these.
480                 
481                 - A block that is in changed_blocks may not be in
482                   lighting_invalidated_blocks.
483         */
484         MapBlock * emergeBlock(
485                         v3s16 p,
486                         bool only_from_disk,
487                         core::map<v3s16, MapBlock*> &changed_blocks,
488                         core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
489         );
490
491         void createDir(std::string path);
492         void createSaveDir();
493         // returns something like "xxxxxxxx"
494         std::string getSectorSubDir(v2s16 pos);
495         // returns something like "map/sectors/xxxxxxxx"
496         std::string getSectorDir(v2s16 pos);
497         std::string createSectorDir(v2s16 pos);
498         // dirname: final directory name
499         v2s16 getSectorPos(std::string dirname);
500         v3s16 getBlockPos(std::string sectordir, std::string blockfile);
501
502         void save(bool only_changed);
503         void loadAll();
504
505         void saveMasterHeightmap();
506         void loadMasterHeightmap();
507
508         // The sector mutex should be locked when calling most of these
509         
510         // This only saves sector-specific data such as the heightmap
511         // (no MapBlocks)
512         void saveSectorMeta(ServerMapSector *sector);
513         MapSector* loadSectorMeta(std::string dirname);
514         
515         // Full load of a sector including all blocks.
516         // returns true on success, false on failure.
517         bool loadSectorFull(v2s16 p2d);
518         // If sector is not found in memory, try to load it from disk.
519         // Returns true if sector now resides in memory
520         //bool deFlushSector(v2s16 p2d);
521         
522         void saveBlock(MapBlock *block);
523         // This will generate a sector with getSector if not found.
524         void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector);
525
526         // Gets from master heightmap
527         void getSectorCorners(v2s16 p2d, s16 *corners);
528
529         // For debug printing
530         virtual void PrintInfo(std::ostream &out);
531
532 private:
533         UnlimitedHeightmap *m_heightmap;
534         MapParams m_params;
535
536         std::string m_savedir;
537         bool m_map_saving_enabled;
538 };
539
540 #ifndef SERVER
541
542 class Client;
543
544 class ClientMap : public Map, public scene::ISceneNode
545 {
546 public:
547         ClientMap(
548                         Client *client,
549                         JMutex &range_mutex,
550                         s16 &viewing_range_nodes,
551                         bool &viewing_range_all,
552                         scene::ISceneNode* parent,
553                         scene::ISceneManager* mgr,
554                         s32 id
555         );
556
557         ~ClientMap();
558
559         s32 mapType() const
560         {
561                 return MAPTYPE_CLIENT;
562         }
563
564         void drop()
565         {
566                 ISceneNode::drop();
567         }
568
569         /*
570                 Forcefully get a sector from somewhere
571         */
572         MapSector * emergeSector(v2s16 p);
573
574         void deSerializeSector(v2s16 p2d, std::istream &is);
575
576         /*
577                 ISceneNode methods
578         */
579
580         virtual void OnRegisterSceneNode();
581
582         virtual void render()
583         {
584                 video::IVideoDriver* driver = SceneManager->getVideoDriver();
585                 driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
586                 renderMap(driver, SceneManager->getSceneNodeRenderPass());
587         }
588         
589         virtual const core::aabbox3d<f32>& getBoundingBox() const
590         {
591                 return m_box;
592         }
593
594         void renderMap(video::IVideoDriver* driver, s32 pass);
595
596         /*
597                 Methods for setting temporary modifications to nodes for
598                 drawing.
599                 Return value is position of changed block.
600         */
601         v3s16 setTempMod(v3s16 p, NodeMod mod);
602         v3s16 clearTempMod(v3s16 p);
603         // Efficient implementation needs a cache of TempMods
604         //void clearTempMods();
605
606         // For debug printing
607         virtual void PrintInfo(std::ostream &out);
608         
609 private:
610         Client *m_client;
611         
612         core::aabbox3d<f32> m_box;
613         
614         // This is the master heightmap mesh
615         scene::SMesh *mesh;
616         JMutex mesh_mutex;
617
618         JMutex &m_range_mutex;
619         s16 &m_viewing_range_nodes;
620         bool &m_viewing_range_all;
621 };
622
623 #endif
624
625 class MapVoxelManipulator : public VoxelManipulator
626 {
627 public:
628         MapVoxelManipulator(Map *map);
629         virtual ~MapVoxelManipulator();
630         
631         virtual void clear()
632         {
633                 VoxelManipulator::clear();
634                 m_loaded_blocks.clear();
635         }
636
637         virtual void emerge(VoxelArea a, s32 caller_id=-1);
638
639         void blitBack(core::map<v3s16, MapBlock*> & modified_blocks);
640
641 private:
642         Map *m_map;
643         /*
644                 NOTE: This might be used or not
645                 bool is dummy value
646                 SUGG: How 'bout an another VoxelManipulator for storing the
647                       information about which block is loaded?
648         */
649         core::map<v3s16, bool> m_loaded_blocks;
650 };
651
652 #endif
653