]> git.lizzy.rs Git - dragonfireclient.git/blob - src/map.h
482ab2ac79ef03e547af42d067e29125925d6bc9
[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 InvalidFilenameException : public BaseException
30 {
31 public:
32         InvalidFilenameException(const char *s):
33                 BaseException(s)
34         {}
35 };
36
37 #define MAPTYPE_BASE 0
38 #define MAPTYPE_SERVER 1
39 #define MAPTYPE_CLIENT 2
40
41 class Map : public NodeContainer, public Heightmappish
42 {
43 protected:
44
45         std::ostream &m_dout;
46
47         core::map<v2s16, MapSector*> m_sectors;
48         JMutex m_sector_mutex;
49
50         v3f m_camera_position;
51         v3f m_camera_direction;
52         JMutex m_camera_mutex;
53
54         // Be sure to set this to NULL when the cached sector is deleted 
55         MapSector *m_sector_cache;
56         v2s16 m_sector_cache_p;
57
58         WrapperHeightmap m_hwrapper;
59
60 public:
61
62         v3s16 drawoffset; // for drawbox()
63
64         Map(std::ostream &dout);
65         virtual ~Map();
66
67         virtual u16 nodeContainerId() const
68         {
69                 return NODECONTAINER_ID_MAP;
70         }
71
72         virtual s32 mapType() const
73         {
74                 return MAPTYPE_BASE;
75         }
76
77         void updateCamera(v3f pos, v3f dir)
78         {
79                 JMutexAutoLock lock(m_camera_mutex);
80                 m_camera_position = pos;
81                 m_camera_direction = dir;
82         }
83
84         /*void StartUpdater()
85         {
86                 updater.Start();
87         }
88
89         void StopUpdater()
90         {
91                 updater.setRun(false);
92                 while(updater.IsRunning())
93                         sleep_s(1);
94         }
95
96         bool UpdaterIsRunning()
97         {
98                 return updater.IsRunning();
99         }*/
100
101         static core::aabbox3d<f32> getNodeBox(v3s16 p)
102         {
103                 return core::aabbox3d<f32>(
104                         (float)p.X * BS - 0.5*BS,
105                         (float)p.Y * BS - 0.5*BS,
106                         (float)p.Z * BS - 0.5*BS,
107                         (float)p.X * BS + 0.5*BS,
108                         (float)p.Y * BS + 0.5*BS,
109                         (float)p.Z * BS + 0.5*BS
110                 );
111         }
112
113         //bool sectorExists(v2s16 p);
114         MapSector * getSectorNoGenerate(v2s16 p2d);
115         /*
116                 This is overloaded by ClientMap and ServerMap to allow
117                 their differing fetch methods.
118         */
119         virtual MapSector * emergeSector(v2s16 p) = 0;
120         
121         // Returns InvalidPositionException if not found
122         MapBlock * getBlockNoCreate(v3s16 p);
123         //virtual MapBlock * getBlock(v3s16 p, bool generate=true);
124         
125         // Returns InvalidPositionException if not found
126         f32 getGroundHeight(v2s16 p, bool generate=false);
127         void setGroundHeight(v2s16 p, f32 y, bool generate=false);
128
129         // Returns InvalidPositionException if not found
130         bool isNodeUnderground(v3s16 p);
131         
132         // virtual from NodeContainer
133         bool isValidPosition(v3s16 p)
134         {
135                 v3s16 blockpos = getNodeBlockPos(p);
136                 MapBlock *blockref;
137                 try{
138                         blockref = getBlockNoCreate(blockpos);
139                 }
140                 catch(InvalidPositionException &e)
141                 {
142                         return false;
143                 }
144                 return true;
145                 /*v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
146                 bool is_valid = blockref->isValidPosition(relpos);
147                 return is_valid;*/
148         }
149         
150         // virtual from NodeContainer
151         MapNode getNode(v3s16 p)
152         {
153                 v3s16 blockpos = getNodeBlockPos(p);
154                 MapBlock * blockref = getBlockNoCreate(blockpos);
155                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
156
157                 return blockref->getNode(relpos);
158         }
159
160         // virtual from NodeContainer
161         void setNode(v3s16 p, MapNode & n)
162         {
163                 v3s16 blockpos = getNodeBlockPos(p);
164                 MapBlock * blockref = getBlockNoCreate(blockpos);
165                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
166                 blockref->setNode(relpos, n);
167         }
168
169         /*MapNode getNodeGenerate(v3s16 p)
170         {
171                 v3s16 blockpos = getNodeBlockPos(p);
172                 MapBlock * blockref = getBlock(blockpos);
173                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
174
175                 return blockref->getNode(relpos);
176         }*/
177
178         /*void setNodeGenerate(v3s16 p, MapNode & n)
179         {
180                 v3s16 blockpos = getNodeBlockPos(p);
181                 MapBlock * blockref = getBlock(blockpos);
182                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
183                 blockref->setNode(relpos, n);
184         }*/
185
186         void unspreadLight(core::map<v3s16, u8> & from_nodes,
187                         core::map<v3s16, bool> & light_sources,
188                         core::map<v3s16, MapBlock*> & modified_blocks);
189
190         void unLightNeighbors(v3s16 pos, u8 lightwas,
191                         core::map<v3s16, bool> & light_sources,
192                         core::map<v3s16, MapBlock*> & modified_blocks);
193         
194         void spreadLight(core::map<v3s16, bool> & from_nodes,
195                         core::map<v3s16, MapBlock*> & modified_blocks);
196         
197         void lightNeighbors(v3s16 pos,
198                         core::map<v3s16, MapBlock*> & modified_blocks);
199
200         v3s16 getBrightestNeighbour(v3s16 p);
201
202         s16 propagateSunlight(v3s16 start,
203                         core::map<v3s16, MapBlock*> & modified_blocks);
204         
205         void updateLighting(core::map<v3s16, MapBlock*>  & a_blocks,
206                         core::map<v3s16, MapBlock*> & modified_blocks);
207                         
208         /*
209                 These handle lighting but not faces.
210         */
211         void addNodeAndUpdate(v3s16 p, MapNode n,
212                         core::map<v3s16, MapBlock*> &modified_blocks);
213         void removeNodeAndUpdate(v3s16 p,
214                         core::map<v3s16, MapBlock*> &modified_blocks);
215         
216         /*
217                 Updates the faces of the given block and blocks on the
218                 leading edge.
219         */
220         void updateMeshes(v3s16 blockpos);
221
222         //core::aabbox3d<s16> getDisplayedBlockArea();
223
224         //bool updateChangedVisibleArea();
225         
226         virtual void save(bool only_changed){assert(0);};
227
228         /*
229                 Updates usage timers
230         */
231         void timerUpdate(float dtime);
232         
233         // Takes cache into account
234         // sector mutex should be locked when calling
235         void deleteSectors(core::list<v2s16> &list, bool only_blocks);
236         
237         // Returns count of deleted sectors
238         u32 deleteUnusedSectors(float timeout, bool only_blocks=false,
239                         core::list<v3s16> *deleted_blocks=NULL);
240
241         // For debug printing
242         virtual void PrintInfo(std::ostream &out);
243 };
244
245 // Master heightmap parameters
246 struct HMParams
247 {
248         HMParams()
249         {
250                 heightmap_blocksize = 64;
251                 height_randmax = "constant 70.0";
252                 height_randfactor = "constant 0.6";
253                 height_base = "linear 0 80 0";
254         }
255         s16 heightmap_blocksize;
256         std::string height_randmax;
257         std::string height_randfactor;
258         std::string height_base;
259 };
260
261 // Map parameters
262 struct MapParams
263 {
264         MapParams()
265         {
266                 plants_amount = 1.0;
267                 //max_objects_in_block = 30;
268         }
269         float plants_amount;
270         //u16 max_objects_in_block;
271 };
272
273 class ServerMap : public Map
274 {
275 public:
276         /*
277                 savedir: directory to which map data should be saved
278         */
279         ServerMap(std::string savedir, HMParams hmp, MapParams mp);
280         ~ServerMap();
281
282         s32 mapType() const
283         {
284                 return MAPTYPE_SERVER;
285         }
286
287         /*
288                 Forcefully get a sector from somewhere
289         */
290         MapSector * emergeSector(v2s16 p);
291         /*
292                 Forcefully get a block from somewhere.
293
294                 Exceptions:
295                 - InvalidPositionException: possible if only_from_disk==true
296                 
297                 changed_blocks:
298                 - All already existing blocks that were modified are added.
299                         - If found on disk, nothing will be added.
300                         - If generated, the new block will not be included.
301
302                 lighting_invalidated_blocks:
303                 - All blocks that have heavy-to-calculate lighting changes
304                   are added.
305                         - updateLighting() should be called for these.
306                 
307                 - A block that is in changed_blocks may not be in
308                   lighting_invalidated_blocks.
309         */
310         MapBlock * emergeBlock(
311                         v3s16 p,
312                         bool only_from_disk,
313                         core::map<v3s16, MapBlock*> &changed_blocks,
314                         core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
315         );
316
317         void createDir(std::string path);
318         void createSaveDir();
319         // returns something like "xxxxxxxx"
320         std::string getSectorSubDir(v2s16 pos);
321         // returns something like "map/sectors/xxxxxxxx"
322         std::string getSectorDir(v2s16 pos);
323         std::string createSectorDir(v2s16 pos);
324         // dirname: final directory name
325         v2s16 getSectorPos(std::string dirname);
326         v3s16 getBlockPos(std::string sectordir, std::string blockfile);
327
328         void save(bool only_changed);
329         void loadAll();
330
331         void saveMasterHeightmap();
332         void loadMasterHeightmap();
333
334         // The sector mutex should be locked when calling most of these
335         
336         // This only saves sector-specific data such as the heightmap
337         // (no MapBlocks)
338         void saveSectorMeta(ServerMapSector *sector);
339         MapSector* loadSectorMeta(std::string dirname);
340         
341         // Full load of a sector including all blocks.
342         // returns true on success, false on failure.
343         bool loadSectorFull(v2s16 p2d);
344         // If sector is not found in memory, try to load it from disk.
345         // Returns true if sector now resides in memory
346         //bool deFlushSector(v2s16 p2d);
347         
348         void saveBlock(MapBlock *block);
349         // This will generate a sector with getSector if not found.
350         void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector);
351
352         // Gets from master heightmap
353         void getSectorCorners(v2s16 p2d, s16 *corners);
354
355         // For debug printing
356         virtual void PrintInfo(std::ostream &out);
357
358 private:
359         UnlimitedHeightmap *m_heightmap;
360         MapParams m_params;
361
362         std::string m_savedir;
363         bool m_map_saving_enabled;
364 };
365
366 class Client;
367
368 class ClientMap : public Map, public scene::ISceneNode
369 {
370 public:
371         ClientMap(
372                         Client *client,
373                         video::SMaterial *materials,
374                         scene::ISceneNode* parent,
375                         scene::ISceneManager* mgr,
376                         s32 id
377         );
378
379         ~ClientMap();
380
381         s32 mapType() const
382         {
383                 return MAPTYPE_CLIENT;
384         }
385
386         /*
387                 Forcefully get a sector from somewhere
388         */
389         MapSector * emergeSector(v2s16 p);
390
391         void deSerializeSector(v2s16 p2d, std::istream &is);
392
393         /*
394                 ISceneNode methods
395         */
396
397         virtual void OnRegisterSceneNode()
398         {
399                 if(IsVisible)
400                 {
401                         //SceneManager->registerNodeForRendering(this, scene::ESNRP_SKY_BOX);
402                         SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
403                         SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
404                 }
405
406                 ISceneNode::OnRegisterSceneNode();
407         }
408
409         virtual void render()
410         {
411                 video::IVideoDriver* driver = SceneManager->getVideoDriver();
412                 driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
413                 renderMap(driver, m_materials, SceneManager->getSceneNodeRenderPass());
414         }
415         
416         virtual const core::aabbox3d<f32>& getBoundingBox() const
417         {
418                 return m_box;
419         }
420
421         void renderMap(video::IVideoDriver* driver,
422                 video::SMaterial *materials, s32 pass);
423
424         // Update master heightmap mesh
425         void updateMesh();
426
427         // For debug printing
428         virtual void PrintInfo(std::ostream &out);
429         
430 private:
431         Client *m_client;
432         
433         video::SMaterial *m_materials;
434
435         core::aabbox3d<f32> m_box;
436         
437         // This is the master heightmap mesh
438         scene::SMesh *mesh;
439         JMutex mesh_mutex;
440 };
441
442 #endif
443