]> git.lizzy.rs Git - minetest.git/blob - src/mapnode.h
fixed bug in inventory textures caused from better handling of unknown blocks
[minetest.git] / src / mapnode.h
1 /*
2 Minetest-c55
3 Copyright (C) 2010-2011 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 #ifndef MAPNODE_HEADER
21 #define MAPNODE_HEADER
22
23 #include <iostream>
24 #include "common_irrlicht.h"
25 #include "light.h"
26 #include "utility.h"
27 #include "exceptions.h"
28 #include "serialization.h"
29 #include "tile.h"
30 #include "materials.h"
31
32 /*
33         Naming scheme:
34         - Material = irrlicht's Material class
35         - Content = (u8) content of a node
36         - Tile = TileSpec at some side of a node of some content type
37 */
38
39 /*
40         Initializes all kind of stuff in here.
41         Many things depend on this.
42
43         This accesses g_texturesource; if it is non-NULL, textures are set.
44
45         Client first calls this with g_texturesource=NULL to run some
46         unit tests and stuff, then it runs this again with g_texturesource
47         defined to get the textures.
48
49         Server only calls this once with g_texturesource=NULL.
50 */
51 void init_mapnode();
52
53 /*
54         Ignored node.
55
56         Anything that stores MapNodes doesn't have to preserve parameters
57         associated with this material.
58         
59         Doesn't create faces with anything and is considered being
60         out-of-map in the game map.
61 */
62 #define CONTENT_IGNORE 255
63 #define CONTENT_IGNORE_DEFAULT_PARAM 0
64
65 /*
66         The common material through which the player can walk and which
67         is transparent to light
68 */
69 #define CONTENT_AIR 254
70
71 /*
72         Content feature list
73 */
74
75 enum ContentParamType
76 {
77         CPT_NONE,
78         CPT_LIGHT,
79         CPT_MINERAL,
80         // Direction for chests and furnaces and such
81         CPT_FACEDIR_SIMPLE
82 };
83
84 enum LiquidType
85 {
86         LIQUID_NONE,
87         LIQUID_FLOWING,
88         LIQUID_SOURCE
89 };
90
91 class MapNode;
92 class NodeMetadata;
93
94 struct ContentFeatures
95 {
96         // If non-NULL, content is translated to this when deserialized
97         MapNode *translate_to;
98
99         // Type of MapNode::param
100         ContentParamType param_type;
101
102         /*
103                 0: up
104                 1: down
105                 2: right
106                 3: left
107                 4: back
108                 5: front
109         */
110         TileSpec tiles[6];
111         
112         video::ITexture *inventory_texture;
113
114         bool is_ground_content;
115         bool light_propagates;
116         bool sunlight_propagates;
117         u8 solidness; // Used when choosing which face is drawn
118         // This is used for collision detection.
119         // Also for general solidness queries.
120         bool walkable;
121         // Player can point to these
122         bool pointable;
123         // Player can dig these
124         bool diggable;
125         // Player can build on these
126         bool buildable_to;
127         // Whether the node has no liquid, source liquid or flowing liquid
128         enum LiquidType liquid_type;
129         // If true, param2 is set to direction when placed. Used for torches.
130         // NOTE: the direction format is quite inefficient and should be changed
131         bool wall_mounted;
132         // If true, node is equivalent to air. Torches are, air is. Water is not.
133         // Is used for example to check whether a mud block can have grass on.
134         bool air_equivalent;
135         
136         // Inventory item string as which the node appears in inventory when dug.
137         // Mineral overrides this.
138         std::string dug_item;
139         
140         // Initial metadata is cloned from this
141         NodeMetadata *initial_metadata;
142         
143         // If the content is liquid, this is the flowing version of the liquid.
144         // If content is liquid, this is the same content.
145         u8 liquid_alternative_flowing;
146         
147         // Amount of light the node emits
148         u8 light_source;
149         
150         // Digging properties for different tools
151         DiggingPropertiesList digging_properties;
152         
153         // NOTE: Move relevant properties to here from elsewhere
154
155         void reset()
156         {
157                 translate_to = NULL;
158                 param_type = CPT_NONE;
159                 inventory_texture = NULL;
160                 is_ground_content = false;
161                 light_propagates = false;
162                 sunlight_propagates = false;
163                 solidness = 2;
164                 walkable = true;
165                 pointable = true;
166                 diggable = true;
167                 buildable_to = false;
168                 liquid_type = LIQUID_NONE;
169                 wall_mounted = false;
170                 air_equivalent = false;
171                 dug_item = "";
172                 initial_metadata = NULL;
173                 liquid_alternative_flowing = CONTENT_IGNORE;
174                 light_source = 0;
175                 digging_properties.clear();
176         }
177
178         ContentFeatures()
179         {
180                 reset();
181         }
182
183         ~ContentFeatures();
184         
185         /*
186                 Quickhands for simple materials
187         */
188         
189         void setTexture(u16 i, std::string name, u8 alpha=255);
190
191         void setAllTextures(std::string name, u8 alpha=255)
192         {
193                 for(u16 i=0; i<6; i++)
194                 {
195                         setTexture(i, name, alpha);
196                 }
197                 // Force inventory texture too
198                 setInventoryTexture(name);
199         }
200
201         void setTile(u16 i, const TileSpec &tile)
202         {
203                 tiles[i] = tile;
204         }
205         void setAllTiles(const TileSpec &tile)
206         {
207                 for(u16 i=0; i<6; i++)
208                 {
209                         setTile(i, tile);
210                 }
211         }
212
213         void setInventoryTexture(std::string imgname);
214         
215         void setInventoryTextureCube(std::string top,
216                         std::string left, std::string right);
217 };
218
219 /*
220         Call this to access the ContentFeature list
221 */
222 ContentFeatures & content_features(u8 i);
223
224
225 /*
226         Here is a bunch of DEPRECATED functions.
227 */
228
229 /*
230         If true, the material allows light propagation and brightness is stored
231         in param.
232         NOTE: Don't use, use "content_features(m).whatever" instead
233 */
234 inline bool light_propagates_content(u8 m)
235 {
236         return content_features(m).light_propagates;
237 }
238 /*
239         If true, the material allows lossless sunlight propagation.
240         NOTE: It doesn't seem to go through torches regardlessly of this
241         NOTE: Don't use, use "content_features(m).whatever" instead
242 */
243 inline bool sunlight_propagates_content(u8 m)
244 {
245         return content_features(m).sunlight_propagates;
246 }
247 /*
248         On a node-node surface, the material of the node with higher solidness
249         is used for drawing.
250         0: Invisible
251         1: Transparent
252         2: Opaque
253         NOTE: Don't use, use "content_features(m).whatever" instead
254 */
255 inline u8 content_solidness(u8 m)
256 {
257         return content_features(m).solidness;
258 }
259 // Objects collide with walkable contents
260 // NOTE: Don't use, use "content_features(m).whatever" instead
261 inline bool content_walkable(u8 m)
262 {
263         return content_features(m).walkable;
264 }
265 // NOTE: Don't use, use "content_features(m).whatever" instead
266 inline bool content_liquid(u8 m)
267 {
268         return content_features(m).liquid_type != LIQUID_NONE;
269 }
270 // NOTE: Don't use, use "content_features(m).whatever" instead
271 inline bool content_flowing_liquid(u8 m)
272 {
273         return content_features(m).liquid_type == LIQUID_FLOWING;
274 }
275 // NOTE: Don't use, use "content_features(m).whatever" instead
276 inline bool content_liquid_source(u8 m)
277 {
278         return content_features(m).liquid_type == LIQUID_SOURCE;
279 }
280 // CONTENT_WATER || CONTENT_WATERSOURCE -> CONTENT_WATER
281 // CONTENT_LAVA || CONTENT_LAVASOURCE -> CONTENT_LAVA
282 // NOTE: Don't use, use "content_features(m).whatever" instead
283 inline u8 make_liquid_flowing(u8 m)
284 {
285         u8 c = content_features(m).liquid_alternative_flowing;
286         assert(c != CONTENT_IGNORE);
287         return c;
288 }
289 // Pointable contents can be pointed to in the map
290 // NOTE: Don't use, use "content_features(m).whatever" instead
291 inline bool content_pointable(u8 m)
292 {
293         return content_features(m).pointable;
294 }
295 // NOTE: Don't use, use "content_features(m).whatever" instead
296 inline bool content_diggable(u8 m)
297 {
298         return content_features(m).diggable;
299 }
300 // NOTE: Don't use, use "content_features(m).whatever" instead
301 inline bool content_buildable_to(u8 m)
302 {
303         return content_features(m).buildable_to;
304 }
305
306 /*
307         Nodes make a face if contents differ and solidness differs.
308         Return value:
309                 0: No face
310                 1: Face uses m1's content
311                 2: Face uses m2's content
312 */
313 inline u8 face_contents(u8 m1, u8 m2)
314 {
315         if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
316                 return 0;
317         
318         bool contents_differ = (m1 != m2);
319         
320         // Contents don't differ for different forms of same liquid
321         if(content_liquid(m1) && content_liquid(m2)
322                         && make_liquid_flowing(m1) == make_liquid_flowing(m2))
323                 contents_differ = false;
324         
325         bool solidness_differs = (content_solidness(m1) != content_solidness(m2));
326         bool makes_face = contents_differ && solidness_differs;
327
328         if(makes_face == false)
329                 return 0;
330
331         if(content_solidness(m1) > content_solidness(m2))
332                 return 1;
333         else
334                 return 2;
335 }
336
337 /*
338         Packs directions like (1,0,0), (1,-1,0)
339 */
340 inline u8 packDir(v3s16 dir)
341 {
342         u8 b = 0;
343
344         if(dir.X > 0)
345                 b |= (1<<0);
346         else if(dir.X < 0)
347                 b |= (1<<1);
348
349         if(dir.Y > 0)
350                 b |= (1<<2);
351         else if(dir.Y < 0)
352                 b |= (1<<3);
353
354         if(dir.Z > 0)
355                 b |= (1<<4);
356         else if(dir.Z < 0)
357                 b |= (1<<5);
358         
359         return b;
360 }
361 inline v3s16 unpackDir(u8 b)
362 {
363         v3s16 d(0,0,0);
364
365         if(b & (1<<0))
366                 d.X = 1;
367         else if(b & (1<<1))
368                 d.X = -1;
369
370         if(b & (1<<2))
371                 d.Y = 1;
372         else if(b & (1<<3))
373                 d.Y = -1;
374
375         if(b & (1<<4))
376                 d.Z = 1;
377         else if(b & (1<<5))
378                 d.Z = -1;
379         
380         return d;
381 }
382
383 /*
384         facedir: CPT_FACEDIR_SIMPLE param1 value
385         dir: The face for which stuff is wanted
386         return value: The face from which the stuff is actually found
387 */
388 v3s16 facedir_rotate(u8 facedir, v3s16 dir);
389
390 enum LightBank
391 {
392         LIGHTBANK_DAY,
393         LIGHTBANK_NIGHT
394 };
395
396 /*
397         This is the stuff what the whole world consists of.
398 */
399
400 struct MapNode
401 {
402         // Content
403         u8 d;
404
405         /*
406                 Misc parameter. Initialized to 0.
407                 - For light_propagates() blocks, this is light intensity,
408                   stored logarithmically from 0 to LIGHT_MAX.
409                   Sunlight is LIGHT_SUN, which is LIGHT_MAX+1.
410                 - Contains 2 values, day- and night lighting. Each takes 4 bits.
411         */
412         union
413         {
414                 s8 param;
415                 u8 param1;
416         };
417         
418         /*
419                 The second parameter. Initialized to 0.
420                 E.g. direction for torches and flowing water.
421         */
422         union
423         {
424                 u8 param2;
425                 u8 dir;
426         };
427
428         MapNode(const MapNode & n)
429         {
430                 *this = n;
431         }
432         
433         MapNode(u8 data=CONTENT_AIR, u8 a_param=0, u8 a_param2=0)
434         {
435                 d = data;
436                 param = a_param;
437                 param2 = a_param2;
438         }
439
440         /*MapNode & operator=(const MapNode &other)
441         {
442                 d = other.d;
443                 param = other.param;
444                 param2 = other.param2;
445                 return *this;
446         }*/
447
448         bool operator==(const MapNode &other)
449         {
450                 return (d == other.d
451                                 && param == other.param
452                                 && param2 == other.param2);
453         }
454         
455         /*
456                 These four are DEPRECATED I guess. -c55
457         */
458         bool light_propagates()
459         {
460                 return light_propagates_content(d);
461         }
462         bool sunlight_propagates()
463         {
464                 return sunlight_propagates_content(d);
465         }
466         u8 solidness()
467         {
468                 return content_solidness(d);
469         }
470         u8 light_source()
471         {
472                 return content_features(d).light_source;
473         }
474
475         u8 getLightBanksWithSource()
476         {
477                 // Select the brightest of [light source, propagated light]
478                 u8 lightday = 0;
479                 u8 lightnight = 0;
480                 if(content_features(d).param_type == CPT_LIGHT)
481                 {
482                         lightday = param & 0x0f;
483                         lightnight = (param>>4)&0x0f;
484                 }
485                 if(light_source() > lightday)
486                         lightday = light_source();
487                 if(light_source() > lightnight)
488                         lightnight = light_source();
489                 return (lightday&0x0f) | ((lightnight<<4)&0xf0);
490         }
491
492         u8 getLight(enum LightBank bank)
493         {
494                 // Select the brightest of [light source, propagated light]
495                 u8 light = 0;
496                 if(content_features(d).param_type == CPT_LIGHT)
497                 {
498                         if(bank == LIGHTBANK_DAY)
499                                 light = param & 0x0f;
500                         else if(bank == LIGHTBANK_NIGHT)
501                                 light = (param>>4)&0x0f;
502                         else
503                                 assert(0);
504                 }
505                 if(light_source() > light)
506                         light = light_source();
507                 return light;
508         }
509         
510         // 0 <= daylight_factor <= 1000
511         // 0 <= return value <= LIGHT_SUN
512         u8 getLightBlend(u32 daylight_factor)
513         {
514                 u8 l = ((daylight_factor * getLight(LIGHTBANK_DAY)
515                         + (1000-daylight_factor) * getLight(LIGHTBANK_NIGHT))
516                         )/1000;
517                 u8 max = LIGHT_MAX;
518                 if(getLight(LIGHTBANK_DAY) == LIGHT_SUN)
519                         max = LIGHT_SUN;
520                 if(l > max)
521                         l = max;
522                 return l;
523         }
524         /*// 0 <= daylight_factor <= 1000
525         // 0 <= return value <= 255
526         u8 getLightBlend(u32 daylight_factor)
527         {
528                 u8 daylight = decode_light(getLight(LIGHTBANK_DAY));
529                 u8 nightlight = decode_light(getLight(LIGHTBANK_NIGHT));
530                 u8 mix = ((daylight_factor * daylight
531                         + (1000-daylight_factor) * nightlight)
532                         )/1000;
533                 return mix;
534         }*/
535
536         void setLight(enum LightBank bank, u8 a_light)
537         {
538                 // If node doesn't contain light data, ignore this
539                 if(content_features(d).param_type != CPT_LIGHT)
540                         return;
541                 if(bank == LIGHTBANK_DAY)
542                 {
543                         param &= 0xf0;
544                         param |= a_light & 0x0f;
545                 }
546                 else if(bank == LIGHTBANK_NIGHT)
547                 {
548                         param &= 0x0f;
549                         param |= (a_light & 0x0f)<<4;
550                 }
551                 else
552                         assert(0);
553         }
554         
555         // In mapnode.cpp
556         /*
557                 Get tile of a face of the node.
558                 dir: direction of face
559                 Returns: TileSpec. Can contain miscellaneous texture coordinates,
560                          which must be obeyed so that the texture atlas can be used.
561         */
562         TileSpec getTile(v3s16 dir);
563         
564         /*
565                 Gets mineral content of node, if there is any.
566                 MINERAL_NONE if doesn't contain or isn't able to contain mineral.
567         */
568         u8 getMineral();
569
570         /*
571                 These serialization functions are used when informing client
572                 of a single node add.
573
574                 NOTE: When loading a MapBlock, these are not used. Should they?
575         */
576
577         static u32 serializedLength(u8 version)
578         {
579                 if(!ser_ver_supported(version))
580                         throw VersionMismatchException("ERROR: MapNode format not supported");
581                         
582                 if(version == 0)
583                         return 1;
584                 else if(version <= 9)
585                         return 2;
586                 else
587                         return 3;
588         }
589         void serialize(u8 *dest, u8 version)
590         {
591                 if(!ser_ver_supported(version))
592                         throw VersionMismatchException("ERROR: MapNode format not supported");
593                         
594                 if(version == 0)
595                 {
596                         dest[0] = d;
597                 }
598                 else if(version <= 9)
599                 {
600                         dest[0] = d;
601                         dest[1] = param;
602                 }
603                 else
604                 {
605                         dest[0] = d;
606                         dest[1] = param;
607                         dest[2] = param2;
608                 }
609         }
610         void deSerialize(u8 *source, u8 version)
611         {
612                 if(!ser_ver_supported(version))
613                         throw VersionMismatchException("ERROR: MapNode format not supported");
614                         
615                 if(version == 0)
616                 {
617                         d = source[0];
618                 }
619                 else if(version == 1)
620                 {
621                         d = source[0];
622                         // This version doesn't support saved lighting
623                         if(light_propagates() || light_source() > 0)
624                                 param = 0;
625                         else
626                                 param = source[1];
627                 }
628                 else if(version <= 9)
629                 {
630                         d = source[0];
631                         param = source[1];
632                 }
633                 else
634                 {
635                         d = source[0];
636                         param = source[1];
637                         param2 = source[2];
638                 }
639
640                 // Translate deprecated stuff
641                 // NOTE: This doesn't get used because MapBlock handles node
642                 // parameters directly
643                 MapNode *translate_to = content_features(d).translate_to;
644                 if(translate_to)
645                 {
646                         dstream<<"MapNode: WARNING: Translating "<<d<<" to "
647                                         <<translate_to->d<<std::endl;
648                         *this = *translate_to;
649                 }
650         }
651 };
652
653 /*
654         Gets lighting value at face of node
655         
656         Parameters must consist of air and !air.
657         Order doesn't matter.
658
659         If either of the nodes doesn't exist, light is 0.
660         
661         parameters:
662                 daynight_ratio: 0...1000
663                 n: getNodeParent(p)
664                 n2: getNodeParent(p + face_dir)
665                 face_dir: axis oriented unit vector from p to p2
666         
667         returns encoded light value.
668 */
669 u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
670                 v3s16 face_dir);
671
672 #endif
673