Merge pull request #13 from Bahamada/upstream_merge
[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                 m_parent(parent),
28                 m_pos(pos),
29                 m_block_cache(NULL)
30 {
31         m_mutex.Init();
32         assert(m_mutex.IsInitialized());
33 }
34
35 MapSector::~MapSector()
36 {
37         deleteBlocks();
38 }
39
40 void MapSector::deleteBlocks()
41 {
42         JMutexAutoLock lock(m_mutex);
43
44         // Clear cache
45         m_block_cache = NULL;
46
47         // Delete all
48         core::map<s16, MapBlock*>::Iterator i = m_blocks.getIterator();
49         for(; i.atEnd() == false; i++)
50         {
51                 delete i.getNode()->getValue();
52         }
53
54         // Clear container
55         m_blocks.clear();
56 }
57
58 MapBlock * MapSector::getBlockBuffered(s16 y)
59 {
60         MapBlock *block;
61
62         if(m_block_cache != NULL && y == m_block_cache_y){
63                 return m_block_cache;
64         }
65         
66         // If block doesn't exist, return NULL
67         core::map<s16, MapBlock*>::Node *n = m_blocks.find(y);
68         if(n == NULL)
69         {
70                 block = NULL;
71         }
72         // If block exists, return it
73         else{
74                 block = n->getValue();
75         }
76         
77         // Cache the last result
78         m_block_cache_y = y;
79         m_block_cache = block;
80         
81         return block;
82 }
83
84 MapBlock * MapSector::getBlockNoCreateNoEx(s16 y)
85 {
86         JMutexAutoLock lock(m_mutex);
87         
88         return getBlockBuffered(y);
89 }
90
91 MapBlock * MapSector::getBlockNoCreate(s16 y)
92 {
93         MapBlock *block = getBlockNoCreateNoEx(y);
94
95         if(block == NULL)
96                 throw InvalidPositionException();
97         
98         return block;
99 }
100
101 MapBlock * MapSector::createBlankBlockNoInsert(s16 y)
102 {
103         // There should not be a block at this position
104         if(getBlockBuffered(y) != NULL)
105                 throw AlreadyExistsException("Block already exists");
106
107         v3s16 blockpos_map(m_pos.X, y, m_pos.Y);
108         
109         MapBlock *block = new MapBlock(m_parent, blockpos_map);
110         
111         return block;
112 }
113
114 MapBlock * MapSector::createBlankBlock(s16 y)
115 {
116         JMutexAutoLock lock(m_mutex);
117         
118         MapBlock *block = createBlankBlockNoInsert(y);
119         
120         m_blocks.insert(y, block);
121
122         return block;
123 }
124
125 void MapSector::insertBlock(MapBlock *block)
126 {
127         s16 block_y = block->getPos().Y;
128
129         {
130                 JMutexAutoLock lock(m_mutex);
131
132                 MapBlock *block2 = getBlockBuffered(block_y);
133                 if(block2 != NULL){
134                         throw AlreadyExistsException("Block already exists");
135                 }
136
137                 v2s16 p2d(block->getPos().X, block->getPos().Z);
138                 assert(p2d == m_pos);
139                 
140                 // Insert into container
141                 m_blocks.insert(block_y, block);
142         }
143 }
144
145 void MapSector::removeBlock(MapBlock *block)
146 {
147         s16 block_y = block->getPos().Y;
148
149         JMutexAutoLock lock(m_mutex);
150         
151         // Clear from cache
152         m_block_cache = NULL;
153         
154         // Remove from container
155         m_blocks.remove(block_y);
156 }
157
158 void MapSector::getBlocks(core::list<MapBlock*> &dest)
159 {
160         JMutexAutoLock lock(m_mutex);
161
162         core::list<MapBlock*> ref_list;
163
164         core::map<s16, MapBlock*>::Iterator bi;
165
166         bi = m_blocks.getIterator();
167         for(; bi.atEnd() == false; bi++)
168         {
169                 MapBlock *b = bi.getNode()->getValue();
170                 dest.push_back(b);
171         }
172 }
173
174 /*
175         ServerMapSector
176 */
177
178 ServerMapSector::ServerMapSector(NodeContainer *parent, v2s16 pos):
179                 MapSector(parent, pos)
180 {
181 }
182
183 ServerMapSector::~ServerMapSector()
184 {
185 }
186
187 f32 ServerMapSector::getGroundHeight(v2s16 p, bool generate)
188 {
189         return GROUNDHEIGHT_NOTFOUND_SETVALUE;
190 }
191
192 void ServerMapSector::setGroundHeight(v2s16 p, f32 y, bool generate)
193 {
194 }
195
196 void ServerMapSector::serialize(std::ostream &os, u8 version)
197 {
198         if(!ser_ver_supported(version))
199                 throw VersionMismatchException("ERROR: MapSector format not supported");
200         
201         /*
202                 [0] u8 serialization version
203                 + heightmap data
204         */
205         
206         // Server has both of these, no need to support not having them.
207         //assert(m_objects != NULL);
208
209         // Write version
210         os.write((char*)&version, 1);
211         
212         /*
213                 Add stuff here, if needed
214         */
215
216 }
217
218 ServerMapSector* ServerMapSector::deSerialize(
219                 std::istream &is,
220                 NodeContainer *parent,
221                 v2s16 p2d,
222                 core::map<v2s16, MapSector*> & sectors
223         )
224 {
225         /*
226                 [0] u8 serialization version
227                 + heightmap data
228         */
229
230         /*
231                 Read stuff
232         */
233         
234         // Read version
235         u8 version = SER_FMT_VER_INVALID;
236         is.read((char*)&version, 1);
237         
238         if(!ser_ver_supported(version))
239                 throw VersionMismatchException("ERROR: MapSector format not supported");
240         
241         /*
242                 Add necessary reading stuff here
243         */
244         
245         /*
246                 Get or create sector
247         */
248
249         ServerMapSector *sector = NULL;
250
251         core::map<v2s16, MapSector*>::Node *n = sectors.find(p2d);
252
253         if(n != NULL)
254         {
255                 dstream<<"WARNING: deSerializing existent sectors not supported "
256                                 "at the moment, because code hasn't been tested."
257                                 <<std::endl;
258
259                 MapSector *sector = n->getValue();
260                 assert(sector->getId() == MAPSECTOR_SERVER);
261                 return (ServerMapSector*)sector;
262         }
263         else
264         {
265                 sector = new ServerMapSector(parent, p2d);
266                 sectors.insert(p2d, sector);
267         }
268
269         /*
270                 Set stuff in sector
271         */
272
273         // Nothing here
274
275         return sector;
276 }
277
278 #ifndef SERVER
279 /*
280         ClientMapSector
281 */
282
283 ClientMapSector::ClientMapSector(NodeContainer *parent, v2s16 pos):
284                 MapSector(parent, pos)
285 {
286 }
287
288 ClientMapSector::~ClientMapSector()
289 {
290 }
291
292 void ClientMapSector::deSerialize(std::istream &is)
293 {
294         /*
295                 [0] u8 serialization version
296                 [1] s16 corners[0]
297                 [3] s16 corners[1]
298                 [5] s16 corners[2]
299                 [7] s16 corners[3]
300                 size = 9
301                 
302                 In which corners are in these positions
303                 v2s16(0,0),
304                 v2s16(1,0),
305                 v2s16(1,1),
306                 v2s16(0,1),
307         */
308         
309         // Read version
310         u8 version = SER_FMT_VER_INVALID;
311         is.read((char*)&version, 1);
312         
313         if(!ser_ver_supported(version))
314                 throw VersionMismatchException("ERROR: MapSector format not supported");
315         
316         u8 buf[2];
317         
318         // Dummy read corners
319         is.read((char*)buf, 2);
320         is.read((char*)buf, 2);
321         is.read((char*)buf, 2);
322         is.read((char*)buf, 2);
323         
324         /*
325                 Set stuff in sector
326         */
327         
328         // Nothing here
329
330 }
331 #endif // !SERVER
332
333 //END