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