]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mapnode.cpp
Node definition names
[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 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 "common_irrlicht.h"
21 #include "mapnode.h"
22 #include "porting.h"
23 #include <string>
24 #include "mineral.h"
25 #include "main.h" // For g_settings
26 #include "nodedef.h"
27 #include "content_mapnode.h" // For mapnode_translate_*_internal
28 #include "serialization.h" // For ser_ver_supported
29
30 #ifndef SERVER
31 /*
32         Nodes make a face if contents differ and solidness differs.
33         Return value:
34                 0: No face
35                 1: Face uses m1's content
36                 2: Face uses m2's content
37         equivalent: Whether the blocks share the same face (eg. water and glass)
38
39         TODO: Add 3: Both faces drawn with backface culling, remove equivalent
40 */
41 u8 face_contents(content_t m1, content_t m2, bool *equivalent,
42                 INodeDefManager *nodemgr)
43 {
44         *equivalent = false;
45
46         if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
47                 return 0;
48         
49         bool contents_differ = (m1 != m2);
50         
51         const ContentFeatures &f1 = nodemgr->get(m1);
52         const ContentFeatures &f2 = nodemgr->get(m2);
53
54         // Contents don't differ for different forms of same liquid
55         if(f1.sameLiquid(f2))
56                 contents_differ = false;
57         
58         u8 c1 = f1.solidness;
59         u8 c2 = f2.solidness;
60
61         bool solidness_differs = (c1 != c2);
62         bool makes_face = contents_differ && solidness_differs;
63
64         if(makes_face == false)
65                 return 0;
66         
67         if(c1 == 0)
68                 c1 = f1.visual_solidness;
69         if(c2 == 0)
70                 c2 = f2.visual_solidness;
71         
72         if(c1 == c2){
73                 *equivalent = true;
74                 // If same solidness, liquid takes precense
75                 if(f1.isLiquid())
76                         return 1;
77                 if(f2.isLiquid())
78                         return 2;
79         }
80         
81         if(c1 > c2)
82                 return 1;
83         else
84                 return 2;
85 }
86 #endif
87
88 v3s16 facedir_rotate(u8 facedir, v3s16 dir)
89 {
90         /*
91                 Face 2 (normally Z-) direction:
92                 facedir=0: Z-
93                 facedir=1: X-
94                 facedir=2: Z+
95                 facedir=3: X+
96         */
97         v3s16 newdir;
98         if(facedir==0) // Same
99                 newdir = v3s16(dir.X, dir.Y, dir.Z);
100         else if(facedir == 1) // Face is taken from rotXZccv(-90)
101                 newdir = v3s16(-dir.Z, dir.Y, dir.X);
102         else if(facedir == 2) // Face is taken from rotXZccv(180)
103                 newdir = v3s16(-dir.X, dir.Y, -dir.Z);
104         else if(facedir == 3) // Face is taken from rotXZccv(90)
105                 newdir = v3s16(dir.Z, dir.Y, -dir.X);
106         else
107                 newdir = dir;
108         return newdir;
109 }
110
111 u8 packDir(v3s16 dir)
112 {
113         u8 b = 0;
114
115         if(dir.X > 0)
116                 b |= (1<<0);
117         else if(dir.X < 0)
118                 b |= (1<<1);
119
120         if(dir.Y > 0)
121                 b |= (1<<2);
122         else if(dir.Y < 0)
123                 b |= (1<<3);
124
125         if(dir.Z > 0)
126                 b |= (1<<4);
127         else if(dir.Z < 0)
128                 b |= (1<<5);
129         
130         return b;
131 }
132 v3s16 unpackDir(u8 b)
133 {
134         v3s16 d(0,0,0);
135
136         if(b & (1<<0))
137                 d.X = 1;
138         else if(b & (1<<1))
139                 d.X = -1;
140
141         if(b & (1<<2))
142                 d.Y = 1;
143         else if(b & (1<<3))
144                 d.Y = -1;
145
146         if(b & (1<<4))
147                 d.Z = 1;
148         else if(b & (1<<5))
149                 d.Z = -1;
150         
151         return d;
152 }
153
154 /*
155         MapNode
156 */
157
158 void MapNode::setLight(enum LightBank bank, u8 a_light, INodeDefManager *nodemgr)
159 {
160         // If node doesn't contain light data, ignore this
161         if(nodemgr->get(*this).param_type != CPT_LIGHT)
162                 return;
163         if(bank == LIGHTBANK_DAY)
164         {
165                 param1 &= 0xf0;
166                 param1 |= a_light & 0x0f;
167         }
168         else if(bank == LIGHTBANK_NIGHT)
169         {
170                 param1 &= 0x0f;
171                 param1 |= (a_light & 0x0f)<<4;
172         }
173         else
174                 assert(0);
175 }
176
177 u8 MapNode::getLight(enum LightBank bank, INodeDefManager *nodemgr) const
178 {
179         // Select the brightest of [light source, propagated light]
180         u8 light = 0;
181         if(nodemgr->get(*this).param_type == CPT_LIGHT)
182         {
183                 if(bank == LIGHTBANK_DAY)
184                         light = param1 & 0x0f;
185                 else if(bank == LIGHTBANK_NIGHT)
186                         light = (param1>>4)&0x0f;
187                 else
188                         assert(0);
189         }
190         if(nodemgr->get(*this).light_source > light)
191                 light = nodemgr->get(*this).light_source;
192         return light;
193 }
194
195 u8 MapNode::getLightBanksWithSource(INodeDefManager *nodemgr) const
196 {
197         // Select the brightest of [light source, propagated light]
198         u8 lightday = 0;
199         u8 lightnight = 0;
200         if(nodemgr->get(*this).param_type == CPT_LIGHT)
201         {
202                 lightday = param1 & 0x0f;
203                 lightnight = (param1>>4)&0x0f;
204         }
205         if(nodemgr->get(*this).light_source > lightday)
206                 lightday = nodemgr->get(*this).light_source;
207         if(nodemgr->get(*this).light_source > lightnight)
208                 lightnight = nodemgr->get(*this).light_source;
209         return (lightday&0x0f) | ((lightnight<<4)&0xf0);
210 }
211
212 u8 MapNode::getMineral(INodeDefManager *nodemgr) const
213 {
214         if(nodemgr->get(*this).param_type == CPT_MINERAL)
215         {
216                 return param1 & 0x0f;
217         }
218
219         return MINERAL_NONE;
220 }
221
222 u32 MapNode::serializedLength(u8 version)
223 {
224         if(!ser_ver_supported(version))
225                 throw VersionMismatchException("ERROR: MapNode format not supported");
226                 
227         if(version == 0)
228                 return 1;
229         else if(version <= 9)
230                 return 2;
231         else
232                 return 3;
233 }
234 void MapNode::serialize(u8 *dest, u8 version)
235 {
236         if(!ser_ver_supported(version))
237                 throw VersionMismatchException("ERROR: MapNode format not supported");
238                 
239         // Translate to wanted version
240         MapNode n_foreign = mapnode_translate_from_internal(*this, version);
241
242         u8 actual_param0 = n_foreign.param0;
243
244         // Convert special values from new version to old
245         if(version <= 18)
246         {
247                 // In these versions, CONTENT_IGNORE and CONTENT_AIR
248                 // are 255 and 254
249                 if(actual_param0 == CONTENT_IGNORE)
250                         actual_param0 = 255;
251                 else if(actual_param0 == CONTENT_AIR)
252                         actual_param0 = 254;
253         }
254
255         if(version == 0)
256         {
257                 dest[0] = actual_param0;
258         }
259         else if(version <= 9)
260         {
261                 dest[0] = actual_param0;
262                 dest[1] = n_foreign.param1;
263         }
264         else
265         {
266                 dest[0] = actual_param0;
267                 dest[1] = n_foreign.param1;
268                 dest[2] = n_foreign.param2;
269         }
270 }
271 void MapNode::deSerialize(u8 *source, u8 version)
272 {
273         if(!ser_ver_supported(version))
274                 throw VersionMismatchException("ERROR: MapNode format not supported");
275                 
276         if(version == 0)
277         {
278                 param0 = source[0];
279         }
280         else if(version == 1)
281         {
282                 param0 = source[0];
283         }
284         else if(version <= 9)
285         {
286                 param0 = source[0];
287                 param1 = source[1];
288         }
289         else
290         {
291                 param0 = source[0];
292                 param1 = source[1];
293                 param2 = source[2];
294         }
295         
296         // Convert special values from old version to new
297         if(version <= 18)
298         {
299                 // In these versions, CONTENT_IGNORE and CONTENT_AIR
300                 // are 255 and 254
301                 if(param0 == 255)
302                         param0 = CONTENT_IGNORE;
303                 else if(param0 == 254)
304                         param0 = CONTENT_AIR;
305         }
306         // version 19 is fucked up with sometimes the old values and sometimes not
307         if(version == 19)
308         {
309                 if(param0 == 255)
310                         param0 = CONTENT_IGNORE;
311                 else if(param0 == 254)
312                         param0 = CONTENT_AIR;
313         }
314
315         // Translate to our known version
316         *this = mapnode_translate_to_internal(*this, version);
317 }
318
319 /*
320         Gets lighting value at face of node
321         
322         Parameters must consist of air and !air.
323         Order doesn't matter.
324
325         If either of the nodes doesn't exist, light is 0.
326         
327         parameters:
328                 daynight_ratio: 0...1000
329                 n: getNode(p) (uses only the lighting value)
330                 n2: getNode(p + face_dir) (uses only the lighting value)
331                 face_dir: axis oriented unit vector from p to p2
332         
333         returns encoded light value.
334 */
335 u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
336                 v3s16 face_dir, INodeDefManager *nodemgr)
337 {
338         try{
339                 u8 light;
340                 u8 l1 = n.getLightBlend(daynight_ratio, nodemgr);
341                 u8 l2 = n2.getLightBlend(daynight_ratio, nodemgr);
342                 if(l1 > l2)
343                         light = l1;
344                 else
345                         light = l2;
346
347                 // Make some nice difference to different sides
348
349                 // This makes light come from a corner
350                 /*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1)
351                         light = diminish_light(diminish_light(light));
352                 else if(face_dir.X == -1 || face_dir.Z == -1)
353                         light = diminish_light(light);*/
354                 
355                 // All neighboring faces have different shade (like in minecraft)
356                 if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1)
357                         light = diminish_light(diminish_light(light));
358                 else if(face_dir.Z == 1 || face_dir.Z == -1)
359                         light = diminish_light(light);
360
361                 return light;
362         }
363         catch(InvalidPositionException &e)
364         {
365                 return 0;
366         }
367 }
368
369