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