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