Reduced server CPU usage on NodeMetadata step()s. Also furnace now cooks while no...
[oweals/minetest.git] / src / map.h
1 /*
2 Minetest-c55
3 Copyright (C) 2010-2011 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 MAP_HEADER
21 #define MAP_HEADER
22
23 #include <jmutex.h>
24 #include <jthread.h>
25 #include <iostream>
26
27 #ifdef _WIN32
28         #include <windows.h>
29         #define sleep_s(x) Sleep((x*1000))
30 #else
31         #include <unistd.h>
32         #define sleep_s(x) sleep(x)
33 #endif
34
35 #include "common_irrlicht.h"
36 #include "mapnode.h"
37 #include "mapblock.h"
38 #include "mapsector.h"
39 #include "constants.h"
40 #include "voxel.h"
41 #include "mapchunk.h"
42 #include "nodemetadata.h"
43
44 #define MAPTYPE_BASE 0
45 #define MAPTYPE_SERVER 1
46 #define MAPTYPE_CLIENT 2
47
48 enum MapEditEventType{
49         // Node added (changed from air or something else to something)
50         MEET_ADDNODE,
51         // Node removed (changed to air)
52         MEET_REMOVENODE,
53         // Node metadata of block changed (not knowing which node exactly)
54         // p stores block coordinate
55         MEET_BLOCK_NODE_METADATA_CHANGED,
56         // Anything else
57         MEET_OTHER
58 };
59
60 struct MapEditEvent
61 {
62         MapEditEventType type;
63         v3s16 p;
64         MapNode n;
65         core::map<v3s16, bool> modified_blocks;
66         u16 already_known_by_peer;
67
68         MapEditEvent():
69                 type(MEET_OTHER),
70                 already_known_by_peer(0)
71         {
72         }
73         
74         MapEditEvent * clone()
75         {
76                 MapEditEvent *event = new MapEditEvent();
77                 event->type = type;
78                 event->p = p;
79                 event->n = n;
80                 for(core::map<v3s16, bool>::Iterator
81                                 i = modified_blocks.getIterator();
82                                 i.atEnd()==false; i++)
83                 {
84                         v3s16 p = i.getNode()->getKey();
85                         bool v = i.getNode()->getValue();
86                         event->modified_blocks.insert(p, v);
87                 }
88                 return event;
89         }
90 };
91
92 class MapEventReceiver
93 {
94 public:
95         // event shall be deleted by caller after the call.
96         virtual void onMapEditEvent(MapEditEvent *event) = 0;
97 };
98
99 class Map : public NodeContainer
100 {
101 public:
102
103         Map(std::ostream &dout);
104         virtual ~Map();
105
106         virtual u16 nodeContainerId() const
107         {
108                 return NODECONTAINER_ID_MAP;
109         }
110
111         virtual s32 mapType() const
112         {
113                 return MAPTYPE_BASE;
114         }
115         
116         /*
117                 Drop (client) or delete (server) the map.
118         */
119         virtual void drop()
120         {
121                 delete this;
122         }
123
124         void addEventReceiver(MapEventReceiver *event_receiver);
125         void removeEventReceiver(MapEventReceiver *event_receiver);
126         // event shall be deleted by caller after the call.
127         void dispatchEvent(MapEditEvent *event);
128
129         // On failure returns NULL
130         MapSector * getSectorNoGenerateNoExNoLock(v2s16 p2d);
131         // On failure returns NULL
132         MapSector * getSectorNoGenerateNoEx(v2s16 p2d);
133         // On failure throws InvalidPositionException
134         MapSector * getSectorNoGenerate(v2s16 p2d);
135         // Gets an existing sector or creates an empty one
136         //MapSector * getSectorCreate(v2s16 p2d);
137
138         /*
139                 This is overloaded by ClientMap and ServerMap to allow
140                 their differing fetch methods.
141         */
142         virtual MapSector * emergeSector(v2s16 p){ return NULL; }
143         virtual MapSector * emergeSector(v2s16 p,
144                         core::map<v3s16, MapBlock*> &changed_blocks){ return NULL; }
145
146         // Returns InvalidPositionException if not found
147         MapBlock * getBlockNoCreate(v3s16 p);
148         // Returns NULL if not found
149         MapBlock * getBlockNoCreateNoEx(v3s16 p);
150         // Gets an existing block or creates an empty one
151         //MapBlock * getBlockCreate(v3s16 p);
152         
153         // Returns InvalidPositionException if not found
154         bool isNodeUnderground(v3s16 p);
155         
156         // virtual from NodeContainer
157         bool isValidPosition(v3s16 p)
158         {
159                 v3s16 blockpos = getNodeBlockPos(p);
160                 MapBlock *blockref;
161                 try{
162                         blockref = getBlockNoCreate(blockpos);
163                 }
164                 catch(InvalidPositionException &e)
165                 {
166                         return false;
167                 }
168                 return true;
169                 /*v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
170                 bool is_valid = blockref->isValidPosition(relpos);
171                 return is_valid;*/
172         }
173         
174         // virtual from NodeContainer
175         // throws InvalidPositionException if not found
176         MapNode getNode(v3s16 p)
177         {
178                 v3s16 blockpos = getNodeBlockPos(p);
179                 MapBlock * blockref = getBlockNoCreate(blockpos);
180                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
181
182                 return blockref->getNodeNoCheck(relpos);
183         }
184
185         // virtual from NodeContainer
186         // throws InvalidPositionException if not found
187         void setNode(v3s16 p, MapNode & n)
188         {
189                 v3s16 blockpos = getNodeBlockPos(p);
190                 MapBlock * blockref = getBlockNoCreate(blockpos);
191                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
192                 blockref->setNodeNoCheck(relpos, n);
193         }
194         
195         // Returns a CONTENT_IGNORE node if not found
196         MapNode getNodeNoEx(v3s16 p)
197         {
198                 try{
199                         v3s16 blockpos = getNodeBlockPos(p);
200                         MapBlock * blockref = getBlockNoCreate(blockpos);
201                         v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
202
203                         return blockref->getNodeNoCheck(relpos);
204                 }
205                 catch(InvalidPositionException &e)
206                 {
207                         return MapNode(CONTENT_IGNORE);
208                 }
209         }
210
211         void unspreadLight(enum LightBank bank,
212                         core::map<v3s16, u8> & from_nodes,
213                         core::map<v3s16, bool> & light_sources,
214                         core::map<v3s16, MapBlock*> & modified_blocks);
215
216         void unLightNeighbors(enum LightBank bank,
217                         v3s16 pos, u8 lightwas,
218                         core::map<v3s16, bool> & light_sources,
219                         core::map<v3s16, MapBlock*> & modified_blocks);
220         
221         void spreadLight(enum LightBank bank,
222                         core::map<v3s16, bool> & from_nodes,
223                         core::map<v3s16, MapBlock*> & modified_blocks);
224         
225         void lightNeighbors(enum LightBank bank,
226                         v3s16 pos,
227                         core::map<v3s16, MapBlock*> & modified_blocks);
228
229         v3s16 getBrightestNeighbour(enum LightBank bank, v3s16 p);
230
231         s16 propagateSunlight(v3s16 start,
232                         core::map<v3s16, MapBlock*> & modified_blocks);
233         
234         void updateLighting(enum LightBank bank,
235                         core::map<v3s16, MapBlock*>  & a_blocks,
236                         core::map<v3s16, MapBlock*> & modified_blocks);
237                         
238         void updateLighting(core::map<v3s16, MapBlock*>  & a_blocks,
239                         core::map<v3s16, MapBlock*> & modified_blocks);
240                         
241         /*
242                 These handle lighting but not faces.
243         */
244         void addNodeAndUpdate(v3s16 p, MapNode n,
245                         core::map<v3s16, MapBlock*> &modified_blocks);
246         void removeNodeAndUpdate(v3s16 p,
247                         core::map<v3s16, MapBlock*> &modified_blocks);
248
249         /*
250                 Wrappers for the latter ones.
251                 These emit events.
252                 Return true if succeeded, false if not.
253         */
254         bool addNodeWithEvent(v3s16 p, MapNode n);
255         bool removeNodeWithEvent(v3s16 p);
256         
257         /*
258                 Takes the blocks at the edges into account
259         */
260         bool dayNightDiffed(v3s16 blockpos);
261
262         //core::aabbox3d<s16> getDisplayedBlockArea();
263
264         //bool updateChangedVisibleArea();
265         
266         virtual void save(bool only_changed){assert(0);};
267
268         /*
269                 Updates usage timers
270         */
271         void timerUpdate(float dtime);
272         
273         // Takes cache into account
274         // sector mutex should be locked when calling
275         void deleteSectors(core::list<v2s16> &list, bool only_blocks);
276         
277         // Returns count of deleted sectors
278         u32 deleteUnusedSectors(float timeout, bool only_blocks=false,
279                         core::list<v3s16> *deleted_blocks=NULL);
280
281         // For debug printing
282         virtual void PrintInfo(std::ostream &out);
283         
284         void transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks);
285
286         /*
287                 Node metadata
288                 These are basically coordinate wrappers to MapBlock
289         */
290         
291         NodeMetadata* getNodeMetadata(v3s16 p);
292         void setNodeMetadata(v3s16 p, NodeMetadata *meta);
293         void removeNodeMetadata(v3s16 p);
294         void nodeMetadataStep(float dtime,
295                         core::map<v3s16, MapBlock*> &changed_blocks);
296         
297         /*
298                 Misc.
299         */
300         core::map<v2s16, MapSector*> *getSectorsPtr(){return &m_sectors;}
301
302         /*
303                 Variables
304         */
305         
306 protected:
307
308         std::ostream &m_dout;
309
310         core::map<MapEventReceiver*, bool> m_event_receivers;
311         
312         core::map<v2s16, MapSector*> m_sectors;
313         //JMutex m_sector_mutex;
314
315         // Be sure to set this to NULL when the cached sector is deleted 
316         MapSector *m_sector_cache;
317         v2s16 m_sector_cache_p;
318
319         // Queued transforming water nodes
320         UniqueQueue<v3s16> m_transforming_liquid;
321 };
322
323 /*
324         ServerMap
325
326         This is the only map class that is able to generate map.
327 */
328
329 struct ChunkMakeData;
330
331 class ServerMap : public Map
332 {
333 public:
334         /*
335                 savedir: directory to which map data should be saved
336         */
337         ServerMap(std::string savedir);
338         ~ServerMap();
339
340         s32 mapType() const
341         {
342                 return MAPTYPE_SERVER;
343         }
344
345         /*
346                 Map generation
347         */
348         
349         // Returns the position of the chunk where the sector is in
350         v2s16 sector_to_chunk(v2s16 sectorpos)
351         {
352                 if(m_chunksize == 0)
353                         return v2s16(0,0);
354                 sectorpos.X += m_chunksize / 2;
355                 sectorpos.Y += m_chunksize / 2;
356                 v2s16 chunkpos = getContainerPos(sectorpos, m_chunksize);
357                 return chunkpos;
358         }
359         
360         // Returns the position of the (0,0) sector of the chunk
361         v2s16 chunk_to_sector(v2s16 chunkpos)
362         {
363                 if(m_chunksize == 0)
364                         return v2s16(0,0);
365                 v2s16 sectorpos(
366                         chunkpos.X * m_chunksize,
367                         chunkpos.Y * m_chunksize
368                 );
369                 sectorpos.X -= m_chunksize / 2;
370                 sectorpos.Y -= m_chunksize / 2;
371                 return sectorpos;
372         }
373
374         /*
375                 Get a chunk.
376         */
377         MapChunk *getChunk(v2s16 chunkpos)
378         {
379                 core::map<v2s16, MapChunk*>::Node *n;
380                 n = m_chunks.find(chunkpos);
381                 if(n == NULL)
382                         return NULL;
383                 return n->getValue();
384         }
385
386         /*
387                 True if the chunk and its neighbors are fully generated.
388                 It means the chunk will not be touched in the future by the
389                 generator. If false, generateChunk will make it true.
390         */
391         bool chunkNonVolatile(v2s16 chunkpos)
392         {
393                 if(m_chunksize == 0)
394                         return true;
395                 
396                 /*for(s16 x=-1; x<=1; x++)
397                 for(s16 y=-1; y<=1; y++)*/
398                 s16 x=0;
399                 s16 y=0;
400                 {
401                         v2s16 chunkpos0 = chunkpos + v2s16(x,y);
402                         MapChunk *chunk = getChunk(chunkpos);
403                         if(chunk == NULL)
404                                 return false;
405                         if(chunk->getGenLevel() != GENERATED_FULLY)
406                                 return false;
407                 }
408                 return true;
409         }
410         
411         /*
412                 Returns true if any chunk is marked as modified
413         */
414         bool anyChunkModified()
415         {
416                 for(core::map<v2s16, MapChunk*>::Iterator
417                                 i = m_chunks.getIterator();
418                                 i.atEnd()==false; i++)
419                 {
420                         v2s16 p = i.getNode()->getKey();
421                         MapChunk *chunk = i.getNode()->getValue();
422                         if(chunk->isModified())
423                                 return true;
424                 }
425                 return false;
426         }
427
428         void setChunksNonModified()
429         {
430                 for(core::map<v2s16, MapChunk*>::Iterator
431                                 i = m_chunks.getIterator();
432                                 i.atEnd()==false; i++)
433                 {
434                         v2s16 p = i.getNode()->getKey();
435                         MapChunk *chunk = i.getNode()->getValue();
436                         chunk->setModified(false);
437                 }
438         }
439
440         /*
441                 Chunks are generated by using these and makeChunk().
442         */
443         void initChunkMake(ChunkMakeData &data, v2s16 chunkpos);
444         MapChunk* finishChunkMake(ChunkMakeData &data,
445                         core::map<v3s16, MapBlock*> &changed_blocks);
446
447         /*
448                 Generate a chunk.
449
450                 All chunks touching this one can be altered also.
451         */
452         /*MapChunk* generateChunkRaw(v2s16 chunkpos,
453                         core::map<v3s16, MapBlock*> &changed_blocks,
454                         bool force=false);*/
455         
456         /*
457                 Generate a chunk and its neighbors so that it won't be touched
458                 anymore.
459         */
460         /*MapChunk* generateChunk(v2s16 chunkpos,
461                         core::map<v3s16, MapBlock*> &changed_blocks);*/
462         
463         /*
464                 Generate a sector.
465                 
466                 This is mainly called by generateChunkRaw.
467         */
468         //ServerMapSector * generateSector(v2s16 p);
469         
470         /*
471                 Get a sector from somewhere.
472                 - Check memory
473                 - Check disk (loads blocks also)
474                 - Create blank one
475         */
476         ServerMapSector * createSector(v2s16 p);
477
478         /*
479                 Get a sector from somewhere.
480                 - Check memory
481                 - Check disk (loads blocks also)
482                 - Generate chunk
483         */
484         /*MapSector * emergeSector(v2s16 p,
485                         core::map<v3s16, MapBlock*> &changed_blocks);*/
486         
487         /*MapSector * emergeSector(v2s16 p)
488         {
489                 core::map<v3s16, MapBlock*> changed_blocks;
490                 return emergeSector(p, changed_blocks);
491         }*/
492
493         MapBlock * generateBlock(
494                         v3s16 p,
495                         MapBlock *original_dummy,
496                         ServerMapSector *sector,
497                         core::map<v3s16, MapBlock*> &changed_blocks,
498                         core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
499         );
500         
501         /*
502                 Get a block from somewhere.
503                 - Memory
504                 - Create blank
505         */
506         MapBlock * createBlock(v3s16 p);
507         
508         /*
509                 only_from_disk, changed_blocks and lighting_invalidated_blocks
510                 are not properly used by the new map generator.
511         */
512         MapBlock * emergeBlock(
513                         v3s16 p,
514                         bool only_from_disk,
515                         core::map<v3s16, MapBlock*> &changed_blocks,
516                         core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
517         );
518
519 #if 0
520         /*
521                 Forcefully get a block from somewhere.
522
523                 Exceptions:
524                 - InvalidPositionException: possible if only_from_disk==true
525                 
526                 changed_blocks:
527                 - All already existing blocks that were modified are added.
528                         - If found on disk, nothing will be added.
529                         - If generated, the new block will not be included.
530
531                 lighting_invalidated_blocks:
532                 - All blocks that have heavy-to-calculate lighting changes
533                   are added.
534                         - updateLighting() should be called for these.
535                 
536                 - A block that is in changed_blocks may not be in
537                   lighting_invalidated_blocks.
538         */
539         MapBlock * emergeBlock(
540                         v3s16 p,
541                         bool only_from_disk,
542                         core::map<v3s16, MapBlock*> &changed_blocks,
543                         core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
544         );
545 #endif
546         
547         // Helper for placing objects on ground level
548         s16 findGroundLevel(v2s16 p2d);
549
550         /*
551                 Misc. helper functions for fiddling with directory and file
552                 names when saving
553         */
554         void createDirs(std::string path);
555         // returns something like "map/sectors/xxxxxxxx"
556         std::string getSectorDir(v2s16 pos, int layout = 2);
557         // dirname: final directory name
558         v2s16 getSectorPos(std::string dirname);
559         v3s16 getBlockPos(std::string sectordir, std::string blockfile);
560
561         void save(bool only_changed);
562         //void loadAll();
563         
564         // Saves map seed and possibly other stuff
565         void saveMapMeta();
566         void loadMapMeta();
567         
568         void saveChunkMeta();
569         void loadChunkMeta();
570         
571         // The sector mutex should be locked when calling most of these
572         
573         // This only saves sector-specific data such as the heightmap
574         // (no MapBlocks)
575         // DEPRECATED? Sectors have no metadata anymore.
576         void saveSectorMeta(ServerMapSector *sector);
577         MapSector* loadSectorMeta(std::string dirname, bool save_after_load);
578         
579         // Full load of a sector including all blocks.
580         // returns true on success, false on failure.
581         bool loadSectorFull(v2s16 p2d);
582         // If sector is not found in memory, try to load it from disk.
583         // Returns true if sector now resides in memory
584         //bool deFlushSector(v2s16 p2d);
585         
586         void saveBlock(MapBlock *block);
587         // This will generate a sector with getSector if not found.
588         void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load=false);
589
590         // For debug printing
591         virtual void PrintInfo(std::ostream &out);
592
593         bool isSavingEnabled(){ return m_map_saving_enabled; }
594
595 private:
596         // Seed used for all kinds of randomness
597         u64 m_seed;
598
599         std::string m_savedir;
600         bool m_map_saving_enabled;
601
602         // Chunk size in MapSectors
603         // If 0, chunks are disabled.
604         s16 m_chunksize;
605         // Chunks
606         core::map<v2s16, MapChunk*> m_chunks;
607
608         /*
609                 Metadata is re-written on disk only if this is true.
610                 This is reset to false when written on disk.
611         */
612         bool m_map_metadata_changed;
613 };
614
615 /*
616         ClientMap stuff
617 */
618
619 #ifndef SERVER
620
621 struct MapDrawControl
622 {
623         MapDrawControl():
624                 range_all(false),
625                 wanted_range(50),
626                 wanted_max_blocks(0),
627                 wanted_min_range(0),
628                 blocks_drawn(0),
629                 blocks_would_have_drawn(0)
630         {
631         }
632         // Overrides limits by drawing everything
633         bool range_all;
634         // Wanted drawing range
635         float wanted_range;
636         // Maximum number of blocks to draw
637         u32 wanted_max_blocks;
638         // Blocks in this range are drawn regardless of number of blocks drawn
639         float wanted_min_range;
640         // Number of blocks rendered is written here by the renderer
641         u32 blocks_drawn;
642         // Number of blocks that would have been drawn in wanted_range
643         u32 blocks_would_have_drawn;
644 };
645
646 class Client;
647
648 /*
649         ClientMap
650         
651         This is the only map class that is able to render itself on screen.
652 */
653
654 class ClientMap : public Map, public scene::ISceneNode
655 {
656 public:
657         ClientMap(
658                         Client *client,
659                         MapDrawControl &control,
660                         scene::ISceneNode* parent,
661                         scene::ISceneManager* mgr,
662                         s32 id
663         );
664
665         ~ClientMap();
666
667         s32 mapType() const
668         {
669                 return MAPTYPE_CLIENT;
670         }
671
672         void drop()
673         {
674                 ISceneNode::drop();
675         }
676
677         void updateCamera(v3f pos, v3f dir)
678         {
679                 JMutexAutoLock lock(m_camera_mutex);
680                 m_camera_position = pos;
681                 m_camera_direction = dir;
682         }
683
684         /*
685                 Forcefully get a sector from somewhere
686         */
687         MapSector * emergeSector(v2s16 p);
688
689         void deSerializeSector(v2s16 p2d, std::istream &is);
690
691         /*
692                 ISceneNode methods
693         */
694
695         virtual void OnRegisterSceneNode();
696
697         virtual void render()
698         {
699                 video::IVideoDriver* driver = SceneManager->getVideoDriver();
700                 driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
701                 renderMap(driver, SceneManager->getSceneNodeRenderPass());
702         }
703         
704         virtual const core::aabbox3d<f32>& getBoundingBox() const
705         {
706                 return m_box;
707         }
708
709         void renderMap(video::IVideoDriver* driver, s32 pass);
710
711         /*
712                 Methods for setting temporary modifications to nodes for
713                 drawing.
714
715                 Returns true if something changed.
716                 
717                 All blocks whose mesh could have been changed are inserted
718                 to affected_blocks.
719         */
720         bool setTempMod(v3s16 p, NodeMod mod,
721                         core::map<v3s16, MapBlock*> *affected_blocks=NULL);
722         bool clearTempMod(v3s16 p,
723                         core::map<v3s16, MapBlock*> *affected_blocks=NULL);
724         // Efficient implementation needs a cache of TempMods
725         //void clearTempMods();
726
727         void expireMeshes(bool only_daynight_diffed);
728         
729         /*
730                 Update the faces of the given block and blocks on the
731                 leading edge.
732         */
733         void updateMeshes(v3s16 blockpos, u32 daynight_ratio);
734         
735         // Update meshes that touch the node
736         //void updateNodeMeshes(v3s16 nodepos, u32 daynight_ratio);
737
738         // For debug printing
739         virtual void PrintInfo(std::ostream &out);
740         
741 private:
742         Client *m_client;
743         
744         core::aabbox3d<f32> m_box;
745         
746         // This is the master heightmap mesh
747         //scene::SMesh *mesh;
748         //JMutex mesh_mutex;
749         
750         MapDrawControl &m_control;
751
752         v3f m_camera_position;
753         v3f m_camera_direction;
754         JMutex m_camera_mutex;
755
756 };
757
758 #endif
759
760 class MapVoxelManipulator : public VoxelManipulator
761 {
762 public:
763         MapVoxelManipulator(Map *map);
764         virtual ~MapVoxelManipulator();
765         
766         virtual void clear()
767         {
768                 VoxelManipulator::clear();
769                 m_loaded_blocks.clear();
770         }
771
772         virtual void emerge(VoxelArea a, s32 caller_id=-1);
773
774         void blitBack(core::map<v3s16, MapBlock*> & modified_blocks);
775
776 protected:
777         Map *m_map;
778         /*
779                 key = blockpos
780                 value = block existed when loaded
781         */
782         core::map<v3s16, bool> m_loaded_blocks;
783 };
784
785 class ManualMapVoxelManipulator : public MapVoxelManipulator
786 {
787 public:
788         ManualMapVoxelManipulator(Map *map);
789         virtual ~ManualMapVoxelManipulator();
790
791         void setMap(Map *map)
792         {m_map = map;}
793         
794         virtual void emerge(VoxelArea a, s32 caller_id=-1);
795
796         void initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max);
797         
798         // This is much faster with big chunks of generated data
799         void blitBackAll(core::map<v3s16, MapBlock*> * modified_blocks);
800
801 protected:
802         bool m_create_area;
803 };
804
805 struct ChunkMakeData
806 {
807         bool no_op;
808         ManualMapVoxelManipulator vmanip;
809         u64 seed;
810         v2s16 chunkpos;
811         s16 y_blocks_min;
812         s16 y_blocks_max;
813         v2s16 sectorpos_base;
814         s16 sectorpos_base_size;
815         v2s16 sectorpos_bigbase;
816         s16 sectorpos_bigbase_size;
817         s16 max_spread_amount;
818         UniqueQueue<v3s16> transforming_liquid;
819
820         ChunkMakeData():
821                 no_op(false),
822                 vmanip(NULL),
823                 seed(0)
824         {}
825 };
826
827 void makeChunk(ChunkMakeData *data);
828
829 #endif
830