]> git.lizzy.rs Git - minetest.git/blob - src/mapblock.h
added dedicated server build without irrlicht
[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         TileSpec tile;
50         video::S3DVertex vertices[4]; // Precalculated vertices
51 };
52
53 enum NodeModType
54 {
55         NODEMOD_NONE,
56         NODEMOD_CHANGECONTENT, //param is content id
57         NODEMOD_CRACK // param is crack progression
58 };
59
60 struct NodeMod
61 {
62         NodeMod()
63         {
64                 type = NODEMOD_NONE;
65         }
66         enum NodeModType type;
67         u16 param;
68 };
69
70 enum
71 {
72         NODECONTAINER_ID_MAPBLOCK,
73         NODECONTAINER_ID_MAPSECTOR,
74         NODECONTAINER_ID_MAP,
75         NODECONTAINER_ID_MAPBLOCKCACHE,
76         NODECONTAINER_ID_VOXELMANIPULATOR,
77 };
78
79 class NodeContainer
80 {
81 public:
82         virtual bool isValidPosition(v3s16 p) = 0;
83         virtual MapNode getNode(v3s16 p) = 0;
84         virtual void setNode(v3s16 p, MapNode & n) = 0;
85         virtual u16 nodeContainerId() const = 0;
86 };
87
88 class MapBlock : public NodeContainer
89 {
90 public:
91         MapBlock(NodeContainer *parent, v3s16 pos, bool dummy=false);
92         ~MapBlock();
93         
94         virtual u16 nodeContainerId() const
95         {
96                 return NODECONTAINER_ID_MAPBLOCK;
97         }
98
99         NodeContainer * getParent()
100         {
101                 return m_parent;
102         }
103
104         bool isDummy()
105         {
106                 return (data == NULL);
107         }
108
109         void unDummify()
110         {
111                 assert(isDummy());
112                 reallocate();
113         }
114         
115         bool getChangedFlag()
116         {
117                 return changed;
118         }
119
120         void resetChangedFlag()
121         {
122                 changed = false;
123         }
124
125         void setChangedFlag()
126         {
127                 changed = true;
128         }
129 #ifndef SERVER
130         void setMeshExpired(bool expired)
131         {
132                 m_mesh_expired = expired;
133         }
134         
135         bool getMeshExpired()
136         {
137                 return m_mesh_expired;
138         }
139 #endif
140         v3s16 getPos()
141         {
142                 return m_pos;
143         }
144                 
145         v3s16 getPosRelative()
146         {
147                 return m_pos * MAP_BLOCKSIZE;
148         }
149                 
150         bool getIsUnderground()
151         {
152                 return is_underground;
153         }
154
155         void setIsUnderground(bool a_is_underground)
156         {
157                 is_underground = a_is_underground;
158                 setChangedFlag();
159         }
160
161         core::aabbox3d<s16> getBox()
162         {
163                 return core::aabbox3d<s16>(getPosRelative(),
164                                 getPosRelative()
165                                 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
166                                 - v3s16(1,1,1));
167         }
168         
169         void reallocate()
170         {
171                 if(data != NULL)
172                         delete[] data;
173                 u32 l = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
174                 data = new MapNode[l];
175                 for(u32 i=0; i<l; i++){
176                         data[i] = MapNode();
177                 }
178                 setChangedFlag();
179         }
180
181         bool isValidPosition(v3s16 p)
182         {
183                 if(data == NULL)
184                         return false;
185                 return (p.X >= 0 && p.X < MAP_BLOCKSIZE
186                                 && p.Y >= 0 && p.Y < MAP_BLOCKSIZE
187                                 && p.Z >= 0 && p.Z < MAP_BLOCKSIZE);
188         }
189
190         /*
191                 Regular MapNode get-setters
192         */
193         
194         MapNode getNode(s16 x, s16 y, s16 z)
195         {
196                 if(data == NULL)
197                         throw InvalidPositionException();
198                 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
199                 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
200                 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
201                 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
202         }
203         
204         MapNode getNode(v3s16 p)
205         {
206                 return getNode(p.X, p.Y, p.Z);
207         }
208         
209         void setNode(s16 x, s16 y, s16 z, MapNode & n)
210         {
211                 if(data == NULL)
212                         throw InvalidPositionException();
213                 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
214                 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
215                 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
216                 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
217                 setChangedFlag();
218         }
219         
220         void setNode(v3s16 p, MapNode & n)
221         {
222                 setNode(p.X, p.Y, p.Z, n);
223         }
224
225         /*
226                 Non-checking variants of the above
227         */
228
229         MapNode getNodeNoCheck(s16 x, s16 y, s16 z)
230         {
231                 if(data == NULL)
232                         throw InvalidPositionException();
233                 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
234         }
235         
236         MapNode getNodeNoCheck(v3s16 p)
237         {
238                 return getNodeNoCheck(p.X, p.Y, p.Z);
239         }
240         
241         void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
242         {
243                 if(data == NULL)
244                         throw InvalidPositionException();
245                 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
246                 setChangedFlag();
247         }
248         
249         void setNodeNoCheck(v3s16 p, MapNode & n)
250         {
251                 setNodeNoCheck(p.X, p.Y, p.Z, n);
252         }
253
254         /*
255                 These functions consult the parent container if the position
256                 is not valid on this MapBlock.
257         */
258         bool isValidPositionParent(v3s16 p);
259         MapNode getNodeParent(v3s16 p);
260         void setNodeParent(v3s16 p, MapNode & n);
261         MapNode getNodeParentNoEx(v3s16 p);
262
263         void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
264         {
265                 for(u16 z=0; z<d; z++)
266                         for(u16 y=0; y<h; y++)
267                                 for(u16 x=0; x<w; x++)
268                                         setNode(x0+x, y0+y, z0+z, node);
269         }
270
271         u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
272                         v3s16 face_dir);
273         
274         u8 getFaceLight(u32 daynight_ratio, v3s16 p, v3s16 face_dir)
275         {
276                 return getFaceLight(daynight_ratio,
277                                 getNodeParentNoEx(p),
278                                 getNodeParentNoEx(p + face_dir),
279                                 face_dir);
280         }
281         
282 #ifndef SERVER
283         static void makeFastFace(TileSpec tile, u8 light, v3f p,
284                         v3s16 dir, v3f scale, v3f posRelative_f,
285                         core::array<FastFace> &dest);
286         
287         TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir);
288         u8 getNodeContent(v3s16 p, MapNode mn);
289
290         /*
291                 startpos:
292                 translate_dir: unit vector with only one of x, y or z
293                 face_dir: unit vector with only one of x, y or z
294         */
295         void updateFastFaceRow(
296                         u32 daynight_ratio,
297                         v3f posRelative_f,
298                         v3s16 startpos,
299                         u16 length,
300                         v3s16 translate_dir,
301                         v3f translate_dir_f,
302                         v3s16 face_dir,
303                         v3f face_dir_f,
304                         core::array<FastFace> &dest);
305
306         void updateMesh(u32 daynight_ratio);
307         /*void updateMesh(s32 daynight_i);
308         // Updates all DAYNIGHT_CACHE_COUNT meshes
309         void updateMeshes(s32 first_i=0);*/
310 #endif // !SERVER
311
312         bool propagateSunlight(core::map<v3s16, bool> & light_sources);
313         
314         // Copies data to VoxelManipulator to getPosRelative()
315         void copyTo(VoxelManipulator &dst);
316
317         /*
318                 Object stuff
319         */
320         
321         void serializeObjects(std::ostream &os, u8 version)
322         {
323                 m_objects.serialize(os, version);
324         }
325         // If smgr!=NULL, new objects are added to the scene
326         void updateObjects(std::istream &is, u8 version,
327                         scene::ISceneManager *smgr)
328         {
329                 m_objects.update(is, version, smgr);
330
331                 setChangedFlag();
332         }
333         void clearObjects()
334         {
335                 m_objects.clear();
336
337                 setChangedFlag();
338         }
339         void addObject(MapBlockObject *object)
340                         throw(ContainerFullException, AlreadyExistsException)
341         {
342                 m_objects.add(object);
343
344                 setChangedFlag();
345         }
346         void removeObject(s16 id)
347         {
348                 m_objects.remove(id);
349
350                 setChangedFlag();
351         }
352         MapBlockObject * getObject(s16 id)
353         {
354                 return m_objects.get(id);
355         }
356         JMutexAutoLock * getObjectLock()
357         {
358                 return m_objects.getLock();
359         }
360         void stepObjects(float dtime, bool server)
361         {
362                 m_objects.step(dtime, server);
363
364                 setChangedFlag();
365         }
366
367         /*void wrapObject(MapBlockObject *object)
368         {
369                 m_objects.wrapObject(object);
370
371                 setChangedFlag();
372         }*/
373
374         // origin is relative to block
375         void getObjects(v3f origin, f32 max_d,
376                         core::array<DistanceSortedObject> &dest)
377         {
378                 m_objects.getObjects(origin, max_d, dest);
379         }
380
381         /*void getPseudoObjects(v3f origin, f32 max_d,
382                         core::array<DistanceSortedObject> &dest);*/
383
384         s32 getObjectCount()
385         {
386                 return m_objects.getCount();
387         }
388
389 #ifndef SERVER
390         /*
391                 Methods for setting temporary modifications to nodes for
392                 drawing
393         */
394         void setTempMod(v3s16 p, NodeMod mod)
395         {
396                 m_temp_mods[p] = mod;
397         }
398         void clearTempMod(v3s16 p)
399         {
400                 if(m_temp_mods.find(p))
401                         m_temp_mods.remove(p);
402         }
403         void clearTempMods()
404         {
405                 m_temp_mods.clear();
406         }
407 #endif
408
409         /*
410                 Day-night lighting difference
411                 
412                 These methods don't care about neighboring blocks.
413                 It means that to know if a block really doesn't need a mesh
414                 update between day and night, the neighboring blocks have
415                 to be taken into account.
416         */
417         void updateDayNightDiff();
418
419         bool dayNightDiffed()
420         {
421                 return m_day_night_differs;
422         }
423
424         /*
425                 Serialization
426         */
427         
428         // Doesn't write version by itself
429         void serialize(std::ostream &os, u8 version);
430
431         void deSerialize(std::istream &is, u8 version);
432
433         /*
434                 Public member variables
435         */
436
437 #ifndef SERVER
438         //scene::SMesh *mesh[DAYNIGHT_CACHE_COUNT];
439         scene::SMesh *mesh;
440         JMutex mesh_mutex;
441 #endif
442
443 private:
444
445         /*
446                 Used only internally, because changes can't be tracked
447         */
448
449         MapNode & getNodeRef(s16 x, s16 y, s16 z)
450         {
451                 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
452                 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
453                 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
454                 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
455         }
456         MapNode & getNodeRef(v3s16 &p)
457         {
458                 return getNodeRef(p.X, p.Y, p.Z);
459         }
460
461         
462         NodeContainer *m_parent;
463         // Position in blocks on parent
464         v3s16 m_pos;
465         /*
466                 If NULL, block is a dummy block.
467                 Dummy blocks are used for caching not-found-on-disk blocks.
468         */
469         MapNode * data;
470         /*
471                 - On the client, this is used for checking whether to
472                   recalculate the face cache. (Is it anymore?)
473                 - On the server, this is used for telling whether the
474                   block has been changed from the one on disk.
475         */
476         bool changed;
477         /*
478                 Used for some initial lighting stuff.
479                 At least /has been/ used. 8)
480                 It's probably useless now.
481         */
482         bool is_underground;
483         
484         // Whether day and night lighting differs
485         bool m_day_night_differs;
486         
487         MapBlockObjectList m_objects;
488         
489 #ifndef SERVER
490         bool m_mesh_expired;
491         
492         // Temporary modifications to nodes
493         // These are only used when drawing
494         core::map<v3s16, NodeMod> m_temp_mods;
495 #endif
496 };
497
498 inline bool blockpos_over_limit(v3s16 p)
499 {
500         return
501           (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
502         || p.X >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
503         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
504         || p.Y >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
505         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
506         || p.Z >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
507 }
508
509 /*
510         Returns the position of the block where the node is located
511 */
512 inline v3s16 getNodeBlockPos(v3s16 p)
513 {
514         return getContainerPos(p, MAP_BLOCKSIZE);
515 }
516
517 inline v2s16 getNodeSectorPos(v2s16 p)
518 {
519         return getContainerPos(p, MAP_BLOCKSIZE);
520 }
521
522 inline s16 getNodeBlockY(s16 y)
523 {
524         return getContainerPos(y, MAP_BLOCKSIZE);
525 }
526
527 #endif
528