Merge pull request #13 from Bahamada/upstream_merge
[oweals/minetest.git] / src / mapsector.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 /*
21 (c) 2010 Perttu Ahola <celeron55@gmail.com>
22 */
23
24 #ifndef MAPSECTOR_HEADER
25 #define MAPSECTOR_HEADER
26
27 #include <jmutex.h>
28 #include "common_irrlicht.h"
29 #include "mapblock.h"
30 //#include "heightmap.h"
31 #include "exceptions.h"
32
33 /*
34         This is an Y-wise stack of MapBlocks.
35 */
36
37 #define MAPSECTOR_SERVER 0
38 #define MAPSECTOR_CLIENT 1
39
40 class MapSector: public NodeContainer
41 {
42 public:
43         
44         MapSector(NodeContainer *parent, v2s16 pos);
45         virtual ~MapSector();
46
47         virtual u16 nodeContainerId() const
48         {
49                 return NODECONTAINER_ID_MAPSECTOR;
50         }
51
52         virtual u32 getId() const = 0;
53
54         void deleteBlocks();
55
56         v2s16 getPos()
57         {
58                 return m_pos;
59         }
60
61         MapBlock * getBlockNoCreateNoEx(s16 y);
62         MapBlock * getBlockNoCreate(s16 y);
63         MapBlock * createBlankBlockNoInsert(s16 y);
64         MapBlock * createBlankBlock(s16 y);
65         //MapBlock * getBlock(s16 y, bool generate=true);
66
67         void insertBlock(MapBlock *block);
68         
69         // This is used to remove a dummy from the sector while generating it.
70         // Block is only removed from internal container, not deleted.
71         void removeBlock(MapBlock *block);
72         
73         /*
74                 This might not be a thread-safe depending on the day.
75                 See the implementation.
76         */
77         void getBlocks(core::list<MapBlock*> &dest);
78         
79         /*
80                 If all nodes in area can be accessed, returns true and
81                 adds all blocks in area to blocks.
82
83                 If all nodes in area cannot be accessed, returns false.
84
85                 The implementation of this is quite slow
86
87                 if blocks==NULL; it is not accessed at all.
88         */
89         bool isValidArea(v3s16 p_min_nodes, v3s16 p_max_nodes,
90                         core::map<s16, MapBlock*> *blocks)
91         {
92                 core::map<s16, MapBlock*> bs;
93                 
94                 v3s16 p_min = getNodeBlockPos(p_min_nodes);
95                 v3s16 p_max = getNodeBlockPos(p_max_nodes);
96                 if(p_min.X != 0 || p_min.Z != 0
97                                 || p_max.X != 0 || p_max.Z != 0)
98                         return false;
99                 v3s16 y;
100                 for(s16 y=p_min.Y; y<=p_max.Y; y++)
101                 {
102                         try{
103                                 MapBlock *block = getBlockNoCreate(y);
104                                 if(block->isDummy())
105                                         return false;
106                                 if(blocks!=NULL)
107                                         bs[y] = block;
108                         }
109                         catch(InvalidPositionException &e)
110                         {
111                                 return false;
112                         }
113                 }
114
115                 if(blocks!=NULL)
116                 {
117                         for(core::map<s16, MapBlock*>::Iterator i=bs.getIterator();
118                                         i.atEnd()==false; i++)
119                         {
120                                 MapBlock *block = i.getNode()->getValue();
121                                 s16 y = i.getNode()->getKey();
122                                 blocks->insert(y, block);
123                         }
124                 }
125                 return true;
126         }
127
128         void getBlocksInArea(v3s16 p_min_nodes, v3s16 p_max_nodes,
129                         core::map<v3s16, MapBlock*> &blocks)
130         {
131                 v3s16 p_min = getNodeBlockPos(p_min_nodes);
132                 v3s16 p_max = getNodeBlockPos(p_max_nodes);
133                 v3s16 y;
134                 for(s16 y=p_min.Y; y<=p_max.Y; y++)
135                 {
136                         try{
137                                 MapBlock *block = getBlockNoCreate(y);
138                                 blocks.insert(block->getPos(), block);
139                         }
140                         catch(InvalidPositionException &e)
141                         {
142                         }
143                 }
144         }
145         
146         // virtual from NodeContainer
147         bool isValidPosition(v3s16 p)
148         {
149                 v3s16 blockpos = getNodeBlockPos(p);
150
151                 if(blockpos.X != 0 || blockpos.Z != 0)
152                         return false;
153
154                 MapBlock *blockref;
155                 try{
156                         blockref = getBlockNoCreate(blockpos.Y);
157                 }
158                 catch(InvalidPositionException &e)
159                 {
160                         return false;
161                 }
162
163                 return true;
164         }
165
166         // virtual from NodeContainer
167         MapNode getNode(v3s16 p)
168         {
169                 v3s16 blockpos = getNodeBlockPos(p);
170                 if(blockpos.X != 0 || blockpos.Z != 0)
171                         throw InvalidPositionException
172                                 ("MapSector only allows Y");
173
174                 MapBlock * blockref = getBlockNoCreate(blockpos.Y);
175                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
176
177                 return blockref->getNode(relpos);
178         }
179         // virtual from NodeContainer
180         void setNode(v3s16 p, MapNode & n)
181         {
182                 v3s16 blockpos = getNodeBlockPos(p);
183                 if(blockpos.X != 0 || blockpos.Z != 0)
184                         throw InvalidPositionException
185                                 ("MapSector only allows Y");
186
187                 MapBlock * blockref = getBlockNoCreate(blockpos.Y);
188                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
189                 blockref->setNode(relpos, n);
190         }
191
192         // DEPRECATED?
193         virtual f32 getGroundHeight(v2s16 p, bool generate=false)
194         {
195                 return GROUNDHEIGHT_NOTFOUND_SETVALUE;
196         }
197         virtual void setGroundHeight(v2s16 p, f32 y, bool generate=false)
198         {
199         }
200         
201         // When true, sector metadata is changed from the one on disk
202         // (sector metadata = all but blocks)
203         // Basically, this should be changed to true in every setter method
204         bool differs_from_disk;
205
206 protected:
207         
208         // The pile of MapBlocks
209         core::map<s16, MapBlock*> m_blocks;
210         //JMutex m_blocks_mutex; // For public access functions
211
212         NodeContainer *m_parent;
213         // Position on parent (in MapBlock widths)
214         v2s16 m_pos;
215
216         // Be sure to set this to NULL when the cached block is deleted 
217         MapBlock *m_block_cache;
218         s16 m_block_cache_y;
219         
220         // This is used for protecting m_blocks
221         JMutex m_mutex;
222         
223         /*
224                 Private methods
225         */
226         MapBlock *getBlockBuffered(s16 y);
227
228 };
229
230 class ServerMapSector : public MapSector
231 {
232 public:
233         ServerMapSector(NodeContainer *parent, v2s16 pos);
234         ~ServerMapSector();
235         
236         u32 getId() const
237         {
238                 return MAPSECTOR_SERVER;
239         }
240         
241         // DEPRECATED?
242         f32 getGroundHeight(v2s16 p, bool generate=false);
243         void setGroundHeight(v2s16 p, f32 y, bool generate=false);
244
245         /*
246                 These functions handle metadata.
247                 They do not handle blocks.
248         */
249         void serialize(std::ostream &os, u8 version);
250         
251         static ServerMapSector* deSerialize(
252                         std::istream &is,
253                         NodeContainer *parent,
254                         v2s16 p2d,
255                         core::map<v2s16, MapSector*> & sectors
256                 );
257                 
258 private:
259 };
260
261 #ifndef SERVER
262 class ClientMapSector : public MapSector
263 {
264 public:
265         ClientMapSector(NodeContainer *parent, v2s16 pos);
266         ~ClientMapSector();
267         
268         u32 getId() const
269         {
270                 return MAPSECTOR_CLIENT;
271         }
272
273         void deSerialize(std::istream &is);
274
275         /*s16 getCorner(u16 i)
276         {
277                 return m_corners[i];
278         }*/
279                 
280 private:
281         // The ground height of the corners is stored in here
282         //s16 m_corners[4];
283 };
284 #endif
285         
286 #endif
287