Custom boxy nodes (stairs, slabs) and collision changes
[oweals/minetest.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 "irrlichttypes_extrabloated.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 static std::vector<aabb3f> transformNodeBox(const MapNode &n,
138                 const NodeBox &nodebox, INodeDefManager *nodemgr)
139 {
140         std::vector<aabb3f> boxes;
141         if(nodebox.type == NODEBOX_FIXED)
142         {
143                 const std::vector<aabb3f> &fixed = nodebox.fixed;
144                 int facedir = n.getFaceDir(nodemgr);
145                 for(std::vector<aabb3f>::const_iterator
146                                 i = fixed.begin();
147                                 i != fixed.end(); i++)
148                 {
149                         aabb3f box = *i;
150                         if(facedir == 1)
151                         {
152                                 box.MinEdge.rotateXZBy(-90);
153                                 box.MaxEdge.rotateXZBy(-90);
154                                 box.repair();
155                         }
156                         else if(facedir == 2)
157                         {
158                                 box.MinEdge.rotateXZBy(180);
159                                 box.MaxEdge.rotateXZBy(180);
160                                 box.repair();
161                         }
162                         else if(facedir == 3)
163                         {
164                                 box.MinEdge.rotateXZBy(90);
165                                 box.MaxEdge.rotateXZBy(90);
166                                 box.repair();
167                         }
168                         boxes.push_back(box);
169                 }
170         }
171         else if(nodebox.type == NODEBOX_WALLMOUNTED)
172         {
173                 v3s16 dir = n.getWallMountedDir(nodemgr);
174
175                 // top
176                 if(dir == v3s16(0,1,0))
177                 {
178                         boxes.push_back(nodebox.wall_top);
179                 }
180                 // bottom
181                 else if(dir == v3s16(0,-1,0))
182                 {
183                         boxes.push_back(nodebox.wall_bottom);
184                 }
185                 // side
186                 else
187                 {
188                         v3f vertices[2] =
189                         {
190                                 nodebox.wall_side.MinEdge,
191                                 nodebox.wall_side.MaxEdge
192                         };
193
194                         for(s32 i=0; i<2; i++)
195                         {
196                                 if(dir == v3s16(-1,0,0))
197                                         vertices[i].rotateXZBy(0);
198                                 if(dir == v3s16(1,0,0))
199                                         vertices[i].rotateXZBy(180);
200                                 if(dir == v3s16(0,0,-1))
201                                         vertices[i].rotateXZBy(90);
202                                 if(dir == v3s16(0,0,1))
203                                         vertices[i].rotateXZBy(-90);
204                         }
205
206                         aabb3f box = aabb3f(vertices[0]);
207                         box.addInternalPoint(vertices[1]);
208                         boxes.push_back(box);
209                 }
210         }
211         else // NODEBOX_REGULAR
212         {
213                 boxes.push_back(aabb3f(-BS/2,-BS/2,-BS/2,BS/2,BS/2,BS/2));
214         }
215         return boxes;
216 }
217
218 std::vector<aabb3f> MapNode::getNodeBoxes(INodeDefManager *nodemgr) const
219 {
220         const ContentFeatures &f = nodemgr->get(*this);
221         return transformNodeBox(*this, f.node_box, nodemgr);
222 }
223
224 std::vector<aabb3f> MapNode::getSelectionBoxes(INodeDefManager *nodemgr) const
225 {
226         const ContentFeatures &f = nodemgr->get(*this);
227         return transformNodeBox(*this, f.selection_box, nodemgr);
228 }
229
230 u32 MapNode::serializedLength(u8 version)
231 {
232         if(!ser_ver_supported(version))
233                 throw VersionMismatchException("ERROR: MapNode format not supported");
234                 
235         if(version == 0)
236                 return 1;
237         else if(version <= 9)
238                 return 2;
239         else
240                 return 3;
241 }
242 void MapNode::serialize(u8 *dest, u8 version)
243 {
244         if(!ser_ver_supported(version))
245                 throw VersionMismatchException("ERROR: MapNode format not supported");
246
247         if(version <= 21)
248         {
249                 serialize_pre22(dest, version);
250                 return;
251         }
252
253         writeU8(dest+0, param0);
254         writeU8(dest+1, param1);
255         writeU8(dest+2, param2);
256 }
257 void MapNode::deSerialize(u8 *source, u8 version)
258 {
259         if(!ser_ver_supported(version))
260                 throw VersionMismatchException("ERROR: MapNode format not supported");
261                 
262         if(version <= 21)
263         {
264                 deSerialize_pre22(source, version);
265                 return;
266         }
267
268         param0 = readU8(source+0);
269         param1 = readU8(source+1);
270         param2 = readU8(source+2);
271 }
272 void MapNode::serializeBulk(std::ostream &os, int version,
273                 const MapNode *nodes, u32 nodecount,
274                 u8 content_width, u8 params_width, bool compressed)
275 {
276         if(!ser_ver_supported(version))
277                 throw VersionMismatchException("ERROR: MapNode format not supported");
278
279         assert(version >= 22);
280         assert(content_width == 1);
281         assert(params_width == 2);
282
283         SharedBuffer<u8> databuf(nodecount * (content_width + params_width));
284
285         // Serialize content
286         if(content_width == 1)
287         {
288                 for(u32 i=0; i<nodecount; i++)
289                         writeU8(&databuf[i], nodes[i].param0);
290         }
291         /* If param0 is extended to two bytes, use something like this: */
292         /*else if(content_width == 2)
293         {
294                 for(u32 i=0; i<nodecount; i++)
295                         writeU16(&databuf[i*2], nodes[i].param0);
296         }*/
297
298         // Serialize param1
299         u32 start1 = content_width * nodecount;
300         for(u32 i=0; i<nodecount; i++)
301                 writeU8(&databuf[start1 + i], nodes[i].param1);
302
303         // Serialize param2
304         u32 start2 = (content_width + 1) * nodecount;
305         for(u32 i=0; i<nodecount; i++)
306                 writeU8(&databuf[start2 + i], nodes[i].param2);
307
308         /*
309                 Compress data to output stream
310         */
311
312         if(compressed)
313         {
314                 compressZlib(databuf, os);
315         }
316         else
317         {
318                 os.write((const char*) &databuf[0], databuf.getSize());
319         }
320 }
321
322 // Deserialize bulk node data
323 void MapNode::deSerializeBulk(std::istream &is, int version,
324                 MapNode *nodes, u32 nodecount,
325                 u8 content_width, u8 params_width, bool compressed)
326 {
327         if(!ser_ver_supported(version))
328                 throw VersionMismatchException("ERROR: MapNode format not supported");
329
330         assert(version >= 22);
331         assert(content_width == 1);
332         assert(params_width == 2);
333
334         // Uncompress or read data
335         u32 len = nodecount * (content_width + params_width);
336         SharedBuffer<u8> databuf(len);
337         if(compressed)
338         {
339                 std::ostringstream os(std::ios_base::binary);
340                 decompressZlib(is, os);
341                 std::string s = os.str();
342                 if(s.size() != len)
343                         throw SerializationError("deSerializeBulkNodes: "
344                                         "decompress resulted in invalid size");
345                 memcpy(&databuf[0], s.c_str(), len);
346         }
347         else
348         {
349                 is.read((char*) &databuf[0], len);
350                 if(is.eof() || is.fail())
351                         throw SerializationError("deSerializeBulkNodes: "
352                                         "failed to read bulk node data");
353         }
354
355         // Deserialize content
356         if(content_width == 1)
357         {
358                 for(u32 i=0; i<nodecount; i++)
359                         nodes[i].param0 = readU8(&databuf[i]);
360         }
361         /* If param0 is extended to two bytes, use something like this: */
362         /*else if(content_width == 2)
363         {
364                 for(u32 i=0; i<nodecount; i++)
365                         nodes[i].param0 = readU16(&databuf[i*2]);
366         }*/
367
368         // Deserialize param1
369         u32 start1 = content_width * nodecount;
370         for(u32 i=0; i<nodecount; i++)
371                 nodes[i].param1 = readU8(&databuf[start1 + i]);
372
373         // Deserialize param2
374         u32 start2 = (content_width + 1) * nodecount;
375         for(u32 i=0; i<nodecount; i++)
376                 nodes[i].param2 = readU8(&databuf[start2 + i]);
377 }
378
379 /*
380         Legacy serialization
381 */
382 void MapNode::serialize_pre22(u8 *dest, u8 version)
383 {
384         // Translate to wanted version
385         MapNode n_foreign = mapnode_translate_from_internal(*this, version);
386
387         u8 actual_param0 = n_foreign.param0;
388
389         // Convert special values from new version to old
390         if(version <= 18)
391         {
392                 // In these versions, CONTENT_IGNORE and CONTENT_AIR
393                 // are 255 and 254
394                 if(actual_param0 == CONTENT_IGNORE)
395                         actual_param0 = 255;
396                 else if(actual_param0 == CONTENT_AIR)
397                         actual_param0 = 254;
398         }
399
400         if(version == 0)
401         {
402                 dest[0] = actual_param0;
403         }
404         else if(version <= 9)
405         {
406                 dest[0] = actual_param0;
407                 dest[1] = n_foreign.param1;
408         }
409         else
410         {
411                 dest[0] = actual_param0;
412                 dest[1] = n_foreign.param1;
413                 dest[2] = n_foreign.param2;
414         }
415 }
416 void MapNode::deSerialize_pre22(u8 *source, u8 version)
417 {
418         if(version <= 1)
419         {
420                 param0 = source[0];
421         }
422         else if(version <= 9)
423         {
424                 param0 = source[0];
425                 param1 = source[1];
426         }
427         else
428         {
429                 param0 = source[0];
430                 param1 = source[1];
431                 param2 = source[2];
432         }
433         
434         // Convert special values from old version to new
435         if(version <= 19)
436         {
437                 // In these versions, CONTENT_IGNORE and CONTENT_AIR
438                 // are 255 and 254
439                 // Version 19 is fucked up with sometimes the old values and sometimes not
440                 if(param0 == 255)
441                         param0 = CONTENT_IGNORE;
442                 else if(param0 == 254)
443                         param0 = CONTENT_AIR;
444         }
445
446         // Translate to our known version
447         *this = mapnode_translate_to_internal(*this, version);
448 }