]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mapblock.h
license stuff
[dragonfireclient.git] / src / mapblock.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 #ifndef MAPBLOCK_HEADER
21 #define MAPBLOCK_HEADER
22
23 #include <jmutex.h>
24 #include <jmutexautolock.h>
25 #include <exception>
26 #include "debug.h"
27 #include "common_irrlicht.h"
28 #include "mapnode.h"
29 #include "exceptions.h"
30 #include "serialization.h"
31 #include "constants.h"
32 #include "mapblockobject.h"
33
34 #define MAP_BLOCKSIZE 16
35
36 // Named by looking towards z+
37 enum{
38         FACE_BACK=0,
39         FACE_TOP,
40         FACE_RIGHT,
41         FACE_FRONT,
42         FACE_BOTTOM,
43         FACE_LEFT
44 };
45
46 struct FastFace
47 {
48         u8 material;
49         video::S3DVertex vertices[4]; // Precalculated vertices
50 };
51
52 enum
53 {
54         NODECONTAINER_ID_MAPBLOCK,
55         NODECONTAINER_ID_MAPSECTOR,
56         NODECONTAINER_ID_MAP,
57         NODECONTAINER_ID_MAPBLOCKCACHE,
58         NODECONTAINER_ID_VOXELMANIPULATOR,
59 };
60
61 class NodeContainer
62 {
63 public:
64         virtual bool isValidPosition(v3s16 p) = 0;
65         virtual MapNode getNode(v3s16 p) = 0;
66         virtual void setNode(v3s16 p, MapNode & n) = 0;
67         virtual u16 nodeContainerId() const = 0;
68 };
69
70 class MapBlock : public NodeContainer
71 {
72 private:
73
74         NodeContainer *m_parent;
75         // Position in blocks on parent
76         v3s16 m_pos;
77         /*
78                 If NULL, block is a dummy block.
79                 Dummy blocks are used for caching not-found-on-disk blocks.
80         */
81         MapNode * data;
82         /*
83                 - On the client, this is used for checking whether to
84                   recalculate the face cache. (Is it anymore?)
85                 - On the server, this is used for telling whether the
86                   block has been changed from the one on disk.
87         */
88         bool changed;
89         /*
90                 Used for some initial lighting stuff.
91                 At least /has been/ used. 8)
92         */
93         bool is_underground;
94         
95         MapBlockObjectList m_objects;
96         
97 public:
98
99         /*
100                 This used by Server's block creation stuff for not sending
101                 blocks that are waiting a lighting update.
102
103                 If true, the block needs some work by the one who set this
104                 to true.
105
106                 While true, nobody else should touch the block.
107         */
108         //bool is_incomplete;
109         
110         scene::SMesh *mesh;
111         JMutex mesh_mutex;
112
113         MapBlock(NodeContainer *parent, v3s16 pos, bool dummy=false):
114                         m_parent(parent),
115                         m_pos(pos),
116                         changed(true),
117                         is_underground(false),
118                         m_objects(this)
119                         //is_incomplete(false)
120         {
121                 data = NULL;
122                 if(dummy == false)
123                         reallocate();
124                 mesh_mutex.Init();
125                 mesh = NULL;
126         }
127
128         ~MapBlock()
129         {
130                 {
131                         JMutexAutoLock lock(mesh_mutex);
132                         
133                         if(mesh != NULL)
134                         {
135                                 mesh->drop();
136                                 mesh = NULL;
137                         }
138                 }
139
140                 if(data)
141                         delete[] data;
142         }
143         
144         virtual u16 nodeContainerId() const
145         {
146                 return NODECONTAINER_ID_MAPBLOCK;
147         }
148
149         NodeContainer * getParent()
150         {
151                 return m_parent;
152         }
153
154         bool isDummy()
155         {
156                 return (data == NULL);
157         }
158
159         void unDummify()
160         {
161                 assert(isDummy());
162                 reallocate();
163         }
164         
165         bool getChangedFlag()
166         {
167                 return changed;
168         }
169
170         void resetChangedFlag()
171         {
172                 changed = false;
173         }
174
175         void setChangedFlag()
176         {
177                 changed = true;
178         }
179
180         v3s16 getPos()
181         {
182                 return m_pos;
183         }
184                 
185         v3s16 getPosRelative()
186         {
187                 return m_pos * MAP_BLOCKSIZE;
188         }
189                 
190         bool getIsUnderground()
191         {
192                 return is_underground;
193         }
194
195         void setIsUnderground(bool a_is_underground)
196         {
197                 is_underground = a_is_underground;
198                 setChangedFlag();
199         }
200
201         core::aabbox3d<s16> getBox()
202         {
203                 return core::aabbox3d<s16>(getPosRelative(),
204                                 getPosRelative()
205                                 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
206                                 - v3s16(1,1,1));
207         }
208         
209         void reallocate()
210         {
211                 if(data != NULL)
212                         delete[] data;
213                 u32 l = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
214                 data = new MapNode[l];
215                 for(u32 i=0; i<l; i++){
216                         data[i] = MapNode();
217                 }
218                 setChangedFlag();
219         }
220
221         bool isValidPosition(v3s16 p)
222         {
223                 if(data == NULL)
224                         return false;
225                 return (p.X >= 0 && p.X < MAP_BLOCKSIZE
226                                 && p.Y >= 0 && p.Y < MAP_BLOCKSIZE
227                                 && p.Z >= 0 && p.Z < MAP_BLOCKSIZE);
228         }
229
230         /*
231                 Regular MapNode get-setters
232         */
233         
234         MapNode getNode(s16 x, s16 y, s16 z)
235         {
236                 if(data == NULL)
237                         throw InvalidPositionException();
238                 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
239                 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
240                 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
241                 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
242         }
243         
244         MapNode getNode(v3s16 p)
245         {
246                 return getNode(p.X, p.Y, p.Z);
247         }
248         
249         void setNode(s16 x, s16 y, s16 z, MapNode & n)
250         {
251                 if(data == NULL)
252                         throw InvalidPositionException();
253                 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
254                 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
255                 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
256                 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
257                 setChangedFlag();
258         }
259         
260         void setNode(v3s16 p, MapNode & n)
261         {
262                 setNode(p.X, p.Y, p.Z, n);
263         }
264
265         /*
266                 Non-checking variants of the above
267         */
268
269         MapNode getNodeNoCheck(s16 x, s16 y, s16 z)
270         {
271                 if(data == NULL)
272                         throw InvalidPositionException();
273                 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
274         }
275         
276         MapNode getNodeNoCheck(v3s16 p)
277         {
278                 return getNodeNoCheck(p.X, p.Y, p.Z);
279         }
280         
281         void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
282         {
283                 if(data == NULL)
284                         throw InvalidPositionException();
285                 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
286                 setChangedFlag();
287         }
288         
289         void setNodeNoCheck(v3s16 p, MapNode & n)
290         {
291                 setNodeNoCheck(p.X, p.Y, p.Z, n);
292         }
293
294         /*
295                 These functions consult the parent container if the position
296                 is not valid on this MapBlock.
297         */
298         bool isValidPositionParent(v3s16 p);
299         MapNode getNodeParent(v3s16 p);
300         void setNodeParent(v3s16 p, MapNode & n);
301
302         void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
303         {
304                 for(u16 z=0; z<d; z++)
305                         for(u16 y=0; y<h; y++)
306                                 for(u16 x=0; x<w; x++)
307                                         setNode(x0+x, y0+y, z0+z, node);
308         }
309
310         static FastFace * makeFastFace(u8 material, u8 light, v3f p,
311                         v3f dir, v3f scale, v3f posRelative_f);
312         
313         u8 getFaceLight(v3s16 p, v3s16 face_dir);
314         
315         /*
316                 Gets node material from any place relative to block.
317                 Returns MATERIAL_AIR if doesn't exist.
318         */
319         u8 getNodeMaterial(v3s16 p);
320
321         /*
322                 startpos:
323                 translate_dir: unit vector with only one of x, y or z
324                 face_dir: unit vector with only one of x, y or z
325         */
326         void updateFastFaceRow(v3s16 startpos,
327                         u16 length,
328                         v3s16 translate_dir,
329                         v3s16 face_dir,
330                         core::list<FastFace*> &dest);
331
332         void updateMesh();
333
334         bool propagateSunlight(core::map<v3s16, bool> & light_sources);
335         
336         // Doesn't write version by itself
337         void serialize(std::ostream &os, u8 version);
338
339         void deSerialize(std::istream &is, u8 version);
340         
341         void serializeObjects(std::ostream &os, u8 version)
342         {
343                 m_objects.serialize(os, version);
344         }
345         // If smgr!=NULL, new objects are added to the scene
346         void updateObjects(std::istream &is, u8 version,
347                         scene::ISceneManager *smgr)
348         {
349                 m_objects.update(is, version, smgr);
350
351                 setChangedFlag();
352         }
353         void clearObjects()
354         {
355                 m_objects.clear();
356
357                 setChangedFlag();
358         }
359         void addObject(MapBlockObject *object)
360                         throw(ContainerFullException, AlreadyExistsException)
361         {
362                 m_objects.add(object);
363
364                 setChangedFlag();
365         }
366         void removeObject(s16 id)
367         {
368                 m_objects.remove(id);
369
370                 setChangedFlag();
371         }
372         MapBlockObject * getObject(s16 id)
373         {
374                 return m_objects.get(id);
375         }
376         JMutexAutoLock * getObjectLock()
377         {
378                 return m_objects.getLock();
379         }
380         void stepObjects(float dtime, bool server)
381         {
382                 m_objects.step(dtime, server);
383
384                 setChangedFlag();
385         }
386
387         /*void wrapObject(MapBlockObject *object)
388         {
389                 m_objects.wrapObject(object);
390
391                 setChangedFlag();
392         }*/
393
394         // origin is relative to block
395         void getObjects(v3f origin, f32 max_d,
396                         core::array<DistanceSortedObject> &dest)
397         {
398                 m_objects.getObjects(origin, max_d, dest);
399         }
400
401         s32 getObjectCount()
402         {
403                 return m_objects.getCount();
404         }
405
406 private:
407
408         /*
409                 Used only internally, because changes can't be tracked
410         */
411
412         MapNode & getNodeRef(s16 x, s16 y, s16 z)
413         {
414                 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
415                 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
416                 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
417                 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
418         }
419         MapNode & getNodeRef(v3s16 &p)
420         {
421                 return getNodeRef(p.X, p.Y, p.Z);
422         }
423 };
424
425 inline bool blockpos_over_limit(v3s16 p)
426 {
427         return
428           (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
429         || p.X >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
430         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
431         || p.Y >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
432         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
433         || p.Z >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
434 }
435
436 /*
437         Returns the position of the block where the node is located
438 */
439 inline v3s16 getNodeBlockPos(v3s16 p)
440 {
441         return getContainerPos(p, MAP_BLOCKSIZE);
442 }
443
444 inline v2s16 getNodeSectorPos(v2s16 p)
445 {
446         return getContainerPos(p, MAP_BLOCKSIZE);
447 }
448
449 inline s16 getNodeBlockY(s16 y)
450 {
451         return getContainerPos(y, MAP_BLOCKSIZE);
452 }
453
454 #endif
455