]> git.lizzy.rs Git - minetest.git/blob - src/mapsector.h
Initial files
[minetest.git] / src / mapsector.h
1 /*
2 (c) 2010 Perttu Ahola <celeron55@gmail.com>
3 */
4
5 #ifndef MAPSECTOR_HEADER
6 #define MAPSECTOR_HEADER
7
8 #include <jmutex.h>
9 #include "common_irrlicht.h"
10 #include "mapblock.h"
11 #include "heightmap.h"
12 #include "exceptions.h"
13
14 /*
15         This is an Y-wise stack of MapBlocks.
16 */
17
18 #define WATER_LEVEL (-5)
19
20 #define SECTOR_OBJECT_TEST 0
21 #define SECTOR_OBJECT_TREE_1 1
22 #define SECTOR_OBJECT_BUSH_1 2
23
24 #define MAPSECTOR_FIXEDHEIGHTMAPS_MAXCOUNT 4
25
26 #define MAPSECTOR_SERVER 0
27 #define MAPSECTOR_CLIENT 1
28
29 class MapSector: public NodeContainer, public Heightmappish
30 {
31 public:
32         
33         MapSector(NodeContainer *parent, v2s16 pos);
34         virtual ~MapSector();
35
36         virtual u16 nodeContainerId() const
37         {
38                 return NODECONTAINER_ID_MAPSECTOR;
39         }
40
41         virtual u32 getId() const = 0;
42
43         void deleteBlocks();
44
45         v2s16 getPos()
46         {
47                 return m_pos;
48         }
49
50         MapBlock * getBlockNoCreate(s16 y);
51         MapBlock * createBlankBlockNoInsert(s16 y);
52         MapBlock * createBlankBlock(s16 y);
53         //MapBlock * getBlock(s16 y, bool generate=true);
54
55         void insertBlock(MapBlock *block);
56         
57         // This is used to remove a dummy from the sector while generating it.
58         // Block is only removed from internal container, not deleted.
59         void removeBlock(MapBlock *block);
60         
61         /*
62                 This might not be a thread-safe depending on the day.
63                 See the implementation.
64         */
65         void getBlocks(core::list<MapBlock*> &dest);
66         
67         /*
68                 If all nodes in area can be accessed, returns true and
69                 adds all blocks in area to blocks.
70
71                 If all nodes in area cannot be accessed, returns false.
72
73                 The implementation of this is quite slow
74
75                 if blocks==NULL; it is not accessed at all.
76         */
77         bool isValidArea(v3s16 p_min_nodes, v3s16 p_max_nodes,
78                         core::map<s16, MapBlock*> *blocks)
79         {
80                 core::map<s16, MapBlock*> bs;
81                 
82                 v3s16 p_min = getNodeBlockPos(p_min_nodes);
83                 v3s16 p_max = getNodeBlockPos(p_max_nodes);
84                 if(p_min.X != 0 || p_min.Z != 0
85                                 || p_max.X != 0 || p_max.Z != 0)
86                         return false;
87                 v3s16 y;
88                 for(s16 y=p_min.Y; y<=p_max.Y; y++)
89                 {
90                         try{
91                                 MapBlock *block = getBlockNoCreate(y);
92                                 if(block->isDummy())
93                                         return false;
94                                 if(blocks!=NULL)
95                                         bs[y] = block;
96                         }
97                         catch(InvalidPositionException &e)
98                         {
99                                 return false;
100                         }
101                 }
102
103                 if(blocks!=NULL)
104                 {
105                         for(core::map<s16, MapBlock*>::Iterator i=bs.getIterator();
106                                         i.atEnd()==false; i++)
107                         {
108                                 MapBlock *block = i.getNode()->getValue();
109                                 s16 y = i.getNode()->getKey();
110                                 blocks->insert(y, block);
111                         }
112                 }
113                 return true;
114         }
115
116         void getBlocksInArea(v3s16 p_min_nodes, v3s16 p_max_nodes,
117                         core::map<v3s16, MapBlock*> &blocks)
118         {
119                 v3s16 p_min = getNodeBlockPos(p_min_nodes);
120                 v3s16 p_max = getNodeBlockPos(p_max_nodes);
121                 v3s16 y;
122                 for(s16 y=p_min.Y; y<=p_max.Y; y++)
123                 {
124                         try{
125                                 MapBlock *block = getBlockNoCreate(y);
126                                 blocks.insert(block->getPos(), block);
127                         }
128                         catch(InvalidPositionException &e)
129                         {
130                         }
131                 }
132         }
133         
134         // virtual from NodeContainer
135         bool isValidPosition(v3s16 p)
136         {
137                 v3s16 blockpos = getNodeBlockPos(p);
138
139                 if(blockpos.X != 0 || blockpos.Z != 0)
140                         return false;
141
142                 MapBlock *blockref;
143                 try{
144                         blockref = getBlockNoCreate(blockpos.Y);
145                 }
146                 catch(InvalidPositionException &e)
147                 {
148                         return false;
149                 }
150
151                 return true;
152         }
153
154         // virtual from NodeContainer
155         MapNode getNode(v3s16 p)
156         {
157                 v3s16 blockpos = getNodeBlockPos(p);
158                 if(blockpos.X != 0 || blockpos.Z != 0)
159                         throw InvalidPositionException
160                                 ("MapSector only allows Y");
161
162                 MapBlock * blockref = getBlockNoCreate(blockpos.Y);
163                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
164
165                 return blockref->getNode(relpos);
166         }
167         // virtual from NodeContainer
168         void setNode(v3s16 p, MapNode & n)
169         {
170                 v3s16 blockpos = getNodeBlockPos(p);
171                 if(blockpos.X != 0 || blockpos.Z != 0)
172                         throw InvalidPositionException
173                                 ("MapSector only allows Y");
174
175                 MapBlock * blockref = getBlockNoCreate(blockpos.Y);
176                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
177                 blockref->setNode(relpos, n);
178         }
179
180         virtual f32 getGroundHeight(v2s16 p, bool generate=false)
181         {
182                 return GROUNDHEIGHT_NOTFOUND_SETVALUE;
183         }
184         virtual void setGroundHeight(v2s16 p, f32 y, bool generate=false)
185         {
186         }
187         
188         // When true, sector metadata is changed from the one on disk
189         // (sector metadata = all but blocks)
190         // Basically, this should be changed to true in every setter method
191         bool differs_from_disk;
192
193         // Counts seconds from last usage.
194         // Sector can be deleted from memory after some time of inactivity.
195         // NOTE: It has to be made very sure no other thread is accessing
196         //       the sector and it doesn't remain in any cache when
197         //       deleting it.
198         float usage_timer;
199
200 protected:
201         
202         // The pile of MapBlocks
203         core::map<s16, MapBlock*> m_blocks;
204         //JMutex m_blocks_mutex; // For public access functions
205
206         NodeContainer *m_parent;
207         // Position on parent (in MapBlock widths)
208         v2s16 m_pos;
209
210         // Be sure to set this to NULL when the cached block is deleted 
211         MapBlock *m_block_cache;
212         s16 m_block_cache_y;
213         
214         // This is used for protecting m_blocks
215         JMutex m_mutex;
216         
217         /*
218                 Private methods
219         */
220         MapBlock *getBlockBuffered(s16 y);
221
222 };
223
224 class ServerMapSector : public MapSector
225 {
226 public:
227         ServerMapSector(NodeContainer *parent, v2s16 pos, u16 hm_split);
228         ~ServerMapSector();
229         
230         u32 getId() const
231         {
232                 return MAPSECTOR_SERVER;
233         }
234
235         void setHeightmap(v2s16 hm_p, FixedHeightmap *hm);
236         FixedHeightmap * getHeightmap(v2s16 hm_p);
237         
238         void printHeightmaps()
239         {
240                 for(s16 y=0; y<m_hm_split; y++)
241                 for(s16 x=0; x<m_hm_split; x++)
242                 {
243                         std::cout<<"Sector "
244                                         <<"("<<m_pos.X<<","<<m_pos.Y<<")"
245                                         " heightmap "
246                                         "("<<x<<","<<y<<"):"
247                                         <<std::endl;
248                         FixedHeightmap *hm = getHeightmap(v2s16(x,y));
249                         hm->print();
250                 }
251         }
252         
253         void setObjects(core::map<v3s16, u8> *objects)
254         {
255                 m_objects = objects;
256                 differs_from_disk = true;
257         }
258
259         core::map<v3s16, u8> * getObjects()
260         {
261                 differs_from_disk = true;
262                 return m_objects;
263         }
264
265         f32 getGroundHeight(v2s16 p, bool generate=false);
266         void setGroundHeight(v2s16 p, f32 y, bool generate=false);
267
268         /*
269                 These functions handle metadata.
270                 They do not handle blocks.
271         */
272         void serialize(std::ostream &os, u8 version);
273         
274         static ServerMapSector* deSerialize(
275                         std::istream &is,
276                         NodeContainer *parent,
277                         v2s16 p2d,
278                         Heightmap *master_hm,
279                         core::map<v2s16, MapSector*> & sectors
280                 );
281                 
282 private:
283         // Heightmap(s) for the sector
284         FixedHeightmap *m_heightmaps[MAPSECTOR_FIXEDHEIGHTMAPS_MAXCOUNT];
285         // Sector is split in m_hm_split^2 heightmaps.
286         // Value of 0 means there is no heightmap.
287         u16 m_hm_split;
288         // These are removed when they are drawn to blocks.
289         // - Each is drawn when generating blocks; When the last one of
290         //   the needed blocks is being generated.
291         core::map<v3s16, u8> *m_objects;
292 };
293
294 class ClientMapSector : public MapSector
295 {
296 public:
297         ClientMapSector(NodeContainer *parent, v2s16 pos);
298         ~ClientMapSector();
299         
300         u32 getId() const
301         {
302                 return MAPSECTOR_CLIENT;
303         }
304
305         void deSerialize(std::istream &is);
306
307         s16 getCorner(u16 i)
308         {
309                 return m_corners[i];
310         }
311                 
312 private:
313         // The ground height of the corners is stored in here
314         s16 m_corners[4];
315 };
316         
317 #endif
318