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