2 #include "jmutexautolock.h"
4 #include "exceptions.h"
6 MapSector::MapSector(NodeContainer *parent, v2s16 pos):
7 differs_from_disk(true),
14 assert(m_mutex.IsInitialized());
17 MapSector::~MapSector()
22 void MapSector::deleteBlocks()
24 JMutexAutoLock lock(m_mutex);
30 core::map<s16, MapBlock*>::Iterator i = m_blocks.getIterator();
31 for(; i.atEnd() == false; i++)
33 delete i.getNode()->getValue();
40 MapBlock * MapSector::getBlockBuffered(s16 y)
44 if(m_block_cache != NULL && y == m_block_cache_y){
48 // If block doesn't exist, return NULL
49 core::map<s16, MapBlock*>::Node *n = m_blocks.find(y);
54 // If block exists, return it
56 block = n->getValue();
59 // Cache the last result
61 m_block_cache = block;
66 MapBlock * MapSector::getBlockNoCreate(s16 y)
68 JMutexAutoLock lock(m_mutex);
70 MapBlock *block = getBlockBuffered(y);
73 throw InvalidPositionException();
78 MapBlock * MapSector::createBlankBlockNoInsert(s16 y)
80 // There should not be a block at this position
81 if(getBlockBuffered(y) != NULL)
82 throw AlreadyExistsException("Block already exists");
84 v3s16 blockpos_map(m_pos.X, y, m_pos.Y);
86 MapBlock *block = new MapBlock(m_parent, blockpos_map);
91 MapBlock * MapSector::createBlankBlock(s16 y)
93 JMutexAutoLock lock(m_mutex);
95 MapBlock *block = createBlankBlockNoInsert(y);
97 m_blocks.insert(y, block);
102 void MapSector::insertBlock(MapBlock *block)
104 s16 block_y = block->getPos().Y;
107 JMutexAutoLock lock(m_mutex);
109 MapBlock *block2 = getBlockBuffered(block_y);
111 throw AlreadyExistsException("Block already exists");
114 v2s16 p2d(block->getPos().X, block->getPos().Z);
115 assert(p2d == m_pos);
117 // Insert into container
118 m_blocks.insert(block_y, block);
122 void MapSector::removeBlock(MapBlock *block)
124 s16 block_y = block->getPos().Y;
126 JMutexAutoLock lock(m_mutex);
129 m_block_cache = NULL;
131 // Remove from container
132 m_blocks.remove(block_y);
135 void MapSector::getBlocks(core::list<MapBlock*> &dest)
137 JMutexAutoLock lock(m_mutex);
139 core::list<MapBlock*> ref_list;
141 core::map<s16, MapBlock*>::Iterator bi;
143 bi = m_blocks.getIterator();
144 for(; bi.atEnd() == false; bi++)
146 MapBlock *b = bi.getNode()->getValue();
155 ServerMapSector::ServerMapSector(NodeContainer *parent, v2s16 pos, u16 hm_split):
156 MapSector(parent, pos),
157 m_hm_split(hm_split),
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);
164 for(u16 i=0; i<hm_split*hm_split; i++)
165 m_heightmaps[i] = NULL;
168 ServerMapSector::~ServerMapSector()
170 u16 hm_count = m_hm_split * m_hm_split;
173 for(u16 i=0; i<hm_count; i++)
176 delete m_heightmaps[i];
183 void ServerMapSector::setHeightmap(v2s16 hm_p, FixedHeightmap *hm)
185 assert(isInArea(hm_p, m_hm_split));
187 s16 i = hm_p.Y * m_hm_split + hm_p.X;
189 // Don't allow setting already set heightmaps as of now
190 assert(m_heightmaps[i] == NULL);
192 /*std::cout<<"MapSector::setHeightmap for sector "
193 <<"("<<m_pos.X<<","<<m_pos.Y<<"): "
194 <<"Setting heightmap "
195 <<"("<<hm_p.X<<","<<hm_p.Y<<")"
197 <<" to pointer "<<(long long)hm
200 m_heightmaps[i] = hm;
202 differs_from_disk = true;
205 FixedHeightmap * ServerMapSector::getHeightmap(v2s16 hm_p)
207 assert(isInArea(hm_p, m_hm_split));
209 s16 i = hm_p.Y * m_hm_split + hm_p.X;
211 return m_heightmaps[i];
214 f32 ServerMapSector::getGroundHeight(v2s16 p, bool generate)
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<<")"
223 return GROUNDHEIGHT_NOTFOUND_SETVALUE;
226 // Side length of heightmap
227 s16 hm_d = MAP_BLOCKSIZE / m_hm_split;
229 // Position of selected heightmap
230 v2s16 hm_p = getContainerPos(p, hm_d);
231 if(isInArea(hm_p, m_hm_split) == false)
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<<")"
237 return GROUNDHEIGHT_NOTFOUND_SETVALUE;
240 // Selected heightmap
241 FixedHeightmap *hm = m_heightmaps[hm_p.Y * m_hm_split + hm_p.X];
245 /*std::cout<<"Sector heightmap ("<<hm_p.X<<","<<hm_p.Y<<")"
247 <<" while trying to get height at ("<<p.X<<","<<p.Y<<")"
248 <<" for sector ("<<m_pos.X<<","<<m_pos.Y<<")"
250 return GROUNDHEIGHT_NOTFOUND_SETVALUE;
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)
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<<")"
262 return GROUNDHEIGHT_NOTFOUND_SETVALUE;
265 f32 h = hm->getGroundHeight(p_in_hm);
267 /*if(h < GROUNDHEIGHT_VALID_MINVALUE)
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<<")"
280 void ServerMapSector::setGroundHeight(v2s16 p, f32 y, bool generate)
284 This causes glitches because the sector cannot be actually
285 modified according to heightmap changes.
287 This is useful when generating continued sub-heightmaps
295 // Side length of heightmap
296 s16 hm_d = MAP_BLOCKSIZE / m_hm_split;
298 // Position of selected heightmap
299 v2s16 hm_p = getContainerPos(p, hm_d);
300 if(isInArea(hm_p, m_hm_split) == false)
303 // Selected heightmap
304 FixedHeightmap *hm = m_heightmaps[hm_p.Y * m_hm_split + hm_p.X];
309 // Position in selected heighmap
310 v2s16 p_in_hm = p - hm_p * hm_d;
311 if(isInArea(p_in_hm, hm_d) == false)
314 hm->setGroundHeight(p_in_hm, y);
316 differs_from_disk = true;
319 void ServerMapSector::serialize(std::ostream &os, u8 version)
321 if(!ser_ver_supported(version))
322 throw VersionMismatchException("ERROR: MapSector format not supported");
325 [0] u8 serialization version
329 // Server has both of these, no need to support not having them.
330 assert(m_objects != NULL);
333 os.write((char*)&version, 1);
336 Serialize heightmap(s)
339 // Version with single heightmap
343 FixedHeightmap::serializedLength(version, MAP_BLOCKSIZE);
345 SharedBuffer<u8> data(heightmap_size);
346 m_heightmaps[0]->serialize(*data, version);
348 os.write((const char*)*data, heightmap_size);
357 if(m_objects->size() > 65535)
358 object_count = 65535;
360 object_count = m_objects->size();
363 writeU16(b, object_count);
364 os.write((char*)b, 2);
366 core::map<v3s16, u8>::Iterator i;
367 i = m_objects->getIterator();
368 for(; i.atEnd() == false; i++)
370 v3s16 p = i.getNode()->getKey();
371 u8 d = i.getNode()->getValue();
373 writeV3S16(&b[0], p);
375 os.write((char*)b, 7);
379 // Version with multiple heightmaps
385 throw SerializationError("Sector has too many heightmaps");
387 // Write heightmap split ratio
388 writeU8(buf, m_hm_split);
389 os.write((char*)buf, 1);
391 // If there are heightmaps, write them
394 u16 hm_d = MAP_BLOCKSIZE / m_hm_split;
396 u32 hm_size = FixedHeightmap::serializedLength(version, hm_d);
397 SharedBuffer<u8> data(hm_size);
399 u16 hm_count = m_hm_split * m_hm_split;
402 for(u16 i=0; i<hm_count; i++)
404 m_heightmaps[i]->serialize(*data, version);
405 os.write((const char*)*data, hm_size);
414 if(m_objects->size() > 65535)
415 object_count = 65535;
417 object_count = m_objects->size();
420 writeU16(b, object_count);
421 os.write((char*)b, 2);
423 core::map<v3s16, u8>::Iterator i;
424 i = m_objects->getIterator();
425 for(; i.atEnd() == false; i++)
427 v3s16 p = i.getNode()->getKey();
428 u8 d = i.getNode()->getValue();
430 writeV3S16(&b[0], p);
432 os.write((char*)b, 7);
437 ServerMapSector* ServerMapSector::deSerialize(
439 NodeContainer *parent,
441 Heightmap *master_hm,
442 core::map<v2s16, MapSector*> & sectors
446 [0] u8 serialization version
455 u8 version = SER_FMT_VER_INVALID;
456 is.read((char*)&version, 1);
458 if(!ser_ver_supported(version))
459 throw VersionMismatchException("ERROR: MapSector format not supported");
465 FixedHeightmap *hms[MAPSECTOR_FIXEDHEIGHTMAPS_MAXCOUNT];
468 // Version with a single heightmap
474 FixedHeightmap::serializedLength(version, MAP_BLOCKSIZE);
476 SharedBuffer<u8> data(hm_size);
477 is.read((char*)*data, hm_size);
479 hms[0] = new FixedHeightmap(master_hm, p2d, MAP_BLOCKSIZE);
480 hms[0]->deSerialize(*data, version);
482 // Version with multiple heightmaps
488 is.read((char*)buf, 1);
489 hm_split = readU8(buf);
491 // If there are heightmaps, read them
494 u16 hm_count = hm_split * hm_split;
496 if(hm_count > MAPSECTOR_FIXEDHEIGHTMAPS_MAXCOUNT)
497 throw SerializationError("Sector has too many heightmaps");
499 u16 hm_d = MAP_BLOCKSIZE / hm_split;
501 u32 hm_size = FixedHeightmap::serializedLength(version, hm_d);
504 for(s16 y=0; y<hm_split; y++)
505 for(s16 x=0; x<hm_split; x++)
507 SharedBuffer<u8> data(hm_size);
508 is.read((char*)*data, hm_size);
510 hms[i] = new FixedHeightmap(master_hm, p2d+v2s16(x,y), hm_d);
511 hms[i]->deSerialize(*data, version);
521 core::map<v3s16, u8> *objects = new core::map<v3s16, u8>;
526 is.read((char*)b, 2);
527 u16 object_count = readU16(b);
529 for(u16 i=0; i<object_count; i++)
532 is.read((char*)b, 7);
533 v3s16 p = readV3S16(&b[0]);
535 objects->insert(p, d);
543 ServerMapSector *sector = NULL;
545 core::map<v2s16, MapSector*>::Node *n = sectors.find(p2d);
549 dstream<<"deSerializing existent sectors not supported "
550 "at the moment, because code hasn't been tested."
553 // NOTE: At least hm_split mismatch would have to be checked
555 //sector = n->getValue();
559 sector = new ServerMapSector(parent, p2d, hm_split);
560 sectors.insert(p2d, sector);
569 sector->m_hm_split = hm_split;
571 u16 hm_count = hm_split * hm_split;
573 for(u16 i=0; i<hm_count; i++)
575 // Set (or change) heightmap
576 FixedHeightmap *oldhm = sector->m_heightmaps[i];
577 sector->m_heightmaps[i] = hms[i];
582 // Set (or change) objects
583 core::map<v3s16, u8> *oldfo = sector->m_objects;
584 sector->m_objects = objects;
595 ClientMapSector::ClientMapSector(NodeContainer *parent, v2s16 pos):
596 MapSector(parent, pos)
600 ClientMapSector::~ClientMapSector()
604 void ClientMapSector::deSerialize(std::istream &is)
607 [0] u8 serialization version
614 In which corners are in these positions
622 u8 version = SER_FMT_VER_INVALID;
623 is.read((char*)&version, 1);
625 if(!ser_ver_supported(version))
626 throw VersionMismatchException("ERROR: MapSector format not supported");
628 throw VersionMismatchException("ERROR: MapSector format not supported");
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);