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