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