3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
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.
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.
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.
20 #include "mapsector.h"
21 #include "jmutexautolock.h"
23 #include "exceptions.h"
25 MapSector::MapSector(NodeContainer *parent, v2s16 pos):
26 differs_from_disk(true),
33 assert(m_mutex.IsInitialized());
36 MapSector::~MapSector()
41 void MapSector::deleteBlocks()
43 JMutexAutoLock lock(m_mutex);
49 core::map<s16, MapBlock*>::Iterator i = m_blocks.getIterator();
50 for(; i.atEnd() == false; i++)
52 delete i.getNode()->getValue();
59 MapBlock * MapSector::getBlockBuffered(s16 y)
63 if(m_block_cache != NULL && y == m_block_cache_y){
67 // If block doesn't exist, return NULL
68 core::map<s16, MapBlock*>::Node *n = m_blocks.find(y);
73 // If block exists, return it
75 block = n->getValue();
78 // Cache the last result
80 m_block_cache = block;
85 MapBlock * MapSector::getBlockNoCreateNoEx(s16 y)
87 JMutexAutoLock lock(m_mutex);
89 return getBlockBuffered(y);
92 MapBlock * MapSector::getBlockNoCreate(s16 y)
94 MapBlock *block = getBlockNoCreateNoEx(y);
97 throw InvalidPositionException();
102 MapBlock * MapSector::createBlankBlockNoInsert(s16 y)
104 // There should not be a block at this position
105 if(getBlockBuffered(y) != NULL)
106 throw AlreadyExistsException("Block already exists");
108 v3s16 blockpos_map(m_pos.X, y, m_pos.Y);
110 MapBlock *block = new MapBlock(m_parent, blockpos_map);
115 MapBlock * MapSector::createBlankBlock(s16 y)
117 JMutexAutoLock lock(m_mutex);
119 MapBlock *block = createBlankBlockNoInsert(y);
121 m_blocks.insert(y, block);
126 void MapSector::insertBlock(MapBlock *block)
128 s16 block_y = block->getPos().Y;
131 JMutexAutoLock lock(m_mutex);
133 MapBlock *block2 = getBlockBuffered(block_y);
135 throw AlreadyExistsException("Block already exists");
138 v2s16 p2d(block->getPos().X, block->getPos().Z);
139 assert(p2d == m_pos);
141 // Insert into container
142 m_blocks.insert(block_y, block);
146 void MapSector::removeBlock(MapBlock *block)
148 s16 block_y = block->getPos().Y;
150 JMutexAutoLock lock(m_mutex);
153 m_block_cache = NULL;
155 // Remove from container
156 m_blocks.remove(block_y);
159 void MapSector::getBlocks(core::list<MapBlock*> &dest)
161 JMutexAutoLock lock(m_mutex);
163 core::list<MapBlock*> ref_list;
165 core::map<s16, MapBlock*>::Iterator bi;
167 bi = m_blocks.getIterator();
168 for(; bi.atEnd() == false; bi++)
170 MapBlock *b = bi.getNode()->getValue();
179 ServerMapSector::ServerMapSector(NodeContainer *parent, v2s16 pos, u16 hm_split):
180 MapSector(parent, pos),
181 m_hm_split(hm_split),
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);
188 for(u16 i=0; i<hm_split*hm_split; i++)
189 m_heightmaps[i] = NULL;
192 ServerMapSector::~ServerMapSector()
194 u16 hm_count = m_hm_split * m_hm_split;
197 for(u16 i=0; i<hm_count; i++)
200 delete m_heightmaps[i];
207 void ServerMapSector::setHeightmap(v2s16 hm_p, FixedHeightmap *hm)
209 assert(isInArea(hm_p, m_hm_split));
211 s16 i = hm_p.Y * m_hm_split + hm_p.X;
213 // Don't allow setting already set heightmaps as of now
214 assert(m_heightmaps[i] == NULL);
216 /*std::cout<<"MapSector::setHeightmap for sector "
217 <<"("<<m_pos.X<<","<<m_pos.Y<<"): "
218 <<"Setting heightmap "
219 <<"("<<hm_p.X<<","<<hm_p.Y<<")"
221 <<" to pointer "<<(long long)hm
224 m_heightmaps[i] = hm;
226 differs_from_disk = true;
229 FixedHeightmap * ServerMapSector::getHeightmap(v2s16 hm_p)
231 assert(isInArea(hm_p, m_hm_split));
233 s16 i = hm_p.Y * m_hm_split + hm_p.X;
235 return m_heightmaps[i];
238 f32 ServerMapSector::getGroundHeight(v2s16 p, bool generate)
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<<")"
247 return GROUNDHEIGHT_NOTFOUND_SETVALUE;
250 // Side length of heightmap
251 s16 hm_d = MAP_BLOCKSIZE / m_hm_split;
253 // Position of selected heightmap
254 v2s16 hm_p = getContainerPos(p, hm_d);
255 if(isInArea(hm_p, m_hm_split) == false)
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<<")"
261 return GROUNDHEIGHT_NOTFOUND_SETVALUE;
264 // Selected heightmap
265 FixedHeightmap *hm = m_heightmaps[hm_p.Y * m_hm_split + hm_p.X];
269 /*std::cout<<"Sector heightmap ("<<hm_p.X<<","<<hm_p.Y<<")"
271 <<" while trying to get height at ("<<p.X<<","<<p.Y<<")"
272 <<" for sector ("<<m_pos.X<<","<<m_pos.Y<<")"
274 return GROUNDHEIGHT_NOTFOUND_SETVALUE;
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)
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<<")"
286 return GROUNDHEIGHT_NOTFOUND_SETVALUE;
289 f32 h = hm->getGroundHeight(p_in_hm);
291 /*if(h < GROUNDHEIGHT_VALID_MINVALUE)
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<<")"
304 void ServerMapSector::setGroundHeight(v2s16 p, f32 y, bool generate)
308 This causes glitches because the sector cannot be actually
309 modified according to heightmap changes.
311 This is useful when generating continued sub-heightmaps
319 // Side length of heightmap
320 s16 hm_d = MAP_BLOCKSIZE / m_hm_split;
322 // Position of selected heightmap
323 v2s16 hm_p = getContainerPos(p, hm_d);
324 if(isInArea(hm_p, m_hm_split) == false)
327 // Selected heightmap
328 FixedHeightmap *hm = m_heightmaps[hm_p.Y * m_hm_split + hm_p.X];
333 // Position in selected heighmap
334 v2s16 p_in_hm = p - hm_p * hm_d;
335 if(isInArea(p_in_hm, hm_d) == false)
338 hm->setGroundHeight(p_in_hm, y);
340 differs_from_disk = true;
343 void ServerMapSector::serialize(std::ostream &os, u8 version)
345 if(!ser_ver_supported(version))
346 throw VersionMismatchException("ERROR: MapSector format not supported");
349 [0] u8 serialization version
353 // Server has both of these, no need to support not having them.
354 assert(m_objects != NULL);
357 os.write((char*)&version, 1);
360 Serialize heightmap(s)
363 // Version with single heightmap
367 FixedHeightmap::serializedLength(version, MAP_BLOCKSIZE);
369 SharedBuffer<u8> data(heightmap_size);
370 m_heightmaps[0]->serialize(*data, version);
372 os.write((const char*)*data, heightmap_size);
381 if(m_objects->size() > 65535)
382 object_count = 65535;
384 object_count = m_objects->size();
387 writeU16(b, object_count);
388 os.write((char*)b, 2);
390 core::map<v3s16, u8>::Iterator i;
391 i = m_objects->getIterator();
392 for(; i.atEnd() == false; i++)
394 v3s16 p = i.getNode()->getKey();
395 u8 d = i.getNode()->getValue();
397 writeV3S16(&b[0], p);
399 os.write((char*)b, 7);
403 // Version with multiple heightmaps
409 throw SerializationError("Sector has too many heightmaps");
411 // Write heightmap split ratio
412 writeU8(buf, m_hm_split);
413 os.write((char*)buf, 1);
415 // If there are heightmaps, write them
418 u16 hm_d = MAP_BLOCKSIZE / m_hm_split;
420 u32 hm_size = FixedHeightmap::serializedLength(version, hm_d);
421 SharedBuffer<u8> data(hm_size);
423 u16 hm_count = m_hm_split * m_hm_split;
426 for(u16 i=0; i<hm_count; i++)
428 m_heightmaps[i]->serialize(*data, version);
429 os.write((const char*)*data, hm_size);
438 if(m_objects->size() > 65535)
439 object_count = 65535;
441 object_count = m_objects->size();
444 writeU16(b, object_count);
445 os.write((char*)b, 2);
447 core::map<v3s16, u8>::Iterator i;
448 i = m_objects->getIterator();
449 for(; i.atEnd() == false; i++)
451 v3s16 p = i.getNode()->getKey();
452 u8 d = i.getNode()->getValue();
454 writeV3S16(&b[0], p);
456 os.write((char*)b, 7);
461 ServerMapSector* ServerMapSector::deSerialize(
463 NodeContainer *parent,
465 Heightmap *master_hm,
466 core::map<v2s16, MapSector*> & sectors
470 [0] u8 serialization version
479 u8 version = SER_FMT_VER_INVALID;
480 is.read((char*)&version, 1);
482 if(!ser_ver_supported(version))
483 throw VersionMismatchException("ERROR: MapSector format not supported");
489 FixedHeightmap *hms[MAPSECTOR_FIXEDHEIGHTMAPS_MAXCOUNT];
492 // Version with a single heightmap
498 FixedHeightmap::serializedLength(version, MAP_BLOCKSIZE);
500 SharedBuffer<u8> data(hm_size);
501 is.read((char*)*data, hm_size);
503 hms[0] = new FixedHeightmap(master_hm, p2d, MAP_BLOCKSIZE);
504 hms[0]->deSerialize(*data, version);
506 // Version with multiple heightmaps
512 is.read((char*)buf, 1);
513 hm_split = readU8(buf);
515 // If there are heightmaps, read them
518 u16 hm_count = hm_split * hm_split;
520 if(hm_count > MAPSECTOR_FIXEDHEIGHTMAPS_MAXCOUNT)
521 throw SerializationError("Sector has too many heightmaps");
523 u16 hm_d = MAP_BLOCKSIZE / hm_split;
525 u32 hm_size = FixedHeightmap::serializedLength(version, hm_d);
528 for(s16 y=0; y<hm_split; y++)
529 for(s16 x=0; x<hm_split; x++)
531 SharedBuffer<u8> data(hm_size);
532 is.read((char*)*data, hm_size);
534 hms[i] = new FixedHeightmap(master_hm, p2d+v2s16(x,y), hm_d);
535 hms[i]->deSerialize(*data, version);
545 core::map<v3s16, u8> *objects = new core::map<v3s16, u8>;
550 is.read((char*)b, 2);
551 u16 object_count = readU16(b);
553 for(u16 i=0; i<object_count; i++)
556 is.read((char*)b, 7);
557 v3s16 p = readV3S16(&b[0]);
559 objects->insert(p, d);
567 ServerMapSector *sector = NULL;
569 core::map<v2s16, MapSector*>::Node *n = sectors.find(p2d);
573 dstream<<"WARNING: deSerializing existent sectors not supported "
574 "at the moment, because code hasn't been tested."
578 MapSector *sector = n->getValue();
579 assert(sector->getId() == MAPSECTOR_SERVER);
580 return (ServerMapSector*)sector;
582 // NOTE: At least hm_split mismatch would have to be checked
584 //sector = n->getValue();
588 sector = new ServerMapSector(parent, p2d, hm_split);
589 sectors.insert(p2d, sector);
598 sector->m_hm_split = hm_split;
600 u16 hm_count = hm_split * hm_split;
602 for(u16 i=0; i<hm_count; i++)
604 // Set (or change) heightmap
605 FixedHeightmap *oldhm = sector->m_heightmaps[i];
606 sector->m_heightmaps[i] = hms[i];
611 // Set (or change) objects
612 core::map<v3s16, u8> *oldfo = sector->m_objects;
613 sector->m_objects = objects;
625 ClientMapSector::ClientMapSector(NodeContainer *parent, v2s16 pos):
626 MapSector(parent, pos)
630 ClientMapSector::~ClientMapSector()
634 void ClientMapSector::deSerialize(std::istream &is)
637 [0] u8 serialization version
644 In which corners are in these positions
652 u8 version = SER_FMT_VER_INVALID;
653 is.read((char*)&version, 1);
655 if(!ser_ver_supported(version))
656 throw VersionMismatchException("ERROR: MapSector format not supported");
658 throw VersionMismatchException("ERROR: MapSector format not supported");
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);