]> git.lizzy.rs Git - minetest.git/blob - src/nodedef.cpp
31366f7e08f2858b2be969f1e08f15fb5183f4c6
[minetest.git] / src / nodedef.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 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 Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser 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 #include "nodedef.h"
21
22 #include "itemdef.h"
23 #ifndef SERVER
24 #include "client/tile.h"
25 #include "mesh.h"
26 #include <IMeshManipulator.h>
27 #endif
28 #include "log.h"
29 #include "settings.h"
30 #include "nameidmapping.h"
31 #include "util/numeric.h"
32 #include "util/serialize.h"
33 #include "exceptions.h"
34 #include "debug.h"
35 #include "gamedef.h"
36 #include <fstream> // Used in applyTextureOverrides()
37
38 /*
39         NodeBox
40 */
41
42 void NodeBox::reset()
43 {
44         type = NODEBOX_REGULAR;
45         // default is empty
46         fixed.clear();
47         // default is sign/ladder-like
48         wall_top = aabb3f(-BS/2, BS/2-BS/16., -BS/2, BS/2, BS/2, BS/2);
49         wall_bottom = aabb3f(-BS/2, -BS/2, -BS/2, BS/2, -BS/2+BS/16., BS/2);
50         wall_side = aabb3f(-BS/2, -BS/2, -BS/2, -BS/2+BS/16., BS/2, BS/2);
51 }
52
53 void NodeBox::serialize(std::ostream &os, u16 protocol_version) const
54 {
55         int version = protocol_version >= 21 ? 2 : 1;
56         writeU8(os, version);
57
58         if (version == 1 && type == NODEBOX_LEVELED)
59                 writeU8(os, NODEBOX_FIXED);
60         else
61                 writeU8(os, type);
62
63         if(type == NODEBOX_FIXED || type == NODEBOX_LEVELED)
64         {
65                 writeU16(os, fixed.size());
66                 for(std::vector<aabb3f>::const_iterator
67                                 i = fixed.begin();
68                                 i != fixed.end(); ++i)
69                 {
70                         writeV3F1000(os, i->MinEdge);
71                         writeV3F1000(os, i->MaxEdge);
72                 }
73         }
74         else if(type == NODEBOX_WALLMOUNTED)
75         {
76                 writeV3F1000(os, wall_top.MinEdge);
77                 writeV3F1000(os, wall_top.MaxEdge);
78                 writeV3F1000(os, wall_bottom.MinEdge);
79                 writeV3F1000(os, wall_bottom.MaxEdge);
80                 writeV3F1000(os, wall_side.MinEdge);
81                 writeV3F1000(os, wall_side.MaxEdge);
82         }
83 }
84
85 void NodeBox::deSerialize(std::istream &is)
86 {
87         int version = readU8(is);
88         if(version < 1 || version > 2)
89                 throw SerializationError("unsupported NodeBox version");
90
91         reset();
92
93         type = (enum NodeBoxType)readU8(is);
94
95         if(type == NODEBOX_FIXED || type == NODEBOX_LEVELED)
96         {
97                 u16 fixed_count = readU16(is);
98                 while(fixed_count--)
99                 {
100                         aabb3f box;
101                         box.MinEdge = readV3F1000(is);
102                         box.MaxEdge = readV3F1000(is);
103                         fixed.push_back(box);
104                 }
105         }
106         else if(type == NODEBOX_WALLMOUNTED)
107         {
108                 wall_top.MinEdge = readV3F1000(is);
109                 wall_top.MaxEdge = readV3F1000(is);
110                 wall_bottom.MinEdge = readV3F1000(is);
111                 wall_bottom.MaxEdge = readV3F1000(is);
112                 wall_side.MinEdge = readV3F1000(is);
113                 wall_side.MaxEdge = readV3F1000(is);
114         }
115 }
116
117 /*
118         TileDef
119 */
120
121 void TileDef::serialize(std::ostream &os, u16 protocol_version) const
122 {
123         if (protocol_version >= 26)
124                 writeU8(os, 2);
125         else if (protocol_version >= 17)
126                 writeU8(os, 1);
127         else
128                 writeU8(os, 0);
129         os<<serializeString(name);
130         writeU8(os, animation.type);
131         writeU16(os, animation.aspect_w);
132         writeU16(os, animation.aspect_h);
133         writeF1000(os, animation.length);
134         if (protocol_version >= 17)
135                 writeU8(os, backface_culling);
136         if (protocol_version >= 26) {
137                 writeU8(os, tileable_horizontal);
138                 writeU8(os, tileable_vertical);
139         }
140 }
141
142 void TileDef::deSerialize(std::istream &is, const u8 contenfeatures_version, const NodeDrawType drawtype)
143 {
144         int version = readU8(is);
145         name = deSerializeString(is);
146         animation.type = (TileAnimationType)readU8(is);
147         animation.aspect_w = readU16(is);
148         animation.aspect_h = readU16(is);
149         animation.length = readF1000(is);
150         if (version >= 1)
151                 backface_culling = readU8(is);
152         if (version >= 2) {
153                 tileable_horizontal = readU8(is);
154                 tileable_vertical = readU8(is);
155         }
156
157         if ((contenfeatures_version < 8) &&
158                 ((drawtype == NDT_MESH) ||
159                  (drawtype == NDT_FIRELIKE) ||
160                  (drawtype == NDT_LIQUID) ||
161                  (drawtype == NDT_PLANTLIKE)))
162                 backface_culling = false;
163 }
164
165
166 /*
167         SimpleSoundSpec serialization
168 */
169
170 static void serializeSimpleSoundSpec(const SimpleSoundSpec &ss,
171                 std::ostream &os)
172 {
173         os<<serializeString(ss.name);
174         writeF1000(os, ss.gain);
175 }
176 static void deSerializeSimpleSoundSpec(SimpleSoundSpec &ss, std::istream &is)
177 {
178         ss.name = deSerializeString(is);
179         ss.gain = readF1000(is);
180 }
181
182 /*
183         ContentFeatures
184 */
185
186 ContentFeatures::ContentFeatures()
187 {
188         reset();
189 }
190
191 ContentFeatures::~ContentFeatures()
192 {
193 }
194
195 void ContentFeatures::reset()
196 {
197         /*
198                 Cached stuff
199         */
200 #ifndef SERVER
201         solidness = 2;
202         visual_solidness = 0;
203         backface_culling = true;
204
205 #endif
206         has_on_construct = false;
207         has_on_destruct = false;
208         has_after_destruct = false;
209         /*
210                 Actual data
211
212                 NOTE: Most of this is always overridden by the default values given
213                       in builtin.lua
214         */
215         name = "";
216         groups.clear();
217         // Unknown nodes can be dug
218         groups["dig_immediate"] = 2;
219         drawtype = NDT_NORMAL;
220         mesh = "";
221 #ifndef SERVER
222         for(u32 i = 0; i < 24; i++)
223                 mesh_ptr[i] = NULL;
224         minimap_color = video::SColor(0, 0, 0, 0);
225 #endif
226         visual_scale = 1.0;
227         for(u32 i = 0; i < 6; i++)
228                 tiledef[i] = TileDef();
229         for(u16 j = 0; j < CF_SPECIAL_COUNT; j++)
230                 tiledef_special[j] = TileDef();
231         alpha = 255;
232         post_effect_color = video::SColor(0, 0, 0, 0);
233         param_type = CPT_NONE;
234         param_type_2 = CPT2_NONE;
235         is_ground_content = false;
236         light_propagates = false;
237         sunlight_propagates = false;
238         walkable = true;
239         pointable = true;
240         diggable = true;
241         climbable = false;
242         buildable_to = false;
243         floodable = false;
244         rightclickable = true;
245         leveled = 0;
246         liquid_type = LIQUID_NONE;
247         liquid_alternative_flowing = "";
248         liquid_alternative_source = "";
249         liquid_viscosity = 0;
250         liquid_renewable = true;
251         liquid_range = LIQUID_LEVEL_MAX+1;
252         drowning = 0;
253         light_source = 0;
254         damage_per_second = 0;
255         node_box = NodeBox();
256         selection_box = NodeBox();
257         collision_box = NodeBox();
258         waving = 0;
259         legacy_facedir_simple = false;
260         legacy_wallmounted = false;
261         sound_footstep = SimpleSoundSpec();
262         sound_dig = SimpleSoundSpec("__group");
263         sound_dug = SimpleSoundSpec();
264 }
265
266 void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const
267 {
268         if(protocol_version < 24){
269                 serializeOld(os, protocol_version);
270                 return;
271         }
272
273         writeU8(os, protocol_version < 27 ? 7 : 8);
274
275         os<<serializeString(name);
276         writeU16(os, groups.size());
277         for(ItemGroupList::const_iterator
278                         i = groups.begin(); i != groups.end(); ++i){
279                 os<<serializeString(i->first);
280                 writeS16(os, i->second);
281         }
282         writeU8(os, drawtype);
283         writeF1000(os, visual_scale);
284         writeU8(os, 6);
285         for(u32 i = 0; i < 6; i++)
286                 tiledef[i].serialize(os, protocol_version);
287         writeU8(os, CF_SPECIAL_COUNT);
288         for(u32 i = 0; i < CF_SPECIAL_COUNT; i++){
289                 tiledef_special[i].serialize(os, protocol_version);
290         }
291         writeU8(os, alpha);
292         writeU8(os, post_effect_color.getAlpha());
293         writeU8(os, post_effect_color.getRed());
294         writeU8(os, post_effect_color.getGreen());
295         writeU8(os, post_effect_color.getBlue());
296         writeU8(os, param_type);
297         writeU8(os, param_type_2);
298         writeU8(os, is_ground_content);
299         writeU8(os, light_propagates);
300         writeU8(os, sunlight_propagates);
301         writeU8(os, walkable);
302         writeU8(os, pointable);
303         writeU8(os, diggable);
304         writeU8(os, climbable);
305         writeU8(os, buildable_to);
306         os<<serializeString(""); // legacy: used to be metadata_name
307         writeU8(os, liquid_type);
308         os<<serializeString(liquid_alternative_flowing);
309         os<<serializeString(liquid_alternative_source);
310         writeU8(os, liquid_viscosity);
311         writeU8(os, liquid_renewable);
312         writeU8(os, light_source);
313         writeU32(os, damage_per_second);
314         node_box.serialize(os, protocol_version);
315         selection_box.serialize(os, protocol_version);
316         writeU8(os, legacy_facedir_simple);
317         writeU8(os, legacy_wallmounted);
318         serializeSimpleSoundSpec(sound_footstep, os);
319         serializeSimpleSoundSpec(sound_dig, os);
320         serializeSimpleSoundSpec(sound_dug, os);
321         writeU8(os, rightclickable);
322         writeU8(os, drowning);
323         writeU8(os, leveled);
324         writeU8(os, liquid_range);
325         writeU8(os, waving);
326         // Stuff below should be moved to correct place in a version that otherwise changes
327         // the protocol version
328         os<<serializeString(mesh);
329         collision_box.serialize(os, protocol_version);
330         writeU8(os, floodable);
331 }
332
333 void ContentFeatures::deSerialize(std::istream &is)
334 {
335         int version = readU8(is);
336         if (version < 7) {
337                 deSerializeOld(is, version);
338                 return;
339         } else if (version > 8) {
340                 throw SerializationError("unsupported ContentFeatures version");
341         }
342
343         name = deSerializeString(is);
344         groups.clear();
345         u32 groups_size = readU16(is);
346         for(u32 i = 0; i < groups_size; i++){
347                 std::string name = deSerializeString(is);
348                 int value = readS16(is);
349                 groups[name] = value;
350         }
351         drawtype = (enum NodeDrawType)readU8(is);
352
353         visual_scale = readF1000(is);
354         if(readU8(is) != 6)
355                 throw SerializationError("unsupported tile count");
356         for(u32 i = 0; i < 6; i++)
357                 tiledef[i].deSerialize(is, version, drawtype);
358         if(readU8(is) != CF_SPECIAL_COUNT)
359                 throw SerializationError("unsupported CF_SPECIAL_COUNT");
360         for(u32 i = 0; i < CF_SPECIAL_COUNT; i++)
361                 tiledef_special[i].deSerialize(is, version, drawtype);
362         alpha = readU8(is);
363         post_effect_color.setAlpha(readU8(is));
364         post_effect_color.setRed(readU8(is));
365         post_effect_color.setGreen(readU8(is));
366         post_effect_color.setBlue(readU8(is));
367         param_type = (enum ContentParamType)readU8(is);
368         param_type_2 = (enum ContentParamType2)readU8(is);
369         is_ground_content = readU8(is);
370         light_propagates = readU8(is);
371         sunlight_propagates = readU8(is);
372         walkable = readU8(is);
373         pointable = readU8(is);
374         diggable = readU8(is);
375         climbable = readU8(is);
376         buildable_to = readU8(is);
377         deSerializeString(is); // legacy: used to be metadata_name
378         liquid_type = (enum LiquidType)readU8(is);
379         liquid_alternative_flowing = deSerializeString(is);
380         liquid_alternative_source = deSerializeString(is);
381         liquid_viscosity = readU8(is);
382         liquid_renewable = readU8(is);
383         light_source = readU8(is);
384         damage_per_second = readU32(is);
385         node_box.deSerialize(is);
386         selection_box.deSerialize(is);
387         legacy_facedir_simple = readU8(is);
388         legacy_wallmounted = readU8(is);
389         deSerializeSimpleSoundSpec(sound_footstep, is);
390         deSerializeSimpleSoundSpec(sound_dig, is);
391         deSerializeSimpleSoundSpec(sound_dug, is);
392         rightclickable = readU8(is);
393         drowning = readU8(is);
394         leveled = readU8(is);
395         liquid_range = readU8(is);
396         waving = readU8(is);
397         // If you add anything here, insert it primarily inside the try-catch
398         // block to not need to increase the version.
399         try{
400                 // Stuff below should be moved to correct place in a version that
401                 // otherwise changes the protocol version
402         mesh = deSerializeString(is);
403         collision_box.deSerialize(is);
404         floodable = readU8(is);
405         }catch(SerializationError &e) {};
406 }
407
408 /*
409         CNodeDefManager
410 */
411
412 class CNodeDefManager: public IWritableNodeDefManager {
413 public:
414         CNodeDefManager();
415         virtual ~CNodeDefManager();
416         void clear();
417         virtual IWritableNodeDefManager *clone();
418         inline virtual const ContentFeatures& get(content_t c) const;
419         inline virtual const ContentFeatures& get(const MapNode &n) const;
420         virtual bool getId(const std::string &name, content_t &result) const;
421         virtual content_t getId(const std::string &name) const;
422         virtual void getIds(const std::string &name, std::set<content_t> &result) const;
423         virtual const ContentFeatures& get(const std::string &name) const;
424         content_t allocateId();
425         virtual content_t set(const std::string &name, const ContentFeatures &def);
426         virtual content_t allocateDummy(const std::string &name);
427         virtual void updateAliases(IItemDefManager *idef);
428         virtual void applyTextureOverrides(const std::string &override_filepath);
429         virtual void updateTextures(IGameDef *gamedef,
430                 void (*progress_cbk)(void *progress_args, u32 progress, u32 max_progress),
431                 void *progress_cbk_args);
432         void serialize(std::ostream &os, u16 protocol_version) const;
433         void deSerialize(std::istream &is);
434
435         inline virtual bool getNodeRegistrationStatus() const;
436         inline virtual void setNodeRegistrationStatus(bool completed);
437
438         virtual void pendNodeResolve(NodeResolver *nr);
439         virtual bool cancelNodeResolveCallback(NodeResolver *nr);
440         virtual void runNodeResolveCallbacks();
441         virtual void resetNodeResolveState();
442
443 private:
444         void addNameIdMapping(content_t i, std::string name);
445 #ifndef SERVER
446         void fillTileAttribs(ITextureSource *tsrc, TileSpec *tile, TileDef *tiledef,
447                 u32 shader_id, bool use_normal_texture, bool backface_culling,
448                 u8 alpha, u8 material_type);
449 #endif
450
451         // Features indexed by id
452         std::vector<ContentFeatures> m_content_features;
453
454         // A mapping for fast converting back and forth between names and ids
455         NameIdMapping m_name_id_mapping;
456
457         // Like m_name_id_mapping, but only from names to ids, and includes
458         // item aliases too. Updated by updateAliases()
459         // Note: Not serialized.
460
461         std::map<std::string, content_t> m_name_id_mapping_with_aliases;
462
463         // A mapping from groups to a list of content_ts (and their levels)
464         // that belong to it.  Necessary for a direct lookup in getIds().
465         // Note: Not serialized.
466         std::map<std::string, GroupItems> m_group_to_items;
467
468         // Next possibly free id
469         content_t m_next_id;
470
471         // NodeResolvers to callback once node registration has ended
472         std::vector<NodeResolver *> m_pending_resolve_callbacks;
473
474         // True when all nodes have been registered
475         bool m_node_registration_complete;
476 };
477
478
479 CNodeDefManager::CNodeDefManager()
480 {
481         clear();
482 }
483
484
485 CNodeDefManager::~CNodeDefManager()
486 {
487 #ifndef SERVER
488         for (u32 i = 0; i < m_content_features.size(); i++) {
489                 ContentFeatures *f = &m_content_features[i];
490                 for (u32 j = 0; j < 24; j++) {
491                         if (f->mesh_ptr[j])
492                                 f->mesh_ptr[j]->drop();
493                 }
494         }
495 #endif
496 }
497
498
499 void CNodeDefManager::clear()
500 {
501         m_content_features.clear();
502         m_name_id_mapping.clear();
503         m_name_id_mapping_with_aliases.clear();
504         m_group_to_items.clear();
505         m_next_id = 0;
506
507         resetNodeResolveState();
508
509         u32 initial_length = 0;
510         initial_length = MYMAX(initial_length, CONTENT_UNKNOWN + 1);
511         initial_length = MYMAX(initial_length, CONTENT_AIR + 1);
512         initial_length = MYMAX(initial_length, CONTENT_IGNORE + 1);
513         m_content_features.resize(initial_length);
514
515         // Set CONTENT_UNKNOWN
516         {
517                 ContentFeatures f;
518                 f.name = "unknown";
519                 // Insert directly into containers
520                 content_t c = CONTENT_UNKNOWN;
521                 m_content_features[c] = f;
522                 addNameIdMapping(c, f.name);
523         }
524
525         // Set CONTENT_AIR
526         {
527                 ContentFeatures f;
528                 f.name                = "air";
529                 f.drawtype            = NDT_AIRLIKE;
530                 f.param_type          = CPT_LIGHT;
531                 f.light_propagates    = true;
532                 f.sunlight_propagates = true;
533                 f.walkable            = false;
534                 f.pointable           = false;
535                 f.diggable            = false;
536                 f.buildable_to        = true;
537                 f.floodable           = true;
538                 f.is_ground_content   = true;
539                 // Insert directly into containers
540                 content_t c = CONTENT_AIR;
541                 m_content_features[c] = f;
542                 addNameIdMapping(c, f.name);
543         }
544
545         // Set CONTENT_IGNORE
546         {
547                 ContentFeatures f;
548                 f.name                = "ignore";
549                 f.drawtype            = NDT_AIRLIKE;
550                 f.param_type          = CPT_NONE;
551                 f.light_propagates    = false;
552                 f.sunlight_propagates = false;
553                 f.walkable            = false;
554                 f.pointable           = false;
555                 f.diggable            = false;
556                 f.buildable_to        = true; // A way to remove accidental CONTENT_IGNOREs
557                 f.is_ground_content   = true;
558                 // Insert directly into containers
559                 content_t c = CONTENT_IGNORE;
560                 m_content_features[c] = f;
561                 addNameIdMapping(c, f.name);
562         }
563 }
564
565
566 IWritableNodeDefManager *CNodeDefManager::clone()
567 {
568         CNodeDefManager *mgr = new CNodeDefManager();
569         *mgr = *this;
570         return mgr;
571 }
572
573
574 inline const ContentFeatures& CNodeDefManager::get(content_t c) const
575 {
576         return c < m_content_features.size()
577                         ? m_content_features[c] : m_content_features[CONTENT_UNKNOWN];
578 }
579
580
581 inline const ContentFeatures& CNodeDefManager::get(const MapNode &n) const
582 {
583         return get(n.getContent());
584 }
585
586
587 bool CNodeDefManager::getId(const std::string &name, content_t &result) const
588 {
589         std::map<std::string, content_t>::const_iterator
590                 i = m_name_id_mapping_with_aliases.find(name);
591         if(i == m_name_id_mapping_with_aliases.end())
592                 return false;
593         result = i->second;
594         return true;
595 }
596
597
598 content_t CNodeDefManager::getId(const std::string &name) const
599 {
600         content_t id = CONTENT_IGNORE;
601         getId(name, id);
602         return id;
603 }
604
605
606 void CNodeDefManager::getIds(const std::string &name,
607                 std::set<content_t> &result) const
608 {
609         //TimeTaker t("getIds", NULL, PRECISION_MICRO);
610         if (name.substr(0,6) != "group:") {
611                 content_t id = CONTENT_IGNORE;
612                 if(getId(name, id))
613                         result.insert(id);
614                 return;
615         }
616         std::string group = name.substr(6);
617
618         std::map<std::string, GroupItems>::const_iterator
619                 i = m_group_to_items.find(group);
620         if (i == m_group_to_items.end())
621                 return;
622
623         const GroupItems &items = i->second;
624         for (GroupItems::const_iterator j = items.begin();
625                 j != items.end(); ++j) {
626                 if ((*j).second != 0)
627                         result.insert((*j).first);
628         }
629         //printf("getIds: %dus\n", t.stop());
630 }
631
632
633 const ContentFeatures& CNodeDefManager::get(const std::string &name) const
634 {
635         content_t id = CONTENT_UNKNOWN;
636         getId(name, id);
637         return get(id);
638 }
639
640
641 // returns CONTENT_IGNORE if no free ID found
642 content_t CNodeDefManager::allocateId()
643 {
644         for (content_t id = m_next_id;
645                         id >= m_next_id; // overflow?
646                         ++id) {
647                 while (id >= m_content_features.size()) {
648                         m_content_features.push_back(ContentFeatures());
649                 }
650                 const ContentFeatures &f = m_content_features[id];
651                 if (f.name == "") {
652                         m_next_id = id + 1;
653                         return id;
654                 }
655         }
656         // If we arrive here, an overflow occurred in id.
657         // That means no ID was found
658         return CONTENT_IGNORE;
659 }
660
661
662 // IWritableNodeDefManager
663 content_t CNodeDefManager::set(const std::string &name, const ContentFeatures &def)
664 {
665         // Pre-conditions
666         assert(name != "");
667         assert(name == def.name);
668
669         // Don't allow redefining ignore (but allow air and unknown)
670         if (name == "ignore") {
671                 warningstream << "NodeDefManager: Ignoring "
672                         "CONTENT_IGNORE redefinition"<<std::endl;
673                 return CONTENT_IGNORE;
674         }
675
676         content_t id = CONTENT_IGNORE;
677         if (!m_name_id_mapping.getId(name, id)) { // ignore aliases
678                 // Get new id
679                 id = allocateId();
680                 if (id == CONTENT_IGNORE) {
681                         warningstream << "NodeDefManager: Absolute "
682                                 "limit reached" << std::endl;
683                         return CONTENT_IGNORE;
684                 }
685                 assert(id != CONTENT_IGNORE);
686                 addNameIdMapping(id, name);
687         }
688         m_content_features[id] = def;
689         verbosestream << "NodeDefManager: registering content id \"" << id
690                 << "\": name=\"" << def.name << "\""<<std::endl;
691
692         // Add this content to the list of all groups it belongs to
693         // FIXME: This should remove a node from groups it no longer
694         // belongs to when a node is re-registered
695         for (ItemGroupList::const_iterator i = def.groups.begin();
696                 i != def.groups.end(); ++i) {
697                 std::string group_name = i->first;
698
699                 std::map<std::string, GroupItems>::iterator
700                         j = m_group_to_items.find(group_name);
701                 if (j == m_group_to_items.end()) {
702                         m_group_to_items[group_name].push_back(
703                                 std::make_pair(id, i->second));
704                 } else {
705                         GroupItems &items = j->second;
706                         items.push_back(std::make_pair(id, i->second));
707                 }
708         }
709         return id;
710 }
711
712
713 content_t CNodeDefManager::allocateDummy(const std::string &name)
714 {
715         assert(name != "");     // Pre-condition
716         ContentFeatures f;
717         f.name = name;
718         return set(name, f);
719 }
720
721
722 void CNodeDefManager::updateAliases(IItemDefManager *idef)
723 {
724         std::set<std::string> all = idef->getAll();
725         m_name_id_mapping_with_aliases.clear();
726         for (std::set<std::string>::iterator
727                         i = all.begin(); i != all.end(); ++i) {
728                 std::string name = *i;
729                 std::string convert_to = idef->getAlias(name);
730                 content_t id;
731                 if (m_name_id_mapping.getId(convert_to, id)) {
732                         m_name_id_mapping_with_aliases.insert(
733                                 std::make_pair(name, id));
734                 }
735         }
736 }
737
738 void CNodeDefManager::applyTextureOverrides(const std::string &override_filepath)
739 {
740         infostream << "CNodeDefManager::applyTextureOverrides(): Applying "
741                 "overrides to textures from " << override_filepath << std::endl;
742
743         std::ifstream infile(override_filepath.c_str());
744         std::string line;
745         int line_c = 0;
746         while (std::getline(infile, line)) {
747                 line_c++;
748                 if (trim(line) == "")
749                         continue;
750                 std::vector<std::string> splitted = str_split(line, ' ');
751                 if (splitted.size() != 3) {
752                         errorstream << override_filepath
753                                 << ":" << line_c << " Could not apply texture override \""
754                                 << line << "\": Syntax error" << std::endl;
755                         continue;
756                 }
757
758                 content_t id;
759                 if (!getId(splitted[0], id)) {
760                         errorstream << override_filepath
761                                 << ":" << line_c << " Could not apply texture override \""
762                                 << line << "\": Unknown node \""
763                                 << splitted[0] << "\"" << std::endl;
764                         continue;
765                 }
766
767                 ContentFeatures &nodedef = m_content_features[id];
768
769                 if (splitted[1] == "top")
770                         nodedef.tiledef[0].name = splitted[2];
771                 else if (splitted[1] == "bottom")
772                         nodedef.tiledef[1].name = splitted[2];
773                 else if (splitted[1] == "right")
774                         nodedef.tiledef[2].name = splitted[2];
775                 else if (splitted[1] == "left")
776                         nodedef.tiledef[3].name = splitted[2];
777                 else if (splitted[1] == "back")
778                         nodedef.tiledef[4].name = splitted[2];
779                 else if (splitted[1] == "front")
780                         nodedef.tiledef[5].name = splitted[2];
781                 else if (splitted[1] == "all" || splitted[1] == "*")
782                         for (int i = 0; i < 6; i++)
783                                 nodedef.tiledef[i].name = splitted[2];
784                 else if (splitted[1] == "sides")
785                         for (int i = 2; i < 6; i++)
786                                 nodedef.tiledef[i].name = splitted[2];
787                 else {
788                         errorstream << override_filepath
789                                 << ":" << line_c << " Could not apply texture override \""
790                                 << line << "\": Unknown node side \""
791                                 << splitted[1] << "\"" << std::endl;
792                         continue;
793                 }
794         }
795 }
796
797 void CNodeDefManager::updateTextures(IGameDef *gamedef,
798         void (*progress_callback)(void *progress_args, u32 progress, u32 max_progress),
799         void *progress_callback_args)
800 {
801 #ifndef SERVER
802         infostream << "CNodeDefManager::updateTextures(): Updating "
803                 "textures in node definitions" << std::endl;
804         ITextureSource *tsrc = gamedef->tsrc();
805         IShaderSource *shdsrc = gamedef->getShaderSource();
806         scene::ISceneManager* smgr = gamedef->getSceneManager();
807         scene::IMeshManipulator* meshmanip = smgr->getMeshManipulator();
808
809         bool new_style_water           = g_settings->getBool("new_style_water");
810         bool connected_glass           = g_settings->getBool("connected_glass");
811         bool opaque_water              = g_settings->getBool("opaque_water");
812         bool enable_shaders            = g_settings->getBool("enable_shaders");
813         bool enable_bumpmapping        = g_settings->getBool("enable_bumpmapping");
814         bool enable_parallax_occlusion = g_settings->getBool("enable_parallax_occlusion");
815         bool enable_mesh_cache         = g_settings->getBool("enable_mesh_cache");
816         bool enable_minimap            = g_settings->getBool("enable_minimap");
817         std::string leaves_style       = g_settings->get("leaves_style");
818
819         bool use_normal_texture = enable_shaders &&
820                 (enable_bumpmapping || enable_parallax_occlusion);
821
822         u32 size = m_content_features.size();
823
824         for (u32 i = 0; i < size; i++) {
825                 ContentFeatures *f = &m_content_features[i];
826
827                 // minimap pixel color - the average color of a texture
828                 if (enable_minimap && f->tiledef[0].name != "")
829                         f->minimap_color = tsrc->getTextureAverageColor(f->tiledef[0].name);
830
831                 // Figure out the actual tiles to use
832                 TileDef tiledef[6];
833                 for (u32 j = 0; j < 6; j++) {
834                         tiledef[j] = f->tiledef[j];
835                         if (tiledef[j].name == "")
836                                 tiledef[j].name = "unknown_node.png";
837                 }
838
839                 bool is_liquid = false;
840                 bool is_water_surface = false;
841
842                 u8 material_type = (f->alpha == 255) ?
843                         TILE_MATERIAL_BASIC : TILE_MATERIAL_ALPHA;
844
845                 switch (f->drawtype) {
846                 default:
847                 case NDT_NORMAL:
848                         f->solidness = 2;
849                         break;
850                 case NDT_AIRLIKE:
851                         f->solidness = 0;
852                         break;
853                 case NDT_LIQUID:
854                         assert(f->liquid_type == LIQUID_SOURCE);
855                         if (opaque_water)
856                                 f->alpha = 255;
857                         f->solidness = new_style_water ? 0 : 1;
858                         is_liquid = true;
859                         break;
860                 case NDT_FLOWINGLIQUID:
861                         assert(f->liquid_type == LIQUID_FLOWING);
862                         f->solidness = 0;
863                         if (opaque_water)
864                                 f->alpha = 255;
865                         is_liquid = true;
866                         break;
867                 case NDT_GLASSLIKE:
868                         f->solidness = 0;
869                         f->visual_solidness = 1;
870                         break;
871                 case NDT_GLASSLIKE_FRAMED:
872                         f->solidness = 0;
873                         f->visual_solidness = 1;
874                         break;
875                 case NDT_GLASSLIKE_FRAMED_OPTIONAL:
876                         f->solidness = 0;
877                         f->visual_solidness = 1;
878                         f->drawtype = connected_glass ? NDT_GLASSLIKE_FRAMED : NDT_GLASSLIKE;
879                         break;
880                 case NDT_ALLFACES:
881                         f->solidness = 0;
882                         f->visual_solidness = 1;
883                         break;
884                 case NDT_ALLFACES_OPTIONAL:
885                         if (leaves_style == "fancy") {
886                                 f->drawtype = NDT_ALLFACES;
887                                 f->solidness = 0;
888                                 f->visual_solidness = 1;
889                         } else if (leaves_style == "simple") {
890                                 for (u32 j = 0; j < 6; j++) {
891                                         if (f->tiledef_special[j].name != "")
892                                                 tiledef[j].name = f->tiledef_special[j].name;
893                                 }
894                                 f->drawtype = NDT_GLASSLIKE;
895                                 f->solidness = 0;
896                                 f->visual_solidness = 1;
897                         } else {
898                                 f->drawtype = NDT_NORMAL;
899                                 f->solidness = 2;
900                                 for (u32 i = 0; i < 6; i++)
901                                         tiledef[i].name += std::string("^[noalpha");
902                         }
903                         if (f->waving == 1)
904                                 material_type = TILE_MATERIAL_WAVING_LEAVES;
905                         break;
906                 case NDT_PLANTLIKE:
907                         f->solidness = 0;
908                         if (f->waving == 1)
909                                 material_type = TILE_MATERIAL_WAVING_PLANTS;
910                         break;
911                 case NDT_FIRELIKE:
912                         f->solidness = 0;
913                         break;
914                 case NDT_MESH:
915                         f->solidness = 0;
916                         break;
917                 case NDT_TORCHLIKE:
918                 case NDT_SIGNLIKE:
919                 case NDT_FENCELIKE:
920                 case NDT_RAILLIKE:
921                 case NDT_NODEBOX:
922                         f->solidness = 0;
923                         break;
924                 }
925
926                 if (is_liquid) {
927                         material_type = (f->alpha == 255) ?
928                                 TILE_MATERIAL_LIQUID_OPAQUE : TILE_MATERIAL_LIQUID_TRANSPARENT;
929                         if (f->name == "default:water_source")
930                                 is_water_surface = true;
931                 }
932
933                 u32 tile_shader[6];
934                 for (u16 j = 0; j < 6; j++) {
935                         tile_shader[j] = shdsrc->getShader("nodes_shader",
936                                 material_type, f->drawtype);
937                 }
938
939                 if (is_water_surface) {
940                         tile_shader[0] = shdsrc->getShader("water_surface_shader",
941                                 material_type, f->drawtype);
942                 }
943
944                 // Tiles (fill in f->tiles[])
945                 for (u16 j = 0; j < 6; j++) {
946                         fillTileAttribs(tsrc, &f->tiles[j], &tiledef[j], tile_shader[j],
947                                 use_normal_texture, f->tiledef[j].backface_culling, f->alpha, material_type);
948                 }
949
950                 // Special tiles (fill in f->special_tiles[])
951                 for (u16 j = 0; j < CF_SPECIAL_COUNT; j++) {
952                         fillTileAttribs(tsrc, &f->special_tiles[j], &f->tiledef_special[j],
953                                 tile_shader[j], use_normal_texture,
954                                 f->tiledef_special[j].backface_culling, f->alpha, material_type);
955                 }
956
957                 if ((f->drawtype == NDT_MESH) && (f->mesh != "")) {
958                         // Meshnode drawtype
959                         // Read the mesh and apply scale
960                         f->mesh_ptr[0] = gamedef->getMesh(f->mesh);
961                         if (f->mesh_ptr[0]){
962                                 v3f scale = v3f(1.0, 1.0, 1.0) * BS * f->visual_scale;
963                                 scaleMesh(f->mesh_ptr[0], scale);
964                                 recalculateBoundingBox(f->mesh_ptr[0]);
965                                 meshmanip->recalculateNormals(f->mesh_ptr[0], true, false);
966                         }
967                 } else if ((f->drawtype == NDT_NODEBOX) &&
968                                 ((f->node_box.type == NODEBOX_REGULAR) ||
969                                 (f->node_box.type == NODEBOX_FIXED)) &&
970                                 (!f->node_box.fixed.empty())) {
971                         //Convert regular nodebox nodes to meshnodes
972                         //Change the drawtype and apply scale
973                         f->drawtype = NDT_MESH;
974                         f->mesh_ptr[0] = convertNodeboxesToMesh(f->node_box.fixed);
975                         v3f scale = v3f(1.0, 1.0, 1.0) * f->visual_scale;
976                         scaleMesh(f->mesh_ptr[0], scale);
977                         recalculateBoundingBox(f->mesh_ptr[0]);
978                         meshmanip->recalculateNormals(f->mesh_ptr[0], true, false);
979                 }
980
981                 //Cache 6dfacedir and wallmounted rotated clones of meshes
982                 if (enable_mesh_cache && f->mesh_ptr[0] && (f->param_type_2 == CPT2_FACEDIR)) {
983                         for (u16 j = 1; j < 24; j++) {
984                                 f->mesh_ptr[j] = cloneMesh(f->mesh_ptr[0]);
985                                 rotateMeshBy6dFacedir(f->mesh_ptr[j], j);
986                                 recalculateBoundingBox(f->mesh_ptr[j]);
987                                 meshmanip->recalculateNormals(f->mesh_ptr[j], true, false);
988                         }
989                 } else if (enable_mesh_cache && f->mesh_ptr[0] && (f->param_type_2 == CPT2_WALLMOUNTED)) {
990                         static const u8 wm_to_6d[6] = {20, 0, 16+1, 12+3, 8, 4+2};
991                         for (u16 j = 1; j < 6; j++) {
992                                 f->mesh_ptr[j] = cloneMesh(f->mesh_ptr[0]);
993                                 rotateMeshBy6dFacedir(f->mesh_ptr[j], wm_to_6d[j]);
994                                 recalculateBoundingBox(f->mesh_ptr[j]);
995                                 meshmanip->recalculateNormals(f->mesh_ptr[j], true, false);
996                         }
997                         rotateMeshBy6dFacedir(f->mesh_ptr[0], wm_to_6d[0]);
998                         recalculateBoundingBox(f->mesh_ptr[0]);
999                         meshmanip->recalculateNormals(f->mesh_ptr[0], true, false);
1000                 }
1001
1002                 progress_callback(progress_callback_args, i, size);
1003         }
1004 #endif
1005 }
1006
1007
1008 #ifndef SERVER
1009 void CNodeDefManager::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile,
1010                 TileDef *tiledef, u32 shader_id, bool use_normal_texture,
1011                 bool backface_culling, u8 alpha, u8 material_type)
1012 {
1013         tile->shader_id     = shader_id;
1014         tile->texture       = tsrc->getTextureForMesh(tiledef->name, &tile->texture_id);
1015         tile->alpha         = alpha;
1016         tile->material_type = material_type;
1017
1018         // Normal texture and shader flags texture
1019         if (use_normal_texture) {
1020                 tile->normal_texture = tsrc->getNormalTexture(tiledef->name);
1021         }
1022         tile->flags_texture = tsrc->getShaderFlagsTexture(tile->normal_texture ? true : false);
1023
1024         // Material flags
1025         tile->material_flags = 0;
1026         if (backface_culling)
1027                 tile->material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
1028         if (tiledef->animation.type == TAT_VERTICAL_FRAMES)
1029                 tile->material_flags |= MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
1030         if (tiledef->tileable_horizontal)
1031                 tile->material_flags |= MATERIAL_FLAG_TILEABLE_HORIZONTAL;
1032         if (tiledef->tileable_vertical)
1033                 tile->material_flags |= MATERIAL_FLAG_TILEABLE_VERTICAL;
1034
1035         // Animation parameters
1036         int frame_count = 1;
1037         if (tile->material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES) {
1038                 // Get texture size to determine frame count by aspect ratio
1039                 v2u32 size = tile->texture->getOriginalSize();
1040                 int frame_height = (float)size.X /
1041                                 (float)tiledef->animation.aspect_w *
1042                                 (float)tiledef->animation.aspect_h;
1043                 frame_count = size.Y / frame_height;
1044                 int frame_length_ms = 1000.0 * tiledef->animation.length / frame_count;
1045                 tile->animation_frame_count = frame_count;
1046                 tile->animation_frame_length_ms = frame_length_ms;
1047         }
1048
1049         if (frame_count == 1) {
1050                 tile->material_flags &= ~MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
1051         } else {
1052                 std::ostringstream os(std::ios::binary);
1053                 tile->frames.resize(frame_count);
1054
1055                 for (int i = 0; i < frame_count; i++) {
1056
1057                         FrameSpec frame;
1058
1059                         os.str("");
1060                         os << tiledef->name << "^[verticalframe:"
1061                                 << frame_count << ":" << i;
1062
1063                         frame.texture = tsrc->getTextureForMesh(os.str(), &frame.texture_id);
1064                         if (tile->normal_texture)
1065                                 frame.normal_texture = tsrc->getNormalTexture(os.str());
1066                         frame.flags_texture = tile->flags_texture;
1067                         tile->frames[i] = frame;
1068                 }
1069         }
1070 }
1071 #endif
1072
1073
1074 void CNodeDefManager::serialize(std::ostream &os, u16 protocol_version) const
1075 {
1076         writeU8(os, 1); // version
1077         u16 count = 0;
1078         std::ostringstream os2(std::ios::binary);
1079         for (u32 i = 0; i < m_content_features.size(); i++) {
1080                 if (i == CONTENT_IGNORE || i == CONTENT_AIR
1081                                 || i == CONTENT_UNKNOWN)
1082                         continue;
1083                 const ContentFeatures *f = &m_content_features[i];
1084                 if (f->name == "")
1085                         continue;
1086                 writeU16(os2, i);
1087                 // Wrap it in a string to allow different lengths without
1088                 // strict version incompatibilities
1089                 std::ostringstream wrapper_os(std::ios::binary);
1090                 f->serialize(wrapper_os, protocol_version);
1091                 os2<<serializeString(wrapper_os.str());
1092
1093                 // must not overflow
1094                 u16 next = count + 1;
1095                 FATAL_ERROR_IF(next < count, "Overflow");
1096                 count++;
1097         }
1098         writeU16(os, count);
1099         os << serializeLongString(os2.str());
1100 }
1101
1102
1103 void CNodeDefManager::deSerialize(std::istream &is)
1104 {
1105         clear();
1106         int version = readU8(is);
1107         if (version != 1)
1108                 throw SerializationError("unsupported NodeDefinitionManager version");
1109         u16 count = readU16(is);
1110         std::istringstream is2(deSerializeLongString(is), std::ios::binary);
1111         ContentFeatures f;
1112         for (u16 n = 0; n < count; n++) {
1113                 u16 i = readU16(is2);
1114
1115                 // Read it from the string wrapper
1116                 std::string wrapper = deSerializeString(is2);
1117                 std::istringstream wrapper_is(wrapper, std::ios::binary);
1118                 f.deSerialize(wrapper_is);
1119
1120                 // Check error conditions
1121                 if (i == CONTENT_IGNORE || i == CONTENT_AIR || i == CONTENT_UNKNOWN) {
1122                         warningstream << "NodeDefManager::deSerialize(): "
1123                                 "not changing builtin node " << i << std::endl;
1124                         continue;
1125                 }
1126                 if (f.name == "") {
1127                         warningstream << "NodeDefManager::deSerialize(): "
1128                                 "received empty name" << std::endl;
1129                         continue;
1130                 }
1131
1132                 // Ignore aliases
1133                 u16 existing_id;
1134                 if (m_name_id_mapping.getId(f.name, existing_id) && i != existing_id) {
1135                         warningstream << "NodeDefManager::deSerialize(): "
1136                                 "already defined with different ID: " << f.name << std::endl;
1137                         continue;
1138                 }
1139
1140                 // All is ok, add node definition with the requested ID
1141                 if (i >= m_content_features.size())
1142                         m_content_features.resize((u32)(i) + 1);
1143                 m_content_features[i] = f;
1144                 addNameIdMapping(i, f.name);
1145                 verbosestream << "deserialized " << f.name << std::endl;
1146         }
1147 }
1148
1149
1150 void CNodeDefManager::addNameIdMapping(content_t i, std::string name)
1151 {
1152         m_name_id_mapping.set(i, name);
1153         m_name_id_mapping_with_aliases.insert(std::make_pair(name, i));
1154 }
1155
1156
1157 IWritableNodeDefManager *createNodeDefManager()
1158 {
1159         return new CNodeDefManager();
1160 }
1161
1162
1163 //// Serialization of old ContentFeatures formats
1164 void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const
1165 {
1166         if (protocol_version == 13)
1167         {
1168                 writeU8(os, 5); // version
1169                 os<<serializeString(name);
1170                 writeU16(os, groups.size());
1171                 for (ItemGroupList::const_iterator
1172                                 i = groups.begin(); i != groups.end(); ++i) {
1173                         os<<serializeString(i->first);
1174                         writeS16(os, i->second);
1175                 }
1176                 writeU8(os, drawtype);
1177                 writeF1000(os, visual_scale);
1178                 writeU8(os, 6);
1179                 for (u32 i = 0; i < 6; i++)
1180                         tiledef[i].serialize(os, protocol_version);
1181                 //CF_SPECIAL_COUNT = 2 before cf ver. 7 and protocol ver. 24
1182                 writeU8(os, 2);
1183                 for (u32 i = 0; i < 2; i++)
1184                         tiledef_special[i].serialize(os, protocol_version);
1185                 writeU8(os, alpha);
1186                 writeU8(os, post_effect_color.getAlpha());
1187                 writeU8(os, post_effect_color.getRed());
1188                 writeU8(os, post_effect_color.getGreen());
1189                 writeU8(os, post_effect_color.getBlue());
1190                 writeU8(os, param_type);
1191                 writeU8(os, param_type_2);
1192                 writeU8(os, is_ground_content);
1193                 writeU8(os, light_propagates);
1194                 writeU8(os, sunlight_propagates);
1195                 writeU8(os, walkable);
1196                 writeU8(os, pointable);
1197                 writeU8(os, diggable);
1198                 writeU8(os, climbable);
1199                 writeU8(os, buildable_to);
1200                 os<<serializeString(""); // legacy: used to be metadata_name
1201                 writeU8(os, liquid_type);
1202                 os<<serializeString(liquid_alternative_flowing);
1203                 os<<serializeString(liquid_alternative_source);
1204                 writeU8(os, liquid_viscosity);
1205                 writeU8(os, light_source);
1206                 writeU32(os, damage_per_second);
1207                 node_box.serialize(os, protocol_version);
1208                 selection_box.serialize(os, protocol_version);
1209                 writeU8(os, legacy_facedir_simple);
1210                 writeU8(os, legacy_wallmounted);
1211                 serializeSimpleSoundSpec(sound_footstep, os);
1212                 serializeSimpleSoundSpec(sound_dig, os);
1213                 serializeSimpleSoundSpec(sound_dug, os);
1214         }
1215         else if (protocol_version > 13 && protocol_version < 24) {
1216                 writeU8(os, 6); // version
1217                 os<<serializeString(name);
1218                 writeU16(os, groups.size());
1219                 for (ItemGroupList::const_iterator
1220                         i = groups.begin(); i != groups.end(); ++i) {
1221                                 os<<serializeString(i->first);
1222                                 writeS16(os, i->second);
1223                 }
1224                 writeU8(os, drawtype);
1225                 writeF1000(os, visual_scale);
1226                 writeU8(os, 6);
1227                 for (u32 i = 0; i < 6; i++)
1228                         tiledef[i].serialize(os, protocol_version);
1229                 //CF_SPECIAL_COUNT = 2 before cf ver. 7 and protocol ver. 24
1230                 writeU8(os, 2);
1231                 for (u32 i = 0; i < 2; i++)
1232                         tiledef_special[i].serialize(os, protocol_version);
1233                 writeU8(os, alpha);
1234                 writeU8(os, post_effect_color.getAlpha());
1235                 writeU8(os, post_effect_color.getRed());
1236                 writeU8(os, post_effect_color.getGreen());
1237                 writeU8(os, post_effect_color.getBlue());
1238                 writeU8(os, param_type);
1239                 writeU8(os, param_type_2);
1240                 writeU8(os, is_ground_content);
1241                 writeU8(os, light_propagates);
1242                 writeU8(os, sunlight_propagates);
1243                 writeU8(os, walkable);
1244                 writeU8(os, pointable);
1245                 writeU8(os, diggable);
1246                 writeU8(os, climbable);
1247                 writeU8(os, buildable_to);
1248                 os<<serializeString(""); // legacy: used to be metadata_name
1249                 writeU8(os, liquid_type);
1250                 os<<serializeString(liquid_alternative_flowing);
1251                 os<<serializeString(liquid_alternative_source);
1252                 writeU8(os, liquid_viscosity);
1253                 writeU8(os, liquid_renewable);
1254                 writeU8(os, light_source);
1255                 writeU32(os, damage_per_second);
1256                 node_box.serialize(os, protocol_version);
1257                 selection_box.serialize(os, protocol_version);
1258                 writeU8(os, legacy_facedir_simple);
1259                 writeU8(os, legacy_wallmounted);
1260                 serializeSimpleSoundSpec(sound_footstep, os);
1261                 serializeSimpleSoundSpec(sound_dig, os);
1262                 serializeSimpleSoundSpec(sound_dug, os);
1263                 writeU8(os, rightclickable);
1264                 writeU8(os, drowning);
1265                 writeU8(os, leveled);
1266                 writeU8(os, liquid_range);
1267         } else
1268                 throw SerializationError("ContentFeatures::serialize(): "
1269                         "Unsupported version requested");
1270 }
1271
1272 void ContentFeatures::deSerializeOld(std::istream &is, int version)
1273 {
1274         if (version == 5) // In PROTOCOL_VERSION 13
1275         {
1276                 name = deSerializeString(is);
1277                 groups.clear();
1278                 u32 groups_size = readU16(is);
1279                 for(u32 i=0; i<groups_size; i++){
1280                         std::string name = deSerializeString(is);
1281                         int value = readS16(is);
1282                         groups[name] = value;
1283                 }
1284                 drawtype = (enum NodeDrawType)readU8(is);
1285
1286                 visual_scale = readF1000(is);
1287                 if (readU8(is) != 6)
1288                         throw SerializationError("unsupported tile count");
1289                 for (u32 i = 0; i < 6; i++)
1290                         tiledef[i].deSerialize(is, version, drawtype);
1291                 if (readU8(is) != CF_SPECIAL_COUNT)
1292                         throw SerializationError("unsupported CF_SPECIAL_COUNT");
1293                 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
1294                         tiledef_special[i].deSerialize(is, version, drawtype);
1295                 alpha = readU8(is);
1296                 post_effect_color.setAlpha(readU8(is));
1297                 post_effect_color.setRed(readU8(is));
1298                 post_effect_color.setGreen(readU8(is));
1299                 post_effect_color.setBlue(readU8(is));
1300                 param_type = (enum ContentParamType)readU8(is);
1301                 param_type_2 = (enum ContentParamType2)readU8(is);
1302                 is_ground_content = readU8(is);
1303                 light_propagates = readU8(is);
1304                 sunlight_propagates = readU8(is);
1305                 walkable = readU8(is);
1306                 pointable = readU8(is);
1307                 diggable = readU8(is);
1308                 climbable = readU8(is);
1309                 buildable_to = readU8(is);
1310                 deSerializeString(is); // legacy: used to be metadata_name
1311                 liquid_type = (enum LiquidType)readU8(is);
1312                 liquid_alternative_flowing = deSerializeString(is);
1313                 liquid_alternative_source = deSerializeString(is);
1314                 liquid_viscosity = readU8(is);
1315                 light_source = readU8(is);
1316                 damage_per_second = readU32(is);
1317                 node_box.deSerialize(is);
1318                 selection_box.deSerialize(is);
1319                 legacy_facedir_simple = readU8(is);
1320                 legacy_wallmounted = readU8(is);
1321                 deSerializeSimpleSoundSpec(sound_footstep, is);
1322                 deSerializeSimpleSoundSpec(sound_dig, is);
1323                 deSerializeSimpleSoundSpec(sound_dug, is);
1324         } else if (version == 6) {
1325                 name = deSerializeString(is);
1326                 groups.clear();
1327                 u32 groups_size = readU16(is);
1328                 for (u32 i = 0; i < groups_size; i++) {
1329                         std::string name = deSerializeString(is);
1330                         int     value = readS16(is);
1331                         groups[name] = value;
1332                 }
1333                 drawtype = (enum NodeDrawType)readU8(is);
1334                 visual_scale = readF1000(is);
1335                 if (readU8(is) != 6)
1336                         throw SerializationError("unsupported tile count");
1337                 for (u32 i = 0; i < 6; i++)
1338                         tiledef[i].deSerialize(is, version, drawtype);
1339                 // CF_SPECIAL_COUNT in version 6 = 2
1340                 if (readU8(is) != 2)
1341                         throw SerializationError("unsupported CF_SPECIAL_COUNT");
1342                 for (u32 i = 0; i < 2; i++)
1343                         tiledef_special[i].deSerialize(is, version, drawtype);
1344                 alpha = readU8(is);
1345                 post_effect_color.setAlpha(readU8(is));
1346                 post_effect_color.setRed(readU8(is));
1347                 post_effect_color.setGreen(readU8(is));
1348                 post_effect_color.setBlue(readU8(is));
1349                 param_type = (enum ContentParamType)readU8(is);
1350                 param_type_2 = (enum ContentParamType2)readU8(is);
1351                 is_ground_content = readU8(is);
1352                 light_propagates = readU8(is);
1353                 sunlight_propagates = readU8(is);
1354                 walkable = readU8(is);
1355                 pointable = readU8(is);
1356                 diggable = readU8(is);
1357                 climbable = readU8(is);
1358                 buildable_to = readU8(is);
1359                 deSerializeString(is); // legacy: used to be metadata_name
1360                 liquid_type = (enum LiquidType)readU8(is);
1361                 liquid_alternative_flowing = deSerializeString(is);
1362                 liquid_alternative_source = deSerializeString(is);
1363                 liquid_viscosity = readU8(is);
1364                 liquid_renewable = readU8(is);
1365                 light_source = readU8(is);
1366                 damage_per_second = readU32(is);
1367                 node_box.deSerialize(is);
1368                 selection_box.deSerialize(is);
1369                 legacy_facedir_simple = readU8(is);
1370                 legacy_wallmounted = readU8(is);
1371                 deSerializeSimpleSoundSpec(sound_footstep, is);
1372                 deSerializeSimpleSoundSpec(sound_dig, is);
1373                 deSerializeSimpleSoundSpec(sound_dug, is);
1374                 rightclickable = readU8(is);
1375                 drowning = readU8(is);
1376                 leveled = readU8(is);
1377                 liquid_range = readU8(is);
1378         } else {
1379                 throw SerializationError("unsupported ContentFeatures version");
1380         }
1381 }
1382
1383
1384 inline bool CNodeDefManager::getNodeRegistrationStatus() const
1385 {
1386         return m_node_registration_complete;
1387 }
1388
1389
1390 inline void CNodeDefManager::setNodeRegistrationStatus(bool completed)
1391 {
1392         m_node_registration_complete = completed;
1393 }
1394
1395
1396 void CNodeDefManager::pendNodeResolve(NodeResolver *nr)
1397 {
1398         nr->m_ndef = this;
1399         if (m_node_registration_complete)
1400                 nr->nodeResolveInternal();
1401         else
1402                 m_pending_resolve_callbacks.push_back(nr);
1403 }
1404
1405
1406 bool CNodeDefManager::cancelNodeResolveCallback(NodeResolver *nr)
1407 {
1408         size_t len = m_pending_resolve_callbacks.size();
1409         for (size_t i = 0; i != len; i++) {
1410                 if (nr != m_pending_resolve_callbacks[i])
1411                         continue;
1412
1413                 len--;
1414                 m_pending_resolve_callbacks[i] = m_pending_resolve_callbacks[len];
1415                 m_pending_resolve_callbacks.resize(len);
1416                 return true;
1417         }
1418
1419         return false;
1420 }
1421
1422
1423 void CNodeDefManager::runNodeResolveCallbacks()
1424 {
1425         for (size_t i = 0; i != m_pending_resolve_callbacks.size(); i++) {
1426                 NodeResolver *nr = m_pending_resolve_callbacks[i];
1427                 nr->nodeResolveInternal();
1428         }
1429
1430         m_pending_resolve_callbacks.clear();
1431 }
1432
1433
1434 void CNodeDefManager::resetNodeResolveState()
1435 {
1436         m_node_registration_complete = false;
1437         m_pending_resolve_callbacks.clear();
1438 }
1439
1440
1441 ////
1442 //// NodeResolver
1443 ////
1444
1445 NodeResolver::NodeResolver()
1446 {
1447         m_ndef            = NULL;
1448         m_nodenames_idx   = 0;
1449         m_nnlistsizes_idx = 0;
1450         m_resolve_done    = false;
1451
1452         m_nodenames.reserve(16);
1453         m_nnlistsizes.reserve(4);
1454 }
1455
1456
1457 NodeResolver::~NodeResolver()
1458 {
1459         if (!m_resolve_done && m_ndef)
1460                 m_ndef->cancelNodeResolveCallback(this);
1461 }
1462
1463
1464 void NodeResolver::nodeResolveInternal()
1465 {
1466         m_nodenames_idx   = 0;
1467         m_nnlistsizes_idx = 0;
1468
1469         resolveNodeNames();
1470         m_resolve_done = true;
1471
1472         m_nodenames.clear();
1473         m_nnlistsizes.clear();
1474 }
1475
1476
1477 bool NodeResolver::getIdFromNrBacklog(content_t *result_out,
1478         const std::string &node_alt, content_t c_fallback)
1479 {
1480         if (m_nodenames_idx == m_nodenames.size()) {
1481                 *result_out = c_fallback;
1482                 errorstream << "NodeResolver: no more nodes in list" << std::endl;
1483                 return false;
1484         }
1485
1486         content_t c;
1487         std::string name = m_nodenames[m_nodenames_idx++];
1488
1489         bool success = m_ndef->getId(name, c);
1490         if (!success && node_alt != "") {
1491                 name = node_alt;
1492                 success = m_ndef->getId(name, c);
1493         }
1494
1495         if (!success) {
1496                 errorstream << "NodeResolver: failed to resolve node name '" << name
1497                         << "'." << std::endl;
1498                 c = c_fallback;
1499         }
1500
1501         *result_out = c;
1502         return success;
1503 }
1504
1505
1506 bool NodeResolver::getIdsFromNrBacklog(std::vector<content_t> *result_out,
1507         bool all_required, content_t c_fallback)
1508 {
1509         bool success = true;
1510
1511         if (m_nnlistsizes_idx == m_nnlistsizes.size()) {
1512                 errorstream << "NodeResolver: no more node lists" << std::endl;
1513                 return false;
1514         }
1515
1516         size_t length = m_nnlistsizes[m_nnlistsizes_idx++];
1517
1518         while (length--) {
1519                 if (m_nodenames_idx == m_nodenames.size()) {
1520                         errorstream << "NodeResolver: no more nodes in list" << std::endl;
1521                         return false;
1522                 }
1523
1524                 content_t c;
1525                 std::string &name = m_nodenames[m_nodenames_idx++];
1526
1527                 if (name.substr(0,6) != "group:") {
1528                         if (m_ndef->getId(name, c)) {
1529                                 result_out->push_back(c);
1530                         } else if (all_required) {
1531                                 errorstream << "NodeResolver: failed to resolve node name '"
1532                                         << name << "'." << std::endl;
1533                                 result_out->push_back(c_fallback);
1534                                 success = false;
1535                         }
1536                 } else {
1537                         std::set<content_t> cids;
1538                         std::set<content_t>::iterator it;
1539                         m_ndef->getIds(name, cids);
1540                         for (it = cids.begin(); it != cids.end(); ++it)
1541                                 result_out->push_back(*it);
1542                 }
1543         }
1544
1545         return success;
1546 }