Made a proper queued thread to client for handling some block mesh updates. Also...
[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 #include "nodemetadata.h"
35
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(enum NodeModType a_type=NODEMOD_NONE, u16 a_param=0)
63         {
64                 type = a_type;
65                 param = a_param;
66         }
67         bool operator==(const NodeMod &other)
68         {
69                 return (type == other.type && param == other.param);
70         }
71         enum NodeModType type;
72         u16 param;
73 };
74
75 class NodeModMap
76 {
77 public:
78         /*
79                 returns true if the mod was different last time
80         */
81         bool set(v3s16 p, const NodeMod &mod)
82         {
83                 // See if old is different, cancel if it is not different.
84                 core::map<v3s16, NodeMod>::Node *n = m_mods.find(p);
85                 if(n)
86                 {
87                         NodeMod old = n->getValue();
88                         if(old == mod)
89                                 return false;
90
91                         n->setValue(mod);
92                 }
93                 else
94                 {
95                         m_mods.insert(p, mod);
96                 }
97                 
98                 return true;
99         }
100         // Returns true if there was one
101         bool get(v3s16 p, NodeMod *mod)
102         {
103                 core::map<v3s16, NodeMod>::Node *n;
104                 n = m_mods.find(p);
105                 if(n == NULL)
106                         return false;
107                 if(mod)
108                         *mod = n->getValue();
109                 return true;
110         }
111         bool clear(v3s16 p)
112         {
113                 if(m_mods.find(p))
114                 {
115                         m_mods.remove(p);
116                         return true;
117                 }
118                 return false;
119         }
120         bool clear()
121         {
122                 if(m_mods.size() == 0)
123                         return false;
124                 m_mods.clear();
125                 return true;
126         }
127         void copy(NodeModMap &dest)
128         {
129                 dest.m_mods.clear();
130
131                 for(core::map<v3s16, NodeMod>::Iterator
132                                 i = m_mods.getIterator();
133                                 i.atEnd() == false; i++)
134                 {
135                         dest.m_mods.insert(i.getNode()->getKey(), i.getNode()->getValue());
136                 }
137         }
138
139 private:
140         core::map<v3s16, NodeMod> m_mods;
141 };
142
143 enum
144 {
145         NODECONTAINER_ID_MAPBLOCK,
146         NODECONTAINER_ID_MAPSECTOR,
147         NODECONTAINER_ID_MAP,
148         NODECONTAINER_ID_MAPBLOCKCACHE,
149         NODECONTAINER_ID_VOXELMANIPULATOR,
150 };
151
152 class NodeContainer
153 {
154 public:
155         virtual bool isValidPosition(v3s16 p) = 0;
156         virtual MapNode getNode(v3s16 p) = 0;
157         virtual void setNode(v3s16 p, MapNode & n) = 0;
158         virtual u16 nodeContainerId() const = 0;
159
160         MapNode getNodeNoEx(v3s16 p)
161         {
162                 try{
163                         return getNode(p);
164                 }
165                 catch(InvalidPositionException &e){
166                         return MapNode(CONTENT_IGNORE);
167                 }
168         }
169 };
170
171 /*
172         Mesh making stuff
173 */
174
175 class MapBlock;
176
177 struct MeshMakeData
178 {
179         u32 m_daynight_ratio;
180         NodeModMap m_temp_mods;
181         VoxelManipulator m_vmanip;
182         v3s16 m_blockpos;
183         
184         /*
185                 Copy central data directly from block, and other data from
186                 parent of block.
187         */
188         void fill(u32 daynight_ratio, MapBlock *block);
189 };
190
191 u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
192                 v3s16 face_dir);
193
194 scene::SMesh* makeMapBlockMesh(MeshMakeData *data);
195
196 /*
197         MapBlock itself
198 */
199
200 class MapBlock : public NodeContainer
201 {
202 public:
203         MapBlock(NodeContainer *parent, v3s16 pos, bool dummy=false);
204         ~MapBlock();
205         
206         virtual u16 nodeContainerId() const
207         {
208                 return NODECONTAINER_ID_MAPBLOCK;
209         }
210         
211         NodeContainer * getParent()
212         {
213                 return m_parent;
214         }
215
216         void reallocate()
217         {
218                 if(data != NULL)
219                         delete[] data;
220                 u32 l = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
221                 data = new MapNode[l];
222                 for(u32 i=0; i<l; i++){
223                         data[i] = MapNode();
224                 }
225                 setChangedFlag();
226         }
227
228         /*
229                 Flags
230         */
231
232         bool isDummy()
233         {
234                 return (data == NULL);
235         }
236         void unDummify()
237         {
238                 assert(isDummy());
239                 reallocate();
240         }
241         
242         bool getChangedFlag()
243         {
244                 return changed;
245         }
246         void resetChangedFlag()
247         {
248                 changed = false;
249         }
250         void setChangedFlag()
251         {
252                 changed = true;
253         }
254
255         bool getIsUnderground()
256         {
257                 return is_underground;
258         }
259
260         void setIsUnderground(bool a_is_underground)
261         {
262                 is_underground = a_is_underground;
263                 setChangedFlag();
264         }
265
266 #ifndef SERVER
267         void setMeshExpired(bool expired)
268         {
269                 m_mesh_expired = expired;
270         }
271         
272         bool getMeshExpired()
273         {
274                 return m_mesh_expired;
275         }
276 #endif
277
278         void setLightingExpired(bool expired)
279         {
280                 m_lighting_expired = expired;
281                 setChangedFlag();
282         }
283         bool getLightingExpired()
284         {
285                 return m_lighting_expired;
286         }
287
288         /*bool isFullyGenerated()
289         {
290                 return !m_not_fully_generated;
291         }
292         void setFullyGenerated(bool b)
293         {
294                 setChangedFlag();
295                 m_not_fully_generated = !b;
296         }*/
297
298         bool isValid()
299         {
300                 if(m_lighting_expired)
301                         return false;
302                 if(data == NULL)
303                         return false;
304                 return true;
305         }
306
307         /*
308                 Position stuff
309         */
310
311         v3s16 getPos()
312         {
313                 return m_pos;
314         }
315                 
316         v3s16 getPosRelative()
317         {
318                 return m_pos * MAP_BLOCKSIZE;
319         }
320                 
321         core::aabbox3d<s16> getBox()
322         {
323                 return core::aabbox3d<s16>(getPosRelative(),
324                                 getPosRelative()
325                                 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
326                                 - v3s16(1,1,1));
327         }
328
329         /*
330                 Regular MapNode get-setters
331         */
332         
333         bool isValidPosition(v3s16 p)
334         {
335                 if(data == NULL)
336                         return false;
337                 return (p.X >= 0 && p.X < MAP_BLOCKSIZE
338                                 && p.Y >= 0 && p.Y < MAP_BLOCKSIZE
339                                 && p.Z >= 0 && p.Z < MAP_BLOCKSIZE);
340         }
341
342         MapNode getNode(s16 x, s16 y, s16 z)
343         {
344                 if(data == NULL)
345                         throw InvalidPositionException();
346                 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
347                 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
348                 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
349                 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
350         }
351         
352         MapNode getNode(v3s16 p)
353         {
354                 return getNode(p.X, p.Y, p.Z);
355         }
356         
357         void setNode(s16 x, s16 y, s16 z, MapNode & n)
358         {
359                 if(data == NULL)
360                         throw InvalidPositionException();
361                 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
362                 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
363                 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
364                 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
365                 setChangedFlag();
366         }
367         
368         void setNode(v3s16 p, MapNode & n)
369         {
370                 setNode(p.X, p.Y, p.Z, n);
371         }
372
373         /*
374                 Non-checking variants of the above
375         */
376
377         MapNode getNodeNoCheck(s16 x, s16 y, s16 z)
378         {
379                 if(data == NULL)
380                         throw InvalidPositionException();
381                 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
382         }
383         
384         MapNode getNodeNoCheck(v3s16 p)
385         {
386                 return getNodeNoCheck(p.X, p.Y, p.Z);
387         }
388         
389         void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
390         {
391                 if(data == NULL)
392                         throw InvalidPositionException();
393                 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
394                 setChangedFlag();
395         }
396         
397         void setNodeNoCheck(v3s16 p, MapNode & n)
398         {
399                 setNodeNoCheck(p.X, p.Y, p.Z, n);
400         }
401
402         /*
403                 These functions consult the parent container if the position
404                 is not valid on this MapBlock.
405         */
406         bool isValidPositionParent(v3s16 p);
407         MapNode getNodeParent(v3s16 p);
408         void setNodeParent(v3s16 p, MapNode & n);
409         MapNode getNodeParentNoEx(v3s16 p);
410
411         void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
412         {
413                 for(u16 z=0; z<d; z++)
414                         for(u16 y=0; y<h; y++)
415                                 for(u16 x=0; x<w; x++)
416                                         setNode(x0+x, y0+y, z0+z, node);
417         }
418
419         /*
420                 Graphics-related methods
421         */
422         
423         /*// A quick version with nodes passed as parameters
424         u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
425                         v3s16 face_dir);*/
426         /*// A more convenient version
427         u8 getFaceLight(u32 daynight_ratio, v3s16 p, v3s16 face_dir)
428         {
429                 return getFaceLight(daynight_ratio,
430                                 getNodeParentNoEx(p),
431                                 getNodeParentNoEx(p + face_dir),
432                                 face_dir);
433         }*/
434         u8 getFaceLight2(u32 daynight_ratio, v3s16 p, v3s16 face_dir)
435         {
436                 return getFaceLight(daynight_ratio,
437                                 getNodeParentNoEx(p),
438                                 getNodeParentNoEx(p + face_dir),
439                                 face_dir);
440         }
441         
442 #ifndef SERVER
443         // light = 0...255
444         /*static void makeFastFace(TileSpec tile, u8 light, v3f p,
445                         v3s16 dir, v3f scale, v3f posRelative_f,
446                         core::array<FastFace> &dest);*/
447         
448         /*TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
449                         NodeModMap &temp_mods);*/
450         /*u8 getNodeContent(v3s16 p, MapNode mn,
451                         NodeModMap &temp_mods);*/
452
453         /*
454                 Generates the FastFaces of a node row. This has a
455                 ridiculous amount of parameters because that way they
456                 can be precalculated by the caller.
457
458                 translate_dir: unit vector with only one of x, y or z
459                 face_dir: unit vector with only one of x, y or z
460         */
461         /*void updateFastFaceRow(
462                         u32 daynight_ratio,
463                         v3f posRelative_f,
464                         v3s16 startpos,
465                         u16 length,
466                         v3s16 translate_dir,
467                         v3f translate_dir_f,
468                         v3s16 face_dir,
469                         v3f face_dir_f,
470                         core::array<FastFace> &dest,
471                         NodeModMap &temp_mods);*/
472         
473         /*
474                 Thread-safely updates the whole mesh of the mapblock.
475         */
476 #if 1
477         void updateMesh(u32 daynight_ratio);
478 #endif
479
480         void replaceMesh(scene::SMesh *mesh_new);
481         
482 #endif // !SERVER
483         
484         // See comments in mapblock.cpp
485         bool propagateSunlight(core::map<v3s16, bool> & light_sources,
486                         bool remove_light=false, bool *black_air_left=NULL,
487                         bool grow_grass=false);
488         
489         // Copies data to VoxelManipulator to getPosRelative()
490         void copyTo(VoxelManipulator &dst);
491         // Copies data from VoxelManipulator getPosRelative()
492         void copyFrom(VoxelManipulator &dst);
493
494         /*
495                 MapBlockObject stuff
496         */
497         
498         void serializeObjects(std::ostream &os, u8 version)
499         {
500                 m_objects.serialize(os, version);
501         }
502         // If smgr!=NULL, new objects are added to the scene
503         void updateObjects(std::istream &is, u8 version,
504                         scene::ISceneManager *smgr, u32 daynight_ratio)
505         {
506                 m_objects.update(is, version, smgr, daynight_ratio);
507
508                 setChangedFlag();
509         }
510         void clearObjects()
511         {
512                 m_objects.clear();
513
514                 setChangedFlag();
515         }
516         void addObject(MapBlockObject *object)
517                         throw(ContainerFullException, AlreadyExistsException)
518         {
519                 m_objects.add(object);
520
521                 setChangedFlag();
522         }
523         void removeObject(s16 id)
524         {
525                 m_objects.remove(id);
526
527                 setChangedFlag();
528         }
529         MapBlockObject * getObject(s16 id)
530         {
531                 return m_objects.get(id);
532         }
533         JMutexAutoLock * getObjectLock()
534         {
535                 return m_objects.getLock();
536         }
537
538         /*
539                 Moves objects, deletes objects and spawns new objects
540         */
541         void stepObjects(float dtime, bool server, u32 daynight_ratio);
542
543         /*void wrapObject(MapBlockObject *object)
544         {
545                 m_objects.wrapObject(object);
546
547                 setChangedFlag();
548         }*/
549
550         // origin is relative to block
551         void getObjects(v3f origin, f32 max_d,
552                         core::array<DistanceSortedObject> &dest)
553         {
554                 m_objects.getObjects(origin, max_d, dest);
555         }
556
557         s32 getObjectCount()
558         {
559                 return m_objects.getCount();
560         }
561
562 #ifndef SERVER
563         /*
564                 Methods for setting temporary modifications to nodes for
565                 drawing
566
567                 returns true if the mod was different last time
568         */
569         bool setTempMod(v3s16 p, const NodeMod &mod)
570         {
571                 /*dstream<<"setTempMod called on block"
572                                 <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
573                                 <<", mod.type="<<mod.type
574                                 <<", mod.param="<<mod.param
575                                 <<std::endl;*/
576                 JMutexAutoLock lock(m_temp_mods_mutex);
577
578                 return m_temp_mods.set(p, mod);
579         }
580         // Returns true if there was one
581         bool getTempMod(v3s16 p, NodeMod *mod)
582         {
583                 JMutexAutoLock lock(m_temp_mods_mutex);
584
585                 return m_temp_mods.get(p, mod);
586         }
587         bool clearTempMod(v3s16 p)
588         {
589                 JMutexAutoLock lock(m_temp_mods_mutex);
590
591                 return m_temp_mods.clear(p);
592         }
593         bool clearTempMods()
594         {
595                 JMutexAutoLock lock(m_temp_mods_mutex);
596                 
597                 return m_temp_mods.clear();
598         }
599         void copyTempMods(NodeModMap &dst)
600         {
601                 JMutexAutoLock lock(m_temp_mods_mutex);
602                 m_temp_mods.copy(dst);
603         }
604 #endif
605
606         /*
607                 Update day-night lighting difference flag.
608                 
609                 Sets m_day_night_differs to appropriate value.
610                 
611                 These methods don't care about neighboring blocks.
612                 It means that to know if a block really doesn't need a mesh
613                 update between day and night, the neighboring blocks have
614                 to be taken into account. Use Map::dayNightDiffed().
615         */
616         void updateDayNightDiff();
617
618         bool dayNightDiffed()
619         {
620                 return m_day_night_differs;
621         }
622
623         /*
624                 Miscellaneous stuff
625         */
626         
627         /*
628                 Tries to measure ground level.
629                 Return value:
630                         -1 = only air
631                         -2 = only ground
632                         -3 = random fail
633                         0...MAP_BLOCKSIZE-1 = ground level
634         */
635         s16 getGroundLevel(v2s16 p2d);
636
637         /*
638                 Serialization
639         */
640         
641         // Doesn't write version by itself
642         void serialize(std::ostream &os, u8 version);
643
644         void deSerialize(std::istream &is, u8 version);
645
646 private:
647         /*
648                 Private methods
649         */
650
651         /*
652                 Used only internally, because changes can't be tracked
653         */
654
655         MapNode & getNodeRef(s16 x, s16 y, s16 z)
656         {
657                 if(data == NULL)
658                         throw InvalidPositionException();
659                 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
660                 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
661                 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
662                 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
663         }
664         MapNode & getNodeRef(v3s16 &p)
665         {
666                 return getNodeRef(p.X, p.Y, p.Z);
667         }
668
669 public:
670         /*
671                 Public member variables
672         */
673
674 #ifndef SERVER
675         scene::SMesh *mesh;
676         JMutex mesh_mutex;
677 #endif
678         
679         NodeMetadataList m_node_metadata;
680         
681 private:
682         /*
683                 Private member variables
684         */
685
686         // NOTE: Lots of things rely on this being the Map
687         NodeContainer *m_parent;
688         // Position in blocks on parent
689         v3s16 m_pos;
690         
691         /*
692                 If NULL, block is a dummy block.
693                 Dummy blocks are used for caching not-found-on-disk blocks.
694         */
695         MapNode * data;
696
697         /*
698                 - On the server, this is used for telling whether the
699                   block has been changed from the one on disk.
700                 - On the client, this is used for nothing.
701         */
702         bool changed;
703
704         /*
705                 When propagating sunlight and the above block doesn't exist,
706                 sunlight is assumed if this is false.
707
708                 In practice this is set to true if the block is completely
709                 undeground with nothing visible above the ground except
710                 caves.
711         */
712         bool is_underground;
713
714         /*
715                 Set to true if changes has been made that make the old lighting
716                 values wrong but the lighting hasn't been actually updated.
717
718                 If this is false, lighting is exactly right.
719                 If this is true, lighting might be wrong or right.
720         */
721         bool m_lighting_expired;
722         
723         // Whether day and night lighting differs
724         bool m_day_night_differs;
725         
726         MapBlockObjectList m_objects;
727
728         // Object spawning stuff
729         float m_spawn_timer;
730
731 #ifndef SERVER // Only on client
732         /*
733                 Set to true if the mesh has been ordered to be updated
734                 sometime in the background.
735                 In practice this is set when the day/night lighting switches.
736         */
737         bool m_mesh_expired;
738         
739         // Temporary modifications to nodes
740         // These are only used when drawing
741         NodeModMap m_temp_mods;
742         JMutex m_temp_mods_mutex;
743 #endif
744 };
745
746 inline bool blockpos_over_limit(v3s16 p)
747 {
748         return
749           (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
750         || p.X >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
751         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
752         || p.Y >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
753         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
754         || p.Z >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
755 }
756
757 /*
758         Returns the position of the block where the node is located
759 */
760 inline v3s16 getNodeBlockPos(v3s16 p)
761 {
762         return getContainerPos(p, MAP_BLOCKSIZE);
763 }
764
765 inline v2s16 getNodeSectorPos(v2s16 p)
766 {
767         return getContainerPos(p, MAP_BLOCKSIZE);
768 }
769
770 inline s16 getNodeBlockY(s16 y)
771 {
772         return getContainerPos(y, MAP_BLOCKSIZE);
773 }
774
775 #endif
776