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 "common_irrlicht.h"
24 #include "main.h" // For g_settings
26 #include "content_mapnode.h" // For mapnode_translate_*_internal
27 #include "serialization.h" // For ser_ver_supported
33 // Create directly from a nodename
34 // If name is unknown, sets CONTENT_IGNORE
35 MapNode::MapNode(INodeDefManager *ndef, const std::string &name,
36 u8 a_param1, u8 a_param2)
38 content_t id = CONTENT_IGNORE;
39 ndef->getId(name, id);
42 // Set content (param0 and (param2&0xf0)) after other params
43 // because this needs to override part of param2
47 void MapNode::setLight(enum LightBank bank, u8 a_light, INodeDefManager *nodemgr)
49 // If node doesn't contain light data, ignore this
50 if(nodemgr->get(*this).param_type != CPT_LIGHT)
52 if(bank == LIGHTBANK_DAY)
55 param1 |= a_light & 0x0f;
57 else if(bank == LIGHTBANK_NIGHT)
60 param1 |= (a_light & 0x0f)<<4;
66 u8 MapNode::getLight(enum LightBank bank, INodeDefManager *nodemgr) const
68 // Select the brightest of [light source, propagated light]
69 const ContentFeatures &f = nodemgr->get(*this);
71 if(f.param_type == CPT_LIGHT)
73 if(bank == LIGHTBANK_DAY)
74 light = param1 & 0x0f;
75 else if(bank == LIGHTBANK_NIGHT)
76 light = (param1>>4)&0x0f;
80 if(f.light_source > light)
81 light = f.light_source;
85 bool MapNode::getLightBanks(u8 &lightday, u8 &lightnight, INodeDefManager *nodemgr) const
87 // Select the brightest of [light source, propagated light]
88 const ContentFeatures &f = nodemgr->get(*this);
89 if(f.param_type == CPT_LIGHT)
91 lightday = param1 & 0x0f;
92 lightnight = (param1>>4)&0x0f;
99 if(f.light_source > lightday)
100 lightday = f.light_source;
101 if(f.light_source > lightnight)
102 lightnight = f.light_source;
103 return f.param_type == CPT_LIGHT || f.light_source != 0;
106 u8 MapNode::getFaceDir(INodeDefManager *nodemgr) const
108 const ContentFeatures &f = nodemgr->get(*this);
109 if(f.param_type_2 == CPT2_FACEDIR)
110 return getParam2() & 0x03;
114 u8 MapNode::getWallMounted(INodeDefManager *nodemgr) const
116 const ContentFeatures &f = nodemgr->get(*this);
117 if(f.param_type_2 == CPT2_WALLMOUNTED)
118 return getParam2() & 0x07;
122 v3s16 MapNode::getWallMountedDir(INodeDefManager *nodemgr) const
124 switch(getWallMounted(nodemgr))
126 case 0: default: return v3s16(0,1,0);
127 case 1: return v3s16(0,-1,0);
128 case 2: return v3s16(1,0,0);
129 case 3: return v3s16(-1,0,0);
130 case 4: return v3s16(0,0,1);
131 case 5: return v3s16(0,0,-1);
137 u32 MapNode::serializedLength(u8 version)
139 if(!ser_ver_supported(version))
140 throw VersionMismatchException("ERROR: MapNode format not supported");
144 else if(version <= 9)
149 void MapNode::serialize(u8 *dest, u8 version)
151 if(!ser_ver_supported(version))
152 throw VersionMismatchException("ERROR: MapNode format not supported");
156 serialize_pre22(dest, version);
160 writeU8(dest+0, param0);
161 writeU8(dest+1, param1);
162 writeU8(dest+2, param2);
164 void MapNode::deSerialize(u8 *source, u8 version)
166 if(!ser_ver_supported(version))
167 throw VersionMismatchException("ERROR: MapNode format not supported");
171 deSerialize_pre22(source, version);
175 param0 = readU8(source+0);
176 param1 = readU8(source+1);
177 param2 = readU8(source+2);
179 void MapNode::serializeBulk(std::ostream &os, int version,
180 const MapNode *nodes, u32 nodecount,
181 u8 content_width, u8 params_width, bool compressed)
183 if(!ser_ver_supported(version))
184 throw VersionMismatchException("ERROR: MapNode format not supported");
186 assert(version >= 22);
187 assert(content_width == 1);
188 assert(params_width == 2);
190 SharedBuffer<u8> databuf(nodecount * (content_width + params_width));
193 if(content_width == 1)
195 for(u32 i=0; i<nodecount; i++)
196 writeU8(&databuf[i], nodes[i].param0);
198 /* If param0 is extended to two bytes, use something like this: */
199 /*else if(content_width == 2)
201 for(u32 i=0; i<nodecount; i++)
202 writeU16(&databuf[i*2], nodes[i].param0);
206 u32 start1 = content_width * nodecount;
207 for(u32 i=0; i<nodecount; i++)
208 writeU8(&databuf[start1 + i], nodes[i].param1);
211 u32 start2 = (content_width + 1) * nodecount;
212 for(u32 i=0; i<nodecount; i++)
213 writeU8(&databuf[start2 + i], nodes[i].param2);
216 Compress data to output stream
221 compressZlib(databuf, os);
225 os.write((const char*) &databuf[0], databuf.getSize());
229 // Deserialize bulk node data
230 void MapNode::deSerializeBulk(std::istream &is, int version,
231 MapNode *nodes, u32 nodecount,
232 u8 content_width, u8 params_width, bool compressed)
234 if(!ser_ver_supported(version))
235 throw VersionMismatchException("ERROR: MapNode format not supported");
237 assert(version >= 22);
238 assert(content_width == 1);
239 assert(params_width == 2);
241 // Uncompress or read data
242 u32 len = nodecount * (content_width + params_width);
243 SharedBuffer<u8> databuf(len);
246 std::ostringstream os(std::ios_base::binary);
247 decompressZlib(is, os);
248 std::string s = os.str();
250 throw SerializationError("deSerializeBulkNodes: "
251 "decompress resulted in invalid size");
252 memcpy(&databuf[0], s.c_str(), len);
256 is.read((char*) &databuf[0], len);
257 if(is.eof() || is.fail())
258 throw SerializationError("deSerializeBulkNodes: "
259 "failed to read bulk node data");
262 // Deserialize content
263 if(content_width == 1)
265 for(u32 i=0; i<nodecount; i++)
266 nodes[i].param0 = readU8(&databuf[i]);
268 /* If param0 is extended to two bytes, use something like this: */
269 /*else if(content_width == 2)
271 for(u32 i=0; i<nodecount; i++)
272 nodes[i].param0 = readU16(&databuf[i*2]);
275 // Deserialize param1
276 u32 start1 = content_width * nodecount;
277 for(u32 i=0; i<nodecount; i++)
278 nodes[i].param1 = readU8(&databuf[start1 + i]);
280 // Deserialize param2
281 u32 start2 = (content_width + 1) * nodecount;
282 for(u32 i=0; i<nodecount; i++)
283 nodes[i].param2 = readU8(&databuf[start2 + i]);
289 void MapNode::serialize_pre22(u8 *dest, u8 version)
291 // Translate to wanted version
292 MapNode n_foreign = mapnode_translate_from_internal(*this, version);
294 u8 actual_param0 = n_foreign.param0;
296 // Convert special values from new version to old
299 // In these versions, CONTENT_IGNORE and CONTENT_AIR
301 if(actual_param0 == CONTENT_IGNORE)
303 else if(actual_param0 == CONTENT_AIR)
309 dest[0] = actual_param0;
311 else if(version <= 9)
313 dest[0] = actual_param0;
314 dest[1] = n_foreign.param1;
318 dest[0] = actual_param0;
319 dest[1] = n_foreign.param1;
320 dest[2] = n_foreign.param2;
323 void MapNode::deSerialize_pre22(u8 *source, u8 version)
329 else if(version <= 9)
341 // Convert special values from old version to new
344 // In these versions, CONTENT_IGNORE and CONTENT_AIR
346 // Version 19 is fucked up with sometimes the old values and sometimes not
348 param0 = CONTENT_IGNORE;
349 else if(param0 == 254)
350 param0 = CONTENT_AIR;
353 // Translate to our known version
354 *this = mapnode_translate_to_internal(*this, version);
361 Nodes make a face if contents differ and solidness differs.
364 1: Face uses m1's content
365 2: Face uses m2's content
366 equivalent: Whether the blocks share the same face (eg. water and glass)
368 TODO: Add 3: Both faces drawn with backface culling, remove equivalent
370 u8 face_contents(content_t m1, content_t m2, bool *equivalent,
371 INodeDefManager *nodemgr)
375 if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
378 bool contents_differ = (m1 != m2);
380 const ContentFeatures &f1 = nodemgr->get(m1);
381 const ContentFeatures &f2 = nodemgr->get(m2);
383 // Contents don't differ for different forms of same liquid
384 if(f1.sameLiquid(f2))
385 contents_differ = false;
387 u8 c1 = f1.solidness;
388 u8 c2 = f2.solidness;
390 bool solidness_differs = (c1 != c2);
391 bool makes_face = contents_differ && solidness_differs;
393 if(makes_face == false)
397 c1 = f1.visual_solidness;
399 c2 = f2.visual_solidness;
403 // If same solidness, liquid takes precense
417 Gets lighting value at face of node
419 Parameters must consist of air and !air.
420 Order doesn't matter.
422 If either of the nodes doesn't exist, light is 0.
425 daynight_ratio: 0...1000
426 n: getNode(p) (uses only the lighting value)
427 n2: getNode(p + face_dir) (uses only the lighting value)
428 face_dir: axis oriented unit vector from p to p2
430 returns encoded light value.
432 u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
433 v3s16 face_dir, INodeDefManager *nodemgr)
437 u8 l1 = n.getLightBlend(daynight_ratio, nodemgr);
438 u8 l2 = n2.getLightBlend(daynight_ratio, nodemgr);
444 // Make some nice difference to different sides
446 // This makes light come from a corner
447 /*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1)
448 light = diminish_light(diminish_light(light));
449 else if(face_dir.X == -1 || face_dir.Z == -1)
450 light = diminish_light(light);*/
452 // All neighboring faces have different shade (like in minecraft)
453 if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1)
454 light = diminish_light(diminish_light(light));
455 else if(face_dir.Z == 1 || face_dir.Z == -1)
456 light = diminish_light(light);
460 catch(InvalidPositionException &e)