partly working chunk-based map generator (doesn't save properly, spawn is pretty...
[oweals/minetest.git] / src / mapsector.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010 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 #include "mapsector.h"
21 #include "jmutexautolock.h"
22 #include "client.h"
23 #include "exceptions.h"
24
25 MapSector::MapSector(NodeContainer *parent, v2s16 pos):
26                 differs_from_disk(true),
27                 usage_timer(0.0),
28                 m_parent(parent),
29                 m_pos(pos),
30                 m_block_cache(NULL)
31 {
32         m_mutex.Init();
33         assert(m_mutex.IsInitialized());
34 }
35
36 MapSector::~MapSector()
37 {
38         deleteBlocks();
39 }
40
41 void MapSector::deleteBlocks()
42 {
43         JMutexAutoLock lock(m_mutex);
44
45         // Clear cache
46         m_block_cache = NULL;
47
48         // Delete all
49         core::map<s16, MapBlock*>::Iterator i = m_blocks.getIterator();
50         for(; i.atEnd() == false; i++)
51         {
52                 delete i.getNode()->getValue();
53         }
54
55         // Clear container
56         m_blocks.clear();
57 }
58
59 MapBlock * MapSector::getBlockBuffered(s16 y)
60 {
61         MapBlock *block;
62
63         if(m_block_cache != NULL && y == m_block_cache_y){
64                 return m_block_cache;
65         }
66         
67         // If block doesn't exist, return NULL
68         core::map<s16, MapBlock*>::Node *n = m_blocks.find(y);
69         if(n == NULL)
70         {
71                 block = NULL;
72         }
73         // If block exists, return it
74         else{
75                 block = n->getValue();
76         }
77         
78         // Cache the last result
79         m_block_cache_y = y;
80         m_block_cache = block;
81         
82         return block;
83 }
84
85 MapBlock * MapSector::getBlockNoCreateNoEx(s16 y)
86 {
87         JMutexAutoLock lock(m_mutex);
88         
89         return getBlockBuffered(y);
90 }
91
92 MapBlock * MapSector::getBlockNoCreate(s16 y)
93 {
94         MapBlock *block = getBlockNoCreateNoEx(y);
95
96         if(block == NULL)
97                 throw InvalidPositionException();
98         
99         return block;
100 }
101
102 MapBlock * MapSector::createBlankBlockNoInsert(s16 y)
103 {
104         // There should not be a block at this position
105         if(getBlockBuffered(y) != NULL)
106                 throw AlreadyExistsException("Block already exists");
107
108         v3s16 blockpos_map(m_pos.X, y, m_pos.Y);
109         
110         MapBlock *block = new MapBlock(m_parent, blockpos_map);
111         
112         return block;
113 }
114
115 MapBlock * MapSector::createBlankBlock(s16 y)
116 {
117         JMutexAutoLock lock(m_mutex);
118         
119         MapBlock *block = createBlankBlockNoInsert(y);
120         
121         m_blocks.insert(y, block);
122
123         return block;
124 }
125
126 void MapSector::insertBlock(MapBlock *block)
127 {
128         s16 block_y = block->getPos().Y;
129
130         {
131                 JMutexAutoLock lock(m_mutex);
132
133                 MapBlock *block2 = getBlockBuffered(block_y);
134                 if(block2 != NULL){
135                         throw AlreadyExistsException("Block already exists");
136                 }
137
138                 v2s16 p2d(block->getPos().X, block->getPos().Z);
139                 assert(p2d == m_pos);
140                 
141                 // Insert into container
142                 m_blocks.insert(block_y, block);
143         }
144 }
145
146 void MapSector::removeBlock(MapBlock *block)
147 {
148         s16 block_y = block->getPos().Y;
149
150         JMutexAutoLock lock(m_mutex);
151         
152         // Clear from cache
153         m_block_cache = NULL;
154         
155         // Remove from container
156         m_blocks.remove(block_y);
157 }
158
159 void MapSector::getBlocks(core::list<MapBlock*> &dest)
160 {
161         JMutexAutoLock lock(m_mutex);
162
163         core::list<MapBlock*> ref_list;
164
165         core::map<s16, MapBlock*>::Iterator bi;
166
167         bi = m_blocks.getIterator();
168         for(; bi.atEnd() == false; bi++)
169         {
170                 MapBlock *b = bi.getNode()->getValue();
171                 dest.push_back(b);
172         }
173 }
174
175 /*
176         ServerMapSector
177 */
178
179 ServerMapSector::ServerMapSector(NodeContainer *parent, v2s16 pos, u16 hm_split):
180                 MapSector(parent, pos),
181                 m_hm_split(hm_split),
182                 m_objects(NULL)
183 {
184         // hm_split has to be 1 or 2^x
185         assert(hm_split == 0 || hm_split == 1 || (hm_split & (hm_split-1)) == 0);
186         assert(hm_split * hm_split <= MAPSECTOR_FIXEDHEIGHTMAPS_MAXCOUNT);
187         
188         for(u16 i=0; i<hm_split*hm_split; i++)
189                 m_heightmaps[i] = NULL;
190 }
191
192 ServerMapSector::~ServerMapSector()
193 {
194         u16 hm_count = m_hm_split * m_hm_split;
195
196         // Write heightmaps
197         for(u16 i=0; i<hm_count; i++)
198         {
199                 if(m_heightmaps[i])
200                         delete m_heightmaps[i];
201         }
202
203         if(m_objects)
204                 delete m_objects;
205 }
206
207 void ServerMapSector::setHeightmap(v2s16 hm_p, FixedHeightmap *hm)
208 {
209         assert(isInArea(hm_p, m_hm_split));
210
211         s16 i = hm_p.Y * m_hm_split + hm_p.X;
212         
213         // Don't allow setting already set heightmaps as of now
214         assert(m_heightmaps[i] == NULL);
215         
216         /*std::cout<<"MapSector::setHeightmap for sector "
217                         <<"("<<m_pos.X<<","<<m_pos.Y<<"): "
218                         <<"Setting heightmap "
219                         <<"("<<hm_p.X<<","<<hm_p.Y<<")"
220                         <<" which is i="<<i
221                         <<" to pointer "<<(long long)hm
222                         <<std::endl;*/
223
224         m_heightmaps[i] = hm;
225         
226         differs_from_disk = true;
227 }
228
229 FixedHeightmap * ServerMapSector::getHeightmap(v2s16 hm_p)
230 {
231         assert(isInArea(hm_p, m_hm_split));
232
233         s16 i = hm_p.Y * m_hm_split + hm_p.X;
234         
235         return m_heightmaps[i];
236 }
237
238 f32 ServerMapSector::getGroundHeight(v2s16 p, bool generate)
239 {
240         // If no heightmaps
241         if(m_hm_split == 0)
242         {
243                 /*std::cout<<"Sector has no heightmap"
244                                 <<" while trying to get height at ("<<p.X<<","<<p.Y<<")"
245                                 <<" for sector ("<<m_pos.X<<","<<m_pos.Y<<")"
246                                 <<std::endl;*/
247                 return GROUNDHEIGHT_NOTFOUND_SETVALUE;
248         }
249         
250         // Side length of heightmap
251         s16 hm_d = MAP_BLOCKSIZE / m_hm_split;
252
253         // Position of selected heightmap
254         v2s16 hm_p = getContainerPos(p, hm_d);
255         if(isInArea(hm_p, m_hm_split) == false)
256         {
257                 /*std::cout<<"Sector has no heightmap ("<<hm_p.X<<","<<hm_p.Y<<")"
258                                 <<" while trying to get height at ("<<p.X<<","<<p.Y<<")"
259                                 <<" for sector ("<<m_pos.X<<","<<m_pos.Y<<")"
260                                 <<std::endl;*/
261                 return GROUNDHEIGHT_NOTFOUND_SETVALUE;
262         }
263
264         // Selected heightmap
265         FixedHeightmap *hm = m_heightmaps[hm_p.Y * m_hm_split + hm_p.X];
266
267         if(hm == NULL)
268         {
269                 /*std::cout<<"Sector heightmap ("<<hm_p.X<<","<<hm_p.Y<<")"
270                                 " is NULL"
271                                 <<" while trying to get height at ("<<p.X<<","<<p.Y<<")"
272                                 <<" for sector ("<<m_pos.X<<","<<m_pos.Y<<")"
273                                 <<std::endl;*/
274                 return GROUNDHEIGHT_NOTFOUND_SETVALUE;
275         }
276         
277         // Position in selected heighmap
278         v2s16 p_in_hm = p - hm_p * hm_d;
279         if(isInArea(p_in_hm, hm_d+1) == false)
280         {
281                 /*std::cout<<"Position ("<<p_in_hm.X<<","<<p_in_hm.Y<<")"
282                                 " not in sector heightmap area"
283                                 <<" while trying to get height at ("<<p.X<<","<<p.Y<<")"
284                                 <<" for sector ("<<m_pos.X<<","<<m_pos.Y<<")"
285                                 <<std::endl;*/
286                 return GROUNDHEIGHT_NOTFOUND_SETVALUE;
287         }
288         
289         f32 h = hm->getGroundHeight(p_in_hm);
290         
291         /*if(h < GROUNDHEIGHT_VALID_MINVALUE)
292         {
293                 std::cout<<"Sector heightmap ("<<hm_p.X<<","<<hm_p.Y<<")"
294                                 " returned invalid value"
295                                 <<" while trying to get height at ("<<p.X<<","<<p.Y<<")"
296                                 <<" which is ("<<p_in_hm.X<<","<<p_in_hm.Y<<") in heightmap"
297                                 <<" for sector ("<<m_pos.X<<","<<m_pos.Y<<")"
298                                 <<std::endl;
299         }*/
300
301         return h;
302 }
303
304 void ServerMapSector::setGroundHeight(v2s16 p, f32 y, bool generate)
305 {
306         /*
307                 NOTE:
308                 This causes glitches because the sector cannot be actually
309                 modified according to heightmap changes.
310
311                 This is useful when generating continued sub-heightmaps
312                 inside the sector.
313         */
314
315         // If no heightmaps
316         if(m_hm_split == 0)
317                 return;
318         
319         // Side length of heightmap
320         s16 hm_d = MAP_BLOCKSIZE / m_hm_split;
321
322         // Position of selected heightmap
323         v2s16 hm_p = getContainerPos(p, hm_d);
324         if(isInArea(hm_p, m_hm_split) == false)
325                 return;
326
327         // Selected heightmap
328         FixedHeightmap *hm = m_heightmaps[hm_p.Y * m_hm_split + hm_p.X];
329
330         if(hm == NULL)
331                 return;
332         
333         // Position in selected heighmap
334         v2s16 p_in_hm = p - hm_p * hm_d;
335         if(isInArea(p_in_hm, hm_d) == false)
336                 return;
337         
338         hm->setGroundHeight(p_in_hm, y);
339         
340         differs_from_disk = true;
341 }
342
343 void ServerMapSector::serialize(std::ostream &os, u8 version)
344 {
345         if(!ser_ver_supported(version))
346                 throw VersionMismatchException("ERROR: MapSector format not supported");
347         
348         /*
349                 [0] u8 serialization version
350                 + heightmap data
351         */
352         
353         // Server has both of these, no need to support not having them.
354         assert(m_objects != NULL);
355
356         // Write version
357         os.write((char*)&version, 1);
358         
359         /*
360                 Serialize heightmap(s)
361         */
362
363         // Version with single heightmap
364         if(version <= 7)
365         {
366                 u32 heightmap_size =
367                                 FixedHeightmap::serializedLength(version, MAP_BLOCKSIZE);
368                 
369                 SharedBuffer<u8> data(heightmap_size);
370                 m_heightmaps[0]->serialize(*data, version);
371
372                 os.write((const char*)*data, heightmap_size);
373                 
374                 if(version >= 5)
375                 {
376                         /*
377                                 Write objects
378                         */
379                         
380                         u16 object_count;
381                         if(m_objects->size() > 65535)
382                                 object_count = 65535;
383                         else
384                                 object_count = m_objects->size();
385
386                         u8 b[2];
387                         writeU16(b, object_count);
388                         os.write((char*)b, 2);
389                         
390                         core::map<v3s16, u8>::Iterator i;
391                         i = m_objects->getIterator();
392                         for(; i.atEnd() == false; i++)
393                         {
394                                 v3s16 p = i.getNode()->getKey();
395                                 u8 d = i.getNode()->getValue();
396                                 u8 b[7];
397                                 writeV3S16(&b[0], p);
398                                 b[6] = d;
399                                 os.write((char*)b, 7);
400                         }
401                 }
402         }
403         // Version with multiple heightmaps
404         else
405         {
406                 u8 buf[2];
407                 
408                 if(m_hm_split > 255)
409                         throw SerializationError("Sector has too many heightmaps");
410                 
411                 // Write heightmap split ratio
412                 writeU8(buf, m_hm_split);
413                 os.write((char*)buf, 1);
414
415                 // If there are heightmaps, write them
416                 if(m_hm_split != 0)
417                 {
418                         u16 hm_d = MAP_BLOCKSIZE / m_hm_split;
419
420                         u32 hm_size = FixedHeightmap::serializedLength(version, hm_d);
421                         SharedBuffer<u8> data(hm_size);
422                         
423                         u16 hm_count = m_hm_split * m_hm_split;
424
425                         // Write heightmaps
426                         for(u16 i=0; i<hm_count; i++)
427                         {
428                                 m_heightmaps[i]->serialize(*data, version);
429                                 os.write((const char*)*data, hm_size);
430                         }
431                 }
432         
433                 /*
434                         Write objects
435                 */
436                 
437                 u16 object_count;
438                 if(m_objects->size() > 65535)
439                         object_count = 65535;
440                 else
441                         object_count = m_objects->size();
442
443                 u8 b[2];
444                 writeU16(b, object_count);
445                 os.write((char*)b, 2);
446                 
447                 core::map<v3s16, u8>::Iterator i;
448                 i = m_objects->getIterator();
449                 for(; i.atEnd() == false; i++)
450                 {
451                         v3s16 p = i.getNode()->getKey();
452                         u8 d = i.getNode()->getValue();
453                         u8 b[7];
454                         writeV3S16(&b[0], p);
455                         b[6] = d;
456                         os.write((char*)b, 7);
457                 }
458         }
459 }
460
461 ServerMapSector* ServerMapSector::deSerialize(
462                 std::istream &is,
463                 NodeContainer *parent,
464                 v2s16 p2d,
465                 Heightmap *master_hm,
466                 core::map<v2s16, MapSector*> & sectors
467         )
468 {
469         /*
470                 [0] u8 serialization version
471                 + heightmap data
472         */
473
474         /*
475                 Read stuff
476         */
477         
478         // Read version
479         u8 version = SER_FMT_VER_INVALID;
480         is.read((char*)&version, 1);
481         
482         if(!ser_ver_supported(version))
483                 throw VersionMismatchException("ERROR: MapSector format not supported");
484         
485         /*
486                 Read heightmap(s)
487         */
488
489         FixedHeightmap *hms[MAPSECTOR_FIXEDHEIGHTMAPS_MAXCOUNT];
490         u16 hm_split = 0;
491         
492         // Version with a single heightmap
493         if(version <= 7)
494         {
495                 hm_split = 1;
496
497                 u32 hm_size =
498                                 FixedHeightmap::serializedLength(version, MAP_BLOCKSIZE);
499                 
500                 SharedBuffer<u8> data(hm_size);
501                 is.read((char*)*data, hm_size);
502
503                 hms[0] = new FixedHeightmap(master_hm, p2d, MAP_BLOCKSIZE);
504                 hms[0]->deSerialize(*data, version);
505         }
506         // Version with multiple heightmaps
507         else
508         {
509                 u8 buf[2];
510
511                 // Read split ratio
512                 is.read((char*)buf, 1);
513                 hm_split = readU8(buf);
514
515                 // If there are heightmaps, read them
516                 if(hm_split != 0)
517                 {
518                         u16 hm_count = hm_split * hm_split;
519
520                         if(hm_count > MAPSECTOR_FIXEDHEIGHTMAPS_MAXCOUNT)
521                                 throw SerializationError("Sector has too many heightmaps");
522                         
523                         u16 hm_d = MAP_BLOCKSIZE / hm_split;
524
525                         u32 hm_size = FixedHeightmap::serializedLength(version, hm_d);
526                         
527                         u16 i=0;
528                         for(s16 y=0; y<hm_split; y++)
529                         for(s16 x=0; x<hm_split; x++)
530                         {
531                                 SharedBuffer<u8> data(hm_size);
532                                 is.read((char*)*data, hm_size);
533
534                                 hms[i] = new FixedHeightmap(master_hm, p2d+v2s16(x,y), hm_d);
535                                 hms[i]->deSerialize(*data, version);
536                                 i++;
537                         }
538                 }
539         }
540
541         /*
542                 Read objects
543         */
544
545         core::map<v3s16, u8> *objects = new core::map<v3s16, u8>;
546
547         if(version >= 5)
548         {
549                 u8 b[2];
550                 is.read((char*)b, 2);
551                 u16 object_count = readU16(b);
552
553                 for(u16 i=0; i<object_count; i++)
554                 {
555                         u8 b[7];
556                         is.read((char*)b, 7);
557                         v3s16 p = readV3S16(&b[0]);
558                         u8 d = b[6];
559                         objects->insert(p, d);
560                 }
561         }
562         
563         /*
564                 Get or create sector
565         */
566
567         ServerMapSector *sector = NULL;
568
569         core::map<v2s16, MapSector*>::Node *n = sectors.find(p2d);
570
571         if(n != NULL)
572         {
573                 dstream<<"WARNING: deSerializing existent sectors not supported "
574                                 "at the moment, because code hasn't been tested."
575                                 <<std::endl;
576
577                 //assert(0);
578                 MapSector *sector = n->getValue();
579                 assert(sector->getId() == MAPSECTOR_SERVER);
580                 return (ServerMapSector*)sector;
581
582                 // NOTE: At least hm_split mismatch would have to be checked
583                 
584                 //sector = n->getValue();
585         }
586         else
587         {
588                 sector = new ServerMapSector(parent, p2d, hm_split);
589                 sectors.insert(p2d, sector);
590         }
591
592         /*
593                 Set stuff in sector
594         */
595
596         // Set heightmaps
597         
598         sector->m_hm_split = hm_split;
599
600         u16 hm_count = hm_split * hm_split;
601
602         for(u16 i=0; i<hm_count; i++)
603         {
604                 // Set (or change) heightmap
605                 FixedHeightmap *oldhm = sector->m_heightmaps[i];
606                 sector->m_heightmaps[i] = hms[i];
607                 if(oldhm != NULL)
608                         delete oldhm;
609         }
610         
611         // Set (or change) objects
612         core::map<v3s16, u8> *oldfo = sector->m_objects;
613         sector->m_objects = objects;
614         if(oldfo)
615                 delete oldfo;
616
617         return sector;
618 }
619
620 #ifndef SERVER
621 /*
622         ClientMapSector
623 */
624
625 ClientMapSector::ClientMapSector(NodeContainer *parent, v2s16 pos):
626                 MapSector(parent, pos)
627 {
628 }
629
630 ClientMapSector::~ClientMapSector()
631 {
632 }
633
634 void ClientMapSector::deSerialize(std::istream &is)
635 {
636         /*
637                 [0] u8 serialization version
638                 [1] s16 corners[0]
639                 [3] s16 corners[1]
640                 [5] s16 corners[2]
641                 [7] s16 corners[3]
642                 size = 9
643                 
644                 In which corners are in these positions
645                 v2s16(0,0),
646                 v2s16(1,0),
647                 v2s16(1,1),
648                 v2s16(0,1),
649         */
650         
651         // Read version
652         u8 version = SER_FMT_VER_INVALID;
653         is.read((char*)&version, 1);
654         
655         if(!ser_ver_supported(version))
656                 throw VersionMismatchException("ERROR: MapSector format not supported");
657         if(version <= 7)
658                 throw VersionMismatchException("ERROR: MapSector format not supported");
659         
660         u8 buf[2];
661         
662         // Read corners
663         is.read((char*)buf, 2);
664         s16 c0 = readU16(buf);
665         is.read((char*)buf, 2);
666         s16 c1 = readU16(buf);
667         is.read((char*)buf, 2);
668         s16 c2 = readU16(buf);
669         is.read((char*)buf, 2);
670         s16 c3 = readU16(buf);
671         
672         /*
673                 Set stuff in sector
674         */
675         
676         m_corners[0] = c0;
677         m_corners[1] = c1;
678         m_corners[2] = c2;
679         m_corners[3] = c3;
680 }
681 #endif // !SERVER
682
683 //END