]> git.lizzy.rs Git - minetest.git/blob - src/mapblock.h
Don't allow banning in singleplayer
[minetest.git] / src / mapblock.h
1 /*
2 Minetest
3 Copyright (C) 2013 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 Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser 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 #pragma once
21
22 #include <set>
23 #include "irr_v3d.h"
24 #include "mapnode.h"
25 #include "exceptions.h"
26 #include "constants.h"
27 #include "staticobject.h"
28 #include "nodemetadata.h"
29 #include "nodetimer.h"
30 #include "modifiedstate.h"
31 #include "util/numeric.h" // getContainerPos
32 #include "settings.h"
33 #include "mapgen/mapgen.h"
34
35 class Map;
36 class NodeMetadataList;
37 class IGameDef;
38 class MapBlockMesh;
39 class VoxelManipulator;
40
41 #define BLOCK_TIMESTAMP_UNDEFINED 0xffffffff
42
43 ////
44 //// MapBlock modified reason flags
45 ////
46
47 #define MOD_REASON_INITIAL                   (1 << 0)
48 #define MOD_REASON_REALLOCATE                (1 << 1)
49 #define MOD_REASON_SET_IS_UNDERGROUND        (1 << 2)
50 #define MOD_REASON_SET_LIGHTING_COMPLETE     (1 << 3)
51 #define MOD_REASON_SET_GENERATED             (1 << 4)
52 #define MOD_REASON_SET_NODE                  (1 << 5)
53 #define MOD_REASON_SET_NODE_NO_CHECK         (1 << 6)
54 #define MOD_REASON_SET_TIMESTAMP             (1 << 7)
55 #define MOD_REASON_REPORT_META_CHANGE        (1 << 8)
56 #define MOD_REASON_CLEAR_ALL_OBJECTS         (1 << 9)
57 #define MOD_REASON_BLOCK_EXPIRED             (1 << 10)
58 #define MOD_REASON_ADD_ACTIVE_OBJECT_RAW     (1 << 11)
59 #define MOD_REASON_REMOVE_OBJECTS_REMOVE     (1 << 12)
60 #define MOD_REASON_REMOVE_OBJECTS_DEACTIVATE (1 << 13)
61 #define MOD_REASON_TOO_MANY_OBJECTS          (1 << 14)
62 #define MOD_REASON_STATIC_DATA_ADDED         (1 << 15)
63 #define MOD_REASON_STATIC_DATA_REMOVED       (1 << 16)
64 #define MOD_REASON_STATIC_DATA_CHANGED       (1 << 17)
65 #define MOD_REASON_EXPIRE_DAYNIGHTDIFF       (1 << 18)
66 #define MOD_REASON_VMANIP                    (1 << 19)
67 #define MOD_REASON_UNKNOWN                   (1 << 20)
68
69 ////
70 //// MapBlock itself
71 ////
72
73 class MapBlock
74 {
75 public:
76         MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef, bool dummy=false);
77         ~MapBlock();
78
79         /*virtual u16 nodeContainerId() const
80         {
81                 return NODECONTAINER_ID_MAPBLOCK;
82         }*/
83
84         Map * getParent()
85         {
86                 return m_parent;
87         }
88
89         void reallocate()
90         {
91                 delete[] data;
92                 data = new MapNode[nodecount];
93                 for (u32 i = 0; i < nodecount; i++)
94                         data[i] = MapNode(CONTENT_IGNORE);
95
96                 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_REALLOCATE);
97         }
98
99         MapNode* getData()
100         {
101                 return data;
102         }
103
104         ////
105         //// Modification tracking methods
106         ////
107         void raiseModified(u32 mod, u32 reason=MOD_REASON_UNKNOWN)
108         {
109                 if (mod > m_modified) {
110                         m_modified = mod;
111                         m_modified_reason = reason;
112                         if (m_modified >= MOD_STATE_WRITE_AT_UNLOAD)
113                                 m_disk_timestamp = m_timestamp;
114                 } else if (mod == m_modified) {
115                         m_modified_reason |= reason;
116                 }
117                 if (mod == MOD_STATE_WRITE_NEEDED)
118                         contents_cached = false;
119         }
120
121         inline u32 getModified()
122         {
123                 return m_modified;
124         }
125
126         inline u32 getModifiedReason()
127         {
128                 return m_modified_reason;
129         }
130
131         std::string getModifiedReasonString();
132
133         inline void resetModified()
134         {
135                 m_modified = MOD_STATE_CLEAN;
136                 m_modified_reason = 0;
137         }
138
139         ////
140         //// Flags
141         ////
142
143         inline bool isDummy() const
144         {
145                 return !data;
146         }
147
148         inline void unDummify()
149         {
150                 assert(isDummy()); // Pre-condition
151                 reallocate();
152         }
153
154         // is_underground getter/setter
155         inline bool getIsUnderground()
156         {
157                 return is_underground;
158         }
159
160         inline void setIsUnderground(bool a_is_underground)
161         {
162                 is_underground = a_is_underground;
163                 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_IS_UNDERGROUND);
164         }
165
166         inline void setLightingComplete(u16 newflags)
167         {
168                 if (newflags != m_lighting_complete) {
169                         m_lighting_complete = newflags;
170                         raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_LIGHTING_COMPLETE);
171                 }
172         }
173
174         inline u16 getLightingComplete()
175         {
176                 return m_lighting_complete;
177         }
178
179         inline void setLightingComplete(LightBank bank, u8 direction,
180                 bool is_complete)
181         {
182                 assert(direction >= 0 && direction <= 5);
183                 if (bank == LIGHTBANK_NIGHT) {
184                         direction += 6;
185                 }
186                 u16 newflags = m_lighting_complete;
187                 if (is_complete) {
188                         newflags |= 1 << direction;
189                 } else {
190                         newflags &= ~(1 << direction);
191                 }
192                 setLightingComplete(newflags);
193         }
194
195         inline bool isLightingComplete(LightBank bank, u8 direction)
196         {
197                 assert(direction >= 0 && direction <= 5);
198                 if (bank == LIGHTBANK_NIGHT) {
199                         direction += 6;
200                 }
201                 return (m_lighting_complete & (1 << direction)) != 0;
202         }
203
204         inline bool isGenerated()
205         {
206                 return m_generated;
207         }
208
209         inline void setGenerated(bool b)
210         {
211                 if (b != m_generated) {
212                         raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_GENERATED);
213                         m_generated = b;
214                 }
215         }
216
217         ////
218         //// Position stuff
219         ////
220
221         inline v3s16 getPos()
222         {
223                 return m_pos;
224         }
225
226         inline v3s16 getPosRelative()
227         {
228                 return m_pos_relative;
229         }
230
231         inline core::aabbox3d<s16> getBox()
232         {
233                 return core::aabbox3d<s16>(getPosRelative(),
234                                 getPosRelative()
235                                 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
236                                 - v3s16(1,1,1));
237         }
238
239         ////
240         //// Regular MapNode get-setters
241         ////
242
243         inline bool isValidPosition(s16 x, s16 y, s16 z)
244         {
245                 return data
246                         && x >= 0 && x < MAP_BLOCKSIZE
247                         && y >= 0 && y < MAP_BLOCKSIZE
248                         && z >= 0 && z < MAP_BLOCKSIZE;
249         }
250
251         inline bool isValidPosition(v3s16 p)
252         {
253                 return isValidPosition(p.X, p.Y, p.Z);
254         }
255
256         inline MapNode getNode(s16 x, s16 y, s16 z, bool *valid_position)
257         {
258                 *valid_position = isValidPosition(x, y, z);
259
260                 if (!*valid_position)
261                         return {CONTENT_IGNORE};
262
263                 return data[z * zstride + y * ystride + x];
264         }
265
266         inline MapNode getNode(v3s16 p, bool *valid_position)
267         {
268                 return getNode(p.X, p.Y, p.Z, valid_position);
269         }
270
271         inline MapNode getNodeNoEx(v3s16 p)
272         {
273                 bool is_valid;
274                 return getNode(p.X, p.Y, p.Z, &is_valid);
275         }
276
277         inline void setNode(s16 x, s16 y, s16 z, MapNode & n)
278         {
279                 if (!isValidPosition(x, y, z))
280                         throw InvalidPositionException();
281
282                 data[z * zstride + y * ystride + x] = n;
283                 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_NODE);
284         }
285
286         inline void setNode(v3s16 p, MapNode & n)
287         {
288                 setNode(p.X, p.Y, p.Z, n);
289         }
290
291         ////
292         //// Non-checking variants of the above
293         ////
294
295         inline MapNode getNodeNoCheck(s16 x, s16 y, s16 z, bool *valid_position)
296         {
297                 *valid_position = data != nullptr;
298                 if (!*valid_position)
299                         return {CONTENT_IGNORE};
300
301                 return data[z * zstride + y * ystride + x];
302         }
303
304         inline MapNode getNodeNoCheck(v3s16 p, bool *valid_position)
305         {
306                 return getNodeNoCheck(p.X, p.Y, p.Z, valid_position);
307         }
308
309         ////
310         //// Non-checking, unsafe variants of the above
311         //// MapBlock must be loaded by another function in the same scope/function
312         //// Caller must ensure that this is not a dummy block (by calling isDummy())
313         ////
314
315         inline const MapNode &getNodeUnsafe(s16 x, s16 y, s16 z)
316         {
317                 return data[z * zstride + y * ystride + x];
318         }
319
320         inline const MapNode &getNodeUnsafe(v3s16 &p)
321         {
322                 return getNodeUnsafe(p.X, p.Y, p.Z);
323         }
324
325         inline void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
326         {
327                 if (!data)
328                         throw InvalidPositionException();
329
330                 data[z * zstride + y * ystride + x] = n;
331                 raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_NODE_NO_CHECK);
332         }
333
334         inline void setNodeNoCheck(v3s16 p, MapNode & n)
335         {
336                 setNodeNoCheck(p.X, p.Y, p.Z, n);
337         }
338
339         // These functions consult the parent container if the position
340         // is not valid on this MapBlock.
341         bool isValidPositionParent(v3s16 p);
342         MapNode getNodeParent(v3s16 p, bool *is_valid_position = NULL);
343
344         // Copies data to VoxelManipulator to getPosRelative()
345         void copyTo(VoxelManipulator &dst);
346
347         // Copies data from VoxelManipulator getPosRelative()
348         void copyFrom(VoxelManipulator &dst);
349
350         // Update day-night lighting difference flag.
351         // Sets m_day_night_differs to appropriate value.
352         // These methods don't care about neighboring blocks.
353         void actuallyUpdateDayNightDiff();
354
355         // Call this to schedule what the previous function does to be done
356         // when the value is actually needed.
357         void expireDayNightDiff();
358
359         inline bool getDayNightDiff()
360         {
361                 if (m_day_night_differs_expired)
362                         actuallyUpdateDayNightDiff();
363                 return m_day_night_differs;
364         }
365
366         ////
367         //// Timestamp (see m_timestamp)
368         ////
369
370         // NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
371
372         inline void setTimestamp(u32 time)
373         {
374                 m_timestamp = time;
375                 raiseModified(MOD_STATE_WRITE_AT_UNLOAD, MOD_REASON_SET_TIMESTAMP);
376         }
377
378         inline void setTimestampNoChangedFlag(u32 time)
379         {
380                 m_timestamp = time;
381         }
382
383         inline u32 getTimestamp()
384         {
385                 return m_timestamp;
386         }
387
388         inline u32 getDiskTimestamp()
389         {
390                 return m_disk_timestamp;
391         }
392
393         ////
394         //// Usage timer (see m_usage_timer)
395         ////
396
397         inline void resetUsageTimer()
398         {
399                 m_usage_timer = 0;
400         }
401
402         inline void incrementUsageTimer(float dtime)
403         {
404                 m_usage_timer += dtime;
405         }
406
407         inline float getUsageTimer()
408         {
409                 return m_usage_timer;
410         }
411
412         ////
413         //// Reference counting (see m_refcount)
414         ////
415
416         inline void refGrab()
417         {
418                 m_refcount++;
419         }
420
421         inline void refDrop()
422         {
423                 m_refcount--;
424         }
425
426         inline int refGet()
427         {
428                 return m_refcount;
429         }
430
431         ////
432         //// Node Timers
433         ////
434
435         inline NodeTimer getNodeTimer(const v3s16 &p)
436         {
437                 return m_node_timers.get(p);
438         }
439
440         inline void removeNodeTimer(const v3s16 &p)
441         {
442                 m_node_timers.remove(p);
443         }
444
445         inline void setNodeTimer(const NodeTimer &t)
446         {
447                 m_node_timers.set(t);
448         }
449
450         inline void clearNodeTimers()
451         {
452                 m_node_timers.clear();
453         }
454
455         ////
456         //// Serialization
457         ///
458
459         // These don't write or read version by itself
460         // Set disk to true for on-disk format, false for over-the-network format
461         // Precondition: version >= SER_FMT_VER_LOWEST_WRITE
462         void serialize(std::ostream &result, u8 version, bool disk, int compression_level);
463         // If disk == true: In addition to doing other things, will add
464         // unknown blocks from id-name mapping to wndef
465         void deSerialize(std::istream &is, u8 version, bool disk);
466
467         void serializeNetworkSpecific(std::ostream &os);
468         void deSerializeNetworkSpecific(std::istream &is);
469 private:
470         /*
471                 Private methods
472         */
473
474         void deSerialize_pre22(std::istream &is, u8 version, bool disk);
475
476         /*
477                 Used only internally, because changes can't be tracked
478         */
479
480         inline MapNode &getNodeRef(s16 x, s16 y, s16 z)
481         {
482                 if (!isValidPosition(x, y, z))
483                         throw InvalidPositionException();
484
485                 return data[z * zstride + y * ystride + x];
486         }
487
488         inline MapNode &getNodeRef(v3s16 &p)
489         {
490                 return getNodeRef(p.X, p.Y, p.Z);
491         }
492
493 public:
494         /*
495                 Public member variables
496         */
497
498 #ifndef SERVER // Only on client
499         MapBlockMesh *mesh = nullptr;
500 #endif
501
502         NodeMetadataList m_node_metadata;
503         NodeTimerList m_node_timers;
504         StaticObjectList m_static_objects;
505
506         static const u32 ystride = MAP_BLOCKSIZE;
507         static const u32 zstride = MAP_BLOCKSIZE * MAP_BLOCKSIZE;
508
509         static const u32 nodecount = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
510
511         //// ABM optimizations ////
512         // Cache of content types
513         std::unordered_set<content_t> contents;
514         // True if content types are cached
515         bool contents_cached = false;
516         // True if we never want to cache content types for this block
517         bool do_not_cache_contents = false;
518
519 private:
520         /*
521                 Private member variables
522         */
523
524         // NOTE: Lots of things rely on this being the Map
525         Map *m_parent;
526         // Position in blocks on parent
527         v3s16 m_pos;
528
529         /* This is the precalculated m_pos_relative value
530         * This caches the value, improving performance by removing 3 s16 multiplications
531         * at runtime on each getPosRelative call
532         * For a 5 minutes runtime with valgrind this removes 3 * 19M s16 multiplications
533         * The gain can be estimated in Release Build to 3 * 100M multiply operations for 5 mins
534         */
535         v3s16 m_pos_relative;
536
537         IGameDef *m_gamedef;
538
539         /*
540                 If NULL, block is a dummy block.
541                 Dummy blocks are used for caching not-found-on-disk blocks.
542         */
543         MapNode *data = nullptr;
544
545         /*
546                 - On the server, this is used for telling whether the
547                   block has been modified from the one on disk.
548                 - On the client, this is used for nothing.
549         */
550         u32 m_modified = MOD_STATE_WRITE_NEEDED;
551         u32 m_modified_reason = MOD_REASON_INITIAL;
552
553         /*
554                 When propagating sunlight and the above block doesn't exist,
555                 sunlight is assumed if this is false.
556
557                 In practice this is set to true if the block is completely
558                 undeground with nothing visible above the ground except
559                 caves.
560         */
561         bool is_underground = false;
562
563         /*!
564          * Each bit indicates if light spreading was finished
565          * in a direction. (Because the neighbor could also be unloaded.)
566          * Bits (most significant first):
567          * nothing,  nothing,  nothing,  nothing,
568          * night X-, night Y-, night Z-, night Z+, night Y+, night X+,
569          * day X-,   day Y-,   day Z-,   day Z+,   day Y+,   day X+.
570         */
571         u16 m_lighting_complete = 0xFFFF;
572
573         // Whether day and night lighting differs
574         bool m_day_night_differs = false;
575         bool m_day_night_differs_expired = true;
576
577         bool m_generated = false;
578
579         /*
580                 When block is removed from active blocks, this is set to gametime.
581                 Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
582         */
583         u32 m_timestamp = BLOCK_TIMESTAMP_UNDEFINED;
584         // The on-disk (or to-be on-disk) timestamp value
585         u32 m_disk_timestamp = BLOCK_TIMESTAMP_UNDEFINED;
586
587         /*
588                 When the block is accessed, this is set to 0.
589                 Map will unload the block when this reaches a timeout.
590         */
591         float m_usage_timer = 0;
592
593         /*
594                 Reference count; currently used for determining if this block is in
595                 the list of blocks to be drawn.
596         */
597         int m_refcount = 0;
598 };
599
600 typedef std::vector<MapBlock*> MapBlockVect;
601
602 inline bool objectpos_over_limit(v3f p)
603 {
604         const float max_limit_bs = (MAX_MAP_GENERATION_LIMIT + 0.5f) * BS;
605         return p.X < -max_limit_bs ||
606                 p.X >  max_limit_bs ||
607                 p.Y < -max_limit_bs ||
608                 p.Y >  max_limit_bs ||
609                 p.Z < -max_limit_bs ||
610                 p.Z >  max_limit_bs;
611 }
612
613 inline bool blockpos_over_max_limit(v3s16 p)
614 {
615         const s16 max_limit_bp = MAX_MAP_GENERATION_LIMIT / MAP_BLOCKSIZE;
616         return p.X < -max_limit_bp ||
617                 p.X >  max_limit_bp ||
618                 p.Y < -max_limit_bp ||
619                 p.Y >  max_limit_bp ||
620                 p.Z < -max_limit_bp ||
621                 p.Z >  max_limit_bp;
622 }
623
624 /*
625         Returns the position of the block where the node is located
626 */
627 inline v3s16 getNodeBlockPos(const v3s16 &p)
628 {
629         return getContainerPos(p, MAP_BLOCKSIZE);
630 }
631
632 inline void getNodeBlockPosWithOffset(const v3s16 &p, v3s16 &block, v3s16 &offset)
633 {
634         getContainerPosWithOffset(p, MAP_BLOCKSIZE, block, offset);
635 }
636
637 /*
638         Get a quick string to describe what a block actually contains
639 */
640 std::string analyze_block(MapBlock *block);