]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mapblock.h
working nicely
[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 #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         u8 material;
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(u8 material, u8 light, v3f p,
287                         v3f dir, v3f scale, v3f posRelative_f);
288         
289         u8 getFaceLight(v3s16 p, v3s16 face_dir);
290         
291         u8 getNodeTile(v3s16 p);
292
293         /*
294                 startpos:
295                 translate_dir: unit vector with only one of x, y or z
296                 face_dir: unit vector with only one of x, y or z
297         */
298         void updateFastFaceRow(v3s16 startpos,
299                         u16 length,
300                         v3s16 translate_dir,
301                         v3s16 face_dir,
302                         core::list<FastFace*> &dest);
303
304         void updateMesh();
305
306         bool propagateSunlight(core::map<v3s16, bool> & light_sources);
307         
308         // Copies data to VoxelManipulator to getPosRelative()
309         void copyTo(VoxelManipulator &dst);
310
311         /*
312                 Object stuff
313         */
314         
315         void serializeObjects(std::ostream &os, u8 version)
316         {
317                 m_objects.serialize(os, version);
318         }
319         // If smgr!=NULL, new objects are added to the scene
320         void updateObjects(std::istream &is, u8 version,
321                         scene::ISceneManager *smgr)
322         {
323                 m_objects.update(is, version, smgr);
324
325                 setChangedFlag();
326         }
327         void clearObjects()
328         {
329                 m_objects.clear();
330
331                 setChangedFlag();
332         }
333         void addObject(MapBlockObject *object)
334                         throw(ContainerFullException, AlreadyExistsException)
335         {
336                 m_objects.add(object);
337
338                 setChangedFlag();
339         }
340         void removeObject(s16 id)
341         {
342                 m_objects.remove(id);
343
344                 setChangedFlag();
345         }
346         MapBlockObject * getObject(s16 id)
347         {
348                 return m_objects.get(id);
349         }
350         JMutexAutoLock * getObjectLock()
351         {
352                 return m_objects.getLock();
353         }
354         void stepObjects(float dtime, bool server)
355         {
356                 m_objects.step(dtime, server);
357
358                 setChangedFlag();
359         }
360
361         /*void wrapObject(MapBlockObject *object)
362         {
363                 m_objects.wrapObject(object);
364
365                 setChangedFlag();
366         }*/
367
368         // origin is relative to block
369         void getObjects(v3f origin, f32 max_d,
370                         core::array<DistanceSortedObject> &dest)
371         {
372                 m_objects.getObjects(origin, max_d, dest);
373         }
374
375         /*void getPseudoObjects(v3f origin, f32 max_d,
376                         core::array<DistanceSortedObject> &dest);*/
377
378         s32 getObjectCount()
379         {
380                 return m_objects.getCount();
381         }
382
383         /*
384                 Serialization
385         */
386         
387         // Doesn't write version by itself
388         void serialize(std::ostream &os, u8 version);
389
390         void deSerialize(std::istream &is, u8 version);
391
392 private:
393
394         /*
395                 Used only internally, because changes can't be tracked
396         */
397
398         MapNode & getNodeRef(s16 x, s16 y, s16 z)
399         {
400                 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
401                 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
402                 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
403                 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
404         }
405         MapNode & getNodeRef(v3s16 &p)
406         {
407                 return getNodeRef(p.X, p.Y, p.Z);
408         }
409
410         
411         NodeContainer *m_parent;
412         // Position in blocks on parent
413         v3s16 m_pos;
414         /*
415                 If NULL, block is a dummy block.
416                 Dummy blocks are used for caching not-found-on-disk blocks.
417         */
418         MapNode * data;
419         /*
420                 - On the client, this is used for checking whether to
421                   recalculate the face cache. (Is it anymore?)
422                 - On the server, this is used for telling whether the
423                   block has been changed from the one on disk.
424         */
425         bool changed;
426         /*
427                 Used for some initial lighting stuff.
428                 At least /has been/ used. 8)
429         */
430         bool is_underground;
431         
432         MapBlockObjectList m_objects;
433         
434 };
435
436 inline bool blockpos_over_limit(v3s16 p)
437 {
438         return
439           (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
440         || p.X >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
441         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
442         || p.Y >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
443         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
444         || p.Z >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
445 }
446
447 /*
448         Returns the position of the block where the node is located
449 */
450 inline v3s16 getNodeBlockPos(v3s16 p)
451 {
452         return getContainerPos(p, MAP_BLOCKSIZE);
453 }
454
455 inline v2s16 getNodeSectorPos(v2s16 p)
456 {
457         return getContainerPos(p, MAP_BLOCKSIZE);
458 }
459
460 inline s16 getNodeBlockY(s16 y)
461 {
462         return getContainerPos(y, MAP_BLOCKSIZE);
463 }
464
465 #endif
466