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