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