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