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