]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mapnode.cpp
2cffd3e4405fa4f6426d47dca916acb3216164dc
[dragonfireclient.git] / src / mapnode.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 Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser 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 "common_irrlicht.h"
21 #include "mapnode.h"
22 #include "porting.h"
23 #include "main.h" // For g_settings
24 #include "nodedef.h"
25 #include "content_mapnode.h" // For mapnode_translate_*_internal
26 #include "serialization.h" // For ser_ver_supported
27 #include "util/serialize.h"
28 #include <string>
29 #include <sstream>
30
31 /*
32         MapNode
33 */
34
35 // Create directly from a nodename
36 // If name is unknown, sets CONTENT_IGNORE
37 MapNode::MapNode(INodeDefManager *ndef, const std::string &name,
38                 u8 a_param1, u8 a_param2)
39 {
40         content_t id = CONTENT_IGNORE;
41         ndef->getId(name, id);
42         param1 = a_param1;
43         param2 = a_param2;
44         // Set content (param0 and (param2&0xf0)) after other params
45         // because this needs to override part of param2
46         setContent(id);
47 }
48
49 void MapNode::setLight(enum LightBank bank, u8 a_light, INodeDefManager *nodemgr)
50 {
51         // If node doesn't contain light data, ignore this
52         if(nodemgr->get(*this).param_type != CPT_LIGHT)
53                 return;
54         if(bank == LIGHTBANK_DAY)
55         {
56                 param1 &= 0xf0;
57                 param1 |= a_light & 0x0f;
58         }
59         else if(bank == LIGHTBANK_NIGHT)
60         {
61                 param1 &= 0x0f;
62                 param1 |= (a_light & 0x0f)<<4;
63         }
64         else
65                 assert(0);
66 }
67
68 u8 MapNode::getLight(enum LightBank bank, INodeDefManager *nodemgr) const
69 {
70         // Select the brightest of [light source, propagated light]
71         const ContentFeatures &f = nodemgr->get(*this);
72         u8 light = 0;
73         if(f.param_type == CPT_LIGHT)
74         {
75                 if(bank == LIGHTBANK_DAY)
76                         light = param1 & 0x0f;
77                 else if(bank == LIGHTBANK_NIGHT)
78                         light = (param1>>4)&0x0f;
79                 else
80                         assert(0);
81         }
82         if(f.light_source > light)
83                 light = f.light_source;
84         return light;
85 }
86
87 bool MapNode::getLightBanks(u8 &lightday, u8 &lightnight, INodeDefManager *nodemgr) const
88 {
89         // Select the brightest of [light source, propagated light]
90         const ContentFeatures &f = nodemgr->get(*this);
91         if(f.param_type == CPT_LIGHT)
92         {
93                 lightday = param1 & 0x0f;
94                 lightnight = (param1>>4)&0x0f;
95         }
96         else
97         {
98                 lightday = 0;
99                 lightnight = 0;
100         }
101         if(f.light_source > lightday)
102                 lightday = f.light_source;
103         if(f.light_source > lightnight)
104                 lightnight = f.light_source;
105         return f.param_type == CPT_LIGHT || f.light_source != 0;
106 }
107
108 u8 MapNode::getFaceDir(INodeDefManager *nodemgr) const
109 {
110         const ContentFeatures &f = nodemgr->get(*this);
111         if(f.param_type_2 == CPT2_FACEDIR)
112                 return getParam2() & 0x03;
113         return 0;
114 }
115
116 u8 MapNode::getWallMounted(INodeDefManager *nodemgr) const
117 {
118         const ContentFeatures &f = nodemgr->get(*this);
119         if(f.param_type_2 == CPT2_WALLMOUNTED)
120                 return getParam2() & 0x07;
121         return 0;
122 }
123
124 v3s16 MapNode::getWallMountedDir(INodeDefManager *nodemgr) const
125 {
126         switch(getWallMounted(nodemgr))
127         {
128         case 0: default: return v3s16(0,1,0);
129         case 1: return v3s16(0,-1,0);
130         case 2: return v3s16(1,0,0);
131         case 3: return v3s16(-1,0,0);
132         case 4: return v3s16(0,0,1);
133         case 5: return v3s16(0,0,-1);
134         }
135 }
136
137
138
139 u32 MapNode::serializedLength(u8 version)
140 {
141         if(!ser_ver_supported(version))
142                 throw VersionMismatchException("ERROR: MapNode format not supported");
143                 
144         if(version == 0)
145                 return 1;
146         else if(version <= 9)
147                 return 2;
148         else
149                 return 3;
150 }
151 void MapNode::serialize(u8 *dest, u8 version)
152 {
153         if(!ser_ver_supported(version))
154                 throw VersionMismatchException("ERROR: MapNode format not supported");
155
156         if(version <= 21)
157         {
158                 serialize_pre22(dest, version);
159                 return;
160         }
161
162         writeU8(dest+0, param0);
163         writeU8(dest+1, param1);
164         writeU8(dest+2, param2);
165 }
166 void MapNode::deSerialize(u8 *source, u8 version)
167 {
168         if(!ser_ver_supported(version))
169                 throw VersionMismatchException("ERROR: MapNode format not supported");
170                 
171         if(version <= 21)
172         {
173                 deSerialize_pre22(source, version);
174                 return;
175         }
176
177         param0 = readU8(source+0);
178         param1 = readU8(source+1);
179         param2 = readU8(source+2);
180 }
181 void MapNode::serializeBulk(std::ostream &os, int version,
182                 const MapNode *nodes, u32 nodecount,
183                 u8 content_width, u8 params_width, bool compressed)
184 {
185         if(!ser_ver_supported(version))
186                 throw VersionMismatchException("ERROR: MapNode format not supported");
187
188         assert(version >= 22);
189         assert(content_width == 1);
190         assert(params_width == 2);
191
192         SharedBuffer<u8> databuf(nodecount * (content_width + params_width));
193
194         // Serialize content
195         if(content_width == 1)
196         {
197                 for(u32 i=0; i<nodecount; i++)
198                         writeU8(&databuf[i], nodes[i].param0);
199         }
200         /* If param0 is extended to two bytes, use something like this: */
201         /*else if(content_width == 2)
202         {
203                 for(u32 i=0; i<nodecount; i++)
204                         writeU16(&databuf[i*2], nodes[i].param0);
205         }*/
206
207         // Serialize param1
208         u32 start1 = content_width * nodecount;
209         for(u32 i=0; i<nodecount; i++)
210                 writeU8(&databuf[start1 + i], nodes[i].param1);
211
212         // Serialize param2
213         u32 start2 = (content_width + 1) * nodecount;
214         for(u32 i=0; i<nodecount; i++)
215                 writeU8(&databuf[start2 + i], nodes[i].param2);
216
217         /*
218                 Compress data to output stream
219         */
220
221         if(compressed)
222         {
223                 compressZlib(databuf, os);
224         }
225         else
226         {
227                 os.write((const char*) &databuf[0], databuf.getSize());
228         }
229 }
230
231 // Deserialize bulk node data
232 void MapNode::deSerializeBulk(std::istream &is, int version,
233                 MapNode *nodes, u32 nodecount,
234                 u8 content_width, u8 params_width, bool compressed)
235 {
236         if(!ser_ver_supported(version))
237                 throw VersionMismatchException("ERROR: MapNode format not supported");
238
239         assert(version >= 22);
240         assert(content_width == 1);
241         assert(params_width == 2);
242
243         // Uncompress or read data
244         u32 len = nodecount * (content_width + params_width);
245         SharedBuffer<u8> databuf(len);
246         if(compressed)
247         {
248                 std::ostringstream os(std::ios_base::binary);
249                 decompressZlib(is, os);
250                 std::string s = os.str();
251                 if(s.size() != len)
252                         throw SerializationError("deSerializeBulkNodes: "
253                                         "decompress resulted in invalid size");
254                 memcpy(&databuf[0], s.c_str(), len);
255         }
256         else
257         {
258                 is.read((char*) &databuf[0], len);
259                 if(is.eof() || is.fail())
260                         throw SerializationError("deSerializeBulkNodes: "
261                                         "failed to read bulk node data");
262         }
263
264         // Deserialize content
265         if(content_width == 1)
266         {
267                 for(u32 i=0; i<nodecount; i++)
268                         nodes[i].param0 = readU8(&databuf[i]);
269         }
270         /* If param0 is extended to two bytes, use something like this: */
271         /*else if(content_width == 2)
272         {
273                 for(u32 i=0; i<nodecount; i++)
274                         nodes[i].param0 = readU16(&databuf[i*2]);
275         }*/
276
277         // Deserialize param1
278         u32 start1 = content_width * nodecount;
279         for(u32 i=0; i<nodecount; i++)
280                 nodes[i].param1 = readU8(&databuf[start1 + i]);
281
282         // Deserialize param2
283         u32 start2 = (content_width + 1) * nodecount;
284         for(u32 i=0; i<nodecount; i++)
285                 nodes[i].param2 = readU8(&databuf[start2 + i]);
286 }
287
288 /*
289         Legacy serialization
290 */
291 void MapNode::serialize_pre22(u8 *dest, u8 version)
292 {
293         // Translate to wanted version
294         MapNode n_foreign = mapnode_translate_from_internal(*this, version);
295
296         u8 actual_param0 = n_foreign.param0;
297
298         // Convert special values from new version to old
299         if(version <= 18)
300         {
301                 // In these versions, CONTENT_IGNORE and CONTENT_AIR
302                 // are 255 and 254
303                 if(actual_param0 == CONTENT_IGNORE)
304                         actual_param0 = 255;
305                 else if(actual_param0 == CONTENT_AIR)
306                         actual_param0 = 254;
307         }
308
309         if(version == 0)
310         {
311                 dest[0] = actual_param0;
312         }
313         else if(version <= 9)
314         {
315                 dest[0] = actual_param0;
316                 dest[1] = n_foreign.param1;
317         }
318         else
319         {
320                 dest[0] = actual_param0;
321                 dest[1] = n_foreign.param1;
322                 dest[2] = n_foreign.param2;
323         }
324 }
325 void MapNode::deSerialize_pre22(u8 *source, u8 version)
326 {
327         if(version <= 1)
328         {
329                 param0 = source[0];
330         }
331         else if(version <= 9)
332         {
333                 param0 = source[0];
334                 param1 = source[1];
335         }
336         else
337         {
338                 param0 = source[0];
339                 param1 = source[1];
340                 param2 = source[2];
341         }
342         
343         // Convert special values from old version to new
344         if(version <= 19)
345         {
346                 // In these versions, CONTENT_IGNORE and CONTENT_AIR
347                 // are 255 and 254
348                 // Version 19 is fucked up with sometimes the old values and sometimes not
349                 if(param0 == 255)
350                         param0 = CONTENT_IGNORE;
351                 else if(param0 == 254)
352                         param0 = CONTENT_AIR;
353         }
354
355         // Translate to our known version
356         *this = mapnode_translate_to_internal(*this, version);
357 }