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