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