]> git.lizzy.rs Git - minetest.git/blob - src/map.h
Store `MapEditEvent` blocks in a vector (#13071)
[minetest.git] / src / map.h
1 /*
2 Minetest
3 Copyright (C) 2010-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 <iostream>
23 #include <sstream>
24 #include <set>
25 #include <map>
26 #include <list>
27
28 #include "irrlichttypes_bloated.h"
29 #include "mapblock.h"
30 #include "mapnode.h"
31 #include "constants.h"
32 #include "voxel.h"
33 #include "modifiedstate.h"
34 #include "util/container.h"
35 #include "util/metricsbackend.h"
36 #include "util/numeric.h"
37 #include "nodetimer.h"
38 #include "map_settings_manager.h"
39 #include "debug.h"
40
41 class Settings;
42 class MapDatabase;
43 class ClientMap;
44 class MapSector;
45 class ServerMapSector;
46 class MapBlock;
47 class NodeMetadata;
48 class IGameDef;
49 class IRollbackManager;
50 class EmergeManager;
51 class MetricsBackend;
52 class ServerEnvironment;
53 struct BlockMakeData;
54
55 /*
56         MapEditEvent
57 */
58
59 enum MapEditEventType{
60         // Node added (changed from air or something else to something)
61         MEET_ADDNODE,
62         // Node removed (changed to air)
63         MEET_REMOVENODE,
64         // Node swapped (changed without metadata change)
65         MEET_SWAPNODE,
66         // Node metadata changed
67         MEET_BLOCK_NODE_METADATA_CHANGED,
68         // Anything else (modified_blocks are set unsent)
69         MEET_OTHER
70 };
71
72 struct MapEditEvent
73 {
74         MapEditEventType type = MEET_OTHER;
75         v3s16 p;
76         MapNode n = CONTENT_AIR;
77         std::vector<v3s16> modified_blocks; // Represents a set
78         bool is_private_change = false;
79
80         MapEditEvent() = default;
81
82         // Sets the event's position and marks the block as modified.
83         void setPositionModified(v3s16 pos)
84         {
85                 assert(modified_blocks.empty()); // only meant for initialization (once)
86                 p = pos;
87                 modified_blocks.push_back(getNodeBlockPos(pos));
88         }
89
90         void setModifiedBlocks(const std::map<v3s16, MapBlock *> blocks)
91         {
92                 assert(modified_blocks.empty()); // only meant for initialization (once)
93                 modified_blocks.reserve(blocks.size());
94                 for (const auto &block : blocks)
95                         modified_blocks.push_back(block.first);
96         }
97
98         VoxelArea getArea() const
99         {
100                 switch(type){
101                 case MEET_ADDNODE:
102                 case MEET_REMOVENODE:
103                 case MEET_SWAPNODE:
104                 case MEET_BLOCK_NODE_METADATA_CHANGED:
105                         return VoxelArea(p);
106                 case MEET_OTHER:
107                 {
108                         VoxelArea a;
109                         for (v3s16 p : modified_blocks) {
110                                 v3s16 np1 = p*MAP_BLOCKSIZE;
111                                 v3s16 np2 = np1 + v3s16(1,1,1)*MAP_BLOCKSIZE - v3s16(1,1,1);
112                                 a.addPoint(np1);
113                                 a.addPoint(np2);
114                         }
115                         return a;
116                 }
117                 }
118                 return VoxelArea();
119         }
120 };
121
122 class MapEventReceiver
123 {
124 public:
125         // event shall be deleted by caller after the call.
126         virtual void onMapEditEvent(const MapEditEvent &event) = 0;
127 };
128
129 class Map /*: public NodeContainer*/
130 {
131 public:
132
133         Map(IGameDef *gamedef);
134         virtual ~Map();
135         DISABLE_CLASS_COPY(Map);
136
137         /*
138                 Drop (client) or delete (server) the map.
139         */
140         virtual void drop()
141         {
142                 delete this;
143         }
144
145         void addEventReceiver(MapEventReceiver *event_receiver);
146         void removeEventReceiver(MapEventReceiver *event_receiver);
147         // event shall be deleted by caller after the call.
148         void dispatchEvent(const MapEditEvent &event);
149
150         // On failure returns NULL
151         MapSector * getSectorNoGenerateNoLock(v2s16 p2d);
152         // Same as the above (there exists no lock anymore)
153         MapSector * getSectorNoGenerate(v2s16 p2d);
154
155         /*
156                 This is overloaded by ClientMap and ServerMap to allow
157                 their differing fetch methods.
158         */
159         virtual MapSector * emergeSector(v2s16 p){ return NULL; }
160
161         // Returns InvalidPositionException if not found
162         MapBlock * getBlockNoCreate(v3s16 p);
163         // Returns NULL if not found
164         MapBlock * getBlockNoCreateNoEx(v3s16 p);
165
166         /* Server overrides */
167         virtual MapBlock * emergeBlock(v3s16 p, bool create_blank=true)
168         { return getBlockNoCreateNoEx(p); }
169
170         inline const NodeDefManager * getNodeDefManager() { return m_nodedef; }
171
172         bool isValidPosition(v3s16 p);
173
174         // throws InvalidPositionException if not found
175         void setNode(v3s16 p, MapNode n);
176
177         // Returns a CONTENT_IGNORE node if not found
178         // If is_valid_position is not NULL then this will be set to true if the
179         // position is valid, otherwise false
180         MapNode getNode(v3s16 p, bool *is_valid_position = NULL);
181
182         /*
183                 These handle lighting but not faces.
184         */
185         virtual void addNodeAndUpdate(v3s16 p, MapNode n,
186                         std::map<v3s16, MapBlock*> &modified_blocks,
187                         bool remove_metadata = true);
188         void removeNodeAndUpdate(v3s16 p,
189                         std::map<v3s16, MapBlock*> &modified_blocks);
190
191         /*
192                 Wrappers for the latter ones.
193                 These emit events.
194                 Return true if succeeded, false if not.
195         */
196         bool addNodeWithEvent(v3s16 p, MapNode n, bool remove_metadata = true);
197         bool removeNodeWithEvent(v3s16 p);
198
199         // Call these before and after saving of many blocks
200         virtual void beginSave() {}
201         virtual void endSave() {}
202
203         virtual void save(ModifiedState save_level) { FATAL_ERROR("FIXME"); }
204
205         /*
206                 Return true unless the map definitely cannot save blocks.
207         */
208         virtual bool maySaveBlocks() { return true; }
209
210         // Server implements these.
211         // Client leaves them as no-op.
212         virtual bool saveBlock(MapBlock *block) { return false; }
213         virtual bool deleteBlock(v3s16 blockpos) { return false; }
214
215         /*
216                 Updates usage timers and unloads unused blocks and sectors.
217                 Saves modified blocks before unloading if possible.
218         */
219         void timerUpdate(float dtime, float unload_timeout, s32 max_loaded_blocks,
220                         std::vector<v3s16> *unloaded_blocks=NULL);
221
222         /*
223                 Unloads all blocks with a zero refCount().
224                 Saves modified blocks before unloading if possible.
225         */
226         void unloadUnreferencedBlocks(std::vector<v3s16> *unloaded_blocks=NULL);
227
228         // Deletes sectors and their blocks from memory
229         // Takes cache into account
230         // If deleted sector is in sector cache, clears cache
231         void deleteSectors(std::vector<v2s16> &list);
232
233         // For debug printing. Prints "Map: ", "ServerMap: " or "ClientMap: "
234         virtual void PrintInfo(std::ostream &out);
235
236         /*
237                 Node metadata
238                 These are basically coordinate wrappers to MapBlock
239         */
240
241         std::vector<v3s16> findNodesWithMetadata(v3s16 p1, v3s16 p2);
242         NodeMetadata *getNodeMetadata(v3s16 p);
243
244         /**
245          * Sets metadata for a node.
246          * This method sets the metadata for a given node.
247          * On success, it returns @c true and the object pointed to
248          * by @p meta is then managed by the system and should
249          * not be deleted by the caller.
250          *
251          * In case of failure, the method returns @c false and the
252          * caller is still responsible for deleting the object!
253          *
254          * @param p node coordinates
255          * @param meta pointer to @c NodeMetadata object
256          * @return @c true on success, false on failure
257          */
258         bool setNodeMetadata(v3s16 p, NodeMetadata *meta);
259         void removeNodeMetadata(v3s16 p);
260
261         /*
262                 Node Timers
263                 These are basically coordinate wrappers to MapBlock
264         */
265
266         NodeTimer getNodeTimer(v3s16 p);
267         void setNodeTimer(const NodeTimer &t);
268         void removeNodeTimer(v3s16 p);
269
270         /*
271                 Utilities
272         */
273
274         // Iterates through all nodes in the area in an unspecified order.
275         // The given callback takes the position as its first argument and the node
276         // as its second. If it returns false, forEachNodeInArea returns early.
277         template<typename F>
278         void forEachNodeInArea(v3s16 minp, v3s16 maxp, F func)
279         {
280                 v3s16 bpmin = getNodeBlockPos(minp);
281                 v3s16 bpmax = getNodeBlockPos(maxp);
282                 for (s16 bz = bpmin.Z; bz <= bpmax.Z; bz++)
283                 for (s16 bx = bpmin.X; bx <= bpmax.X; bx++)
284                 for (s16 by = bpmin.Y; by <= bpmax.Y; by++) {
285                         // y is iterated innermost to make use of the sector cache.
286                         v3s16 bp(bx, by, bz);
287                         MapBlock *block = getBlockNoCreateNoEx(bp);
288                         v3s16 basep = bp * MAP_BLOCKSIZE;
289                         s16 minx_block = rangelim(minp.X - basep.X, 0, MAP_BLOCKSIZE - 1);
290                         s16 miny_block = rangelim(minp.Y - basep.Y, 0, MAP_BLOCKSIZE - 1);
291                         s16 minz_block = rangelim(minp.Z - basep.Z, 0, MAP_BLOCKSIZE - 1);
292                         s16 maxx_block = rangelim(maxp.X - basep.X, 0, MAP_BLOCKSIZE - 1);
293                         s16 maxy_block = rangelim(maxp.Y - basep.Y, 0, MAP_BLOCKSIZE - 1);
294                         s16 maxz_block = rangelim(maxp.Z - basep.Z, 0, MAP_BLOCKSIZE - 1);
295                         for (s16 z_block = minz_block; z_block <= maxz_block; z_block++)
296                         for (s16 y_block = miny_block; y_block <= maxy_block; y_block++)
297                         for (s16 x_block = minx_block; x_block <= maxx_block; x_block++) {
298                                 v3s16 p = basep + v3s16(x_block, y_block, z_block);
299                                 MapNode n = block ?
300                                                 block->getNodeNoCheck(x_block, y_block, z_block) :
301                                                 MapNode(CONTENT_IGNORE);
302                                 if (!func(p, n))
303                                         return;
304                         }
305                 }
306         }
307
308         bool isBlockOccluded(MapBlock *block, v3s16 cam_pos_nodes);
309 protected:
310         IGameDef *m_gamedef;
311
312         std::set<MapEventReceiver*> m_event_receivers;
313
314         std::unordered_map<v2s16, MapSector*> m_sectors;
315
316         // Be sure to set this to NULL when the cached sector is deleted
317         MapSector *m_sector_cache = nullptr;
318         v2s16 m_sector_cache_p;
319
320         // This stores the properties of the nodes on the map.
321         const NodeDefManager *m_nodedef;
322
323         // Can be implemented by child class
324         virtual void reportMetrics(u64 save_time_us, u32 saved_blocks, u32 all_blocks) {}
325
326         bool determineAdditionalOcclusionCheck(const v3s16 &pos_camera,
327                 const core::aabbox3d<s16> &block_bounds, v3s16 &check);
328         bool isOccluded(const v3s16 &pos_camera, const v3s16 &pos_target,
329                 float step, float stepfac, float start_offset, float end_offset,
330                 u32 needed_count);
331 };
332
333 /*
334         ServerMap
335
336         This is the only map class that is able to generate map.
337 */
338
339 class ServerMap : public Map
340 {
341 public:
342         /*
343                 savedir: directory to which map data should be saved
344         */
345         ServerMap(const std::string &savedir, IGameDef *gamedef, EmergeManager *emerge, MetricsBackend *mb);
346         ~ServerMap();
347
348         /*
349                 Get a sector from somewhere.
350                 - Check memory
351                 - Check disk (doesn't load blocks)
352                 - Create blank one
353         */
354         MapSector *createSector(v2s16 p);
355
356         /*
357                 Blocks are generated by using these and makeBlock().
358         */
359         bool blockpos_over_mapgen_limit(v3s16 p);
360         bool initBlockMake(v3s16 blockpos, BlockMakeData *data);
361         void finishBlockMake(BlockMakeData *data,
362                 std::map<v3s16, MapBlock*> *changed_blocks);
363
364         /*
365                 Get a block from somewhere.
366                 - Memory
367                 - Create blank
368         */
369         MapBlock *createBlock(v3s16 p);
370
371         /*
372                 Forcefully get a block from somewhere.
373                 - Memory
374                 - Load from disk
375                 - Create blank filled with CONTENT_IGNORE
376
377         */
378         MapBlock *emergeBlock(v3s16 p, bool create_blank=true) override;
379
380         /*
381                 Try to get a block.
382                 If it does not exist in memory, add it to the emerge queue.
383                 - Memory
384                 - Emerge Queue (deferred disk or generate)
385         */
386         MapBlock *getBlockOrEmerge(v3s16 p3d);
387
388         bool isBlockInQueue(v3s16 pos);
389
390         void addNodeAndUpdate(v3s16 p, MapNode n,
391                         std::map<v3s16, MapBlock*> &modified_blocks,
392                         bool remove_metadata) override;
393
394         /*
395                 Database functions
396         */
397         static MapDatabase *createDatabase(const std::string &name, const std::string &savedir, Settings &conf);
398
399         // Call these before and after saving of blocks
400         void beginSave() override;
401         void endSave() override;
402
403         void save(ModifiedState save_level) override;
404         void listAllLoadableBlocks(std::vector<v3s16> &dst);
405         void listAllLoadedBlocks(std::vector<v3s16> &dst);
406
407         MapgenParams *getMapgenParams();
408
409         bool saveBlock(MapBlock *block) override;
410         static bool saveBlock(MapBlock *block, MapDatabase *db, int compression_level = -1);
411         MapBlock* loadBlock(v3s16 p);
412         // Database version
413         void loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load=false);
414
415         bool deleteBlock(v3s16 blockpos) override;
416
417         void updateVManip(v3s16 pos);
418
419         // For debug printing
420         void PrintInfo(std::ostream &out) override;
421
422         bool isSavingEnabled(){ return m_map_saving_enabled; }
423
424         u64 getSeed();
425
426         /*!
427          * Fixes lighting in one map block.
428          * May modify other blocks as well, as light can spread
429          * out of the specified block.
430          * Returns false if the block is not generated (so nothing
431          * changed), true otherwise.
432          */
433         bool repairBlockLight(v3s16 blockpos,
434                 std::map<v3s16, MapBlock *> *modified_blocks);
435
436         void transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks,
437                         ServerEnvironment *env);
438
439         void transforming_liquid_add(v3s16 p);
440
441         MapSettingsManager settings_mgr;
442
443 protected:
444
445         void reportMetrics(u64 save_time_us, u32 saved_blocks, u32 all_blocks) override;
446
447 private:
448         friend class LuaVoxelManip;
449
450         // Emerge manager
451         EmergeManager *m_emerge;
452
453         std::string m_savedir;
454         bool m_map_saving_enabled;
455
456         int m_map_compression_level;
457
458         std::set<v3s16> m_chunks_in_progress;
459
460         // Queued transforming water nodes
461         UniqueQueue<v3s16> m_transforming_liquid;
462         f32 m_transforming_liquid_loop_count_multiplier = 1.0f;
463         u32 m_unprocessed_count = 0;
464         u64 m_inc_trending_up_start_time = 0; // milliseconds
465         bool m_queue_size_timer_started = false;
466
467         /*
468                 Metadata is re-written on disk only if this is true.
469                 This is reset to false when written on disk.
470         */
471         bool m_map_metadata_changed = true;
472         MapDatabase *dbase = nullptr;
473         MapDatabase *dbase_ro = nullptr;
474
475         // Map metrics
476         MetricGaugePtr m_loaded_blocks_gauge;
477         MetricCounterPtr m_save_time_counter;
478         MetricCounterPtr m_save_count_counter;
479 };
480
481
482 #define VMANIP_BLOCK_DATA_INEXIST     1
483 #define VMANIP_BLOCK_CONTAINS_CIGNORE 2
484
485 class MMVManip : public VoxelManipulator
486 {
487 public:
488         MMVManip(Map *map);
489         virtual ~MMVManip() = default;
490
491         virtual void clear()
492         {
493                 VoxelManipulator::clear();
494                 m_loaded_blocks.clear();
495         }
496
497         void initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max,
498                 bool load_if_inexistent = true);
499
500         // This is much faster with big chunks of generated data
501         void blitBackAll(std::map<v3s16, MapBlock*> * modified_blocks,
502                 bool overwrite_generated = true);
503
504         /*
505                 Creates a copy of this VManip including contents, the copy will not be
506                 associated with a Map.
507         */
508         MMVManip *clone() const;
509
510         // Reassociates a copied VManip to a map
511         void reparent(Map *map);
512
513         // Is it impossible to call initialEmerge / blitBackAll?
514         inline bool isOrphan() const { return !m_map; }
515
516         bool m_is_dirty = false;
517
518 protected:
519         MMVManip() {};
520
521         // may be null
522         Map *m_map = nullptr;
523         /*
524                 key = blockpos
525                 value = flags describing the block
526         */
527         std::map<v3s16, u8> m_loaded_blocks;
528 };