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