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