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