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