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