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