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