3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
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.
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.
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.
22 #include "main.h" // For g_settings
29 #include "nameidmapping.h"
35 void NodeBox::serialize(std::ostream &os) const
37 writeU8(os, 0); // version
39 writeV3F1000(os, fixed.MinEdge);
40 writeV3F1000(os, fixed.MaxEdge);
41 writeV3F1000(os, wall_top.MinEdge);
42 writeV3F1000(os, wall_top.MaxEdge);
43 writeV3F1000(os, wall_bottom.MinEdge);
44 writeV3F1000(os, wall_bottom.MaxEdge);
45 writeV3F1000(os, wall_side.MinEdge);
46 writeV3F1000(os, wall_side.MaxEdge);
49 void NodeBox::deSerialize(std::istream &is)
51 int version = readU8(is);
53 throw SerializationError("unsupported NodeBox version");
54 type = (enum NodeBoxType)readU8(is);
55 fixed.MinEdge = readV3F1000(is);
56 fixed.MaxEdge = readV3F1000(is);
57 wall_top.MinEdge = readV3F1000(is);
58 wall_top.MaxEdge = readV3F1000(is);
59 wall_bottom.MinEdge = readV3F1000(is);
60 wall_bottom.MaxEdge = readV3F1000(is);
61 wall_side.MinEdge = readV3F1000(is);
62 wall_side.MaxEdge = readV3F1000(is);
69 void TileDef::serialize(std::ostream &os) const
71 writeU8(os, 0); // version
72 os<<serializeString(name);
73 writeU8(os, animation.type);
74 writeU16(os, animation.aspect_w);
75 writeU16(os, animation.aspect_h);
76 writeF1000(os, animation.length);
79 void TileDef::deSerialize(std::istream &is)
81 int version = readU8(is);
83 throw SerializationError("unsupported TileDef version");
84 name = deSerializeString(is);
85 animation.type = (TileAnimationType)readU8(is);
86 animation.aspect_w = readU16(is);
87 animation.aspect_h = readU16(is);
88 animation.length = readF1000(is);
92 SimpleSoundSpec serialization
95 static void serializeSimpleSoundSpec(const SimpleSoundSpec &ss,
98 os<<serializeString(ss.name);
99 writeF1000(os, ss.gain);
101 static void deSerializeSimpleSoundSpec(SimpleSoundSpec &ss, std::istream &is)
103 ss.name = deSerializeString(is);
104 ss.gain = readF1000(is);
111 ContentFeatures::ContentFeatures()
116 ContentFeatures::~ContentFeatures()
120 void ContentFeatures::reset()
127 visual_solidness = 0;
128 backface_culling = true;
130 has_on_construct = false;
131 has_on_destruct = false;
132 has_after_destruct = false;
136 NOTE: Most of this is always overridden by the default values given
141 // Unknown nodes can be dug
142 groups["dig_immediate"] = 2;
143 drawtype = NDT_NORMAL;
145 for(u32 i=0; i<6; i++)
146 tiledef[i] = TileDef();
147 for(u16 j=0; j<CF_SPECIAL_COUNT; j++)
148 tiledef_special[j] = TileDef();
150 post_effect_color = video::SColor(0, 0, 0, 0);
151 param_type = CPT_NONE;
152 param_type_2 = CPT2_NONE;
153 is_ground_content = false;
154 light_propagates = false;
155 sunlight_propagates = false;
160 buildable_to = false;
161 liquid_type = LIQUID_NONE;
162 liquid_alternative_flowing = "";
163 liquid_alternative_source = "";
164 liquid_viscosity = 0;
166 damage_per_second = 0;
167 selection_box = NodeBox();
168 legacy_facedir_simple = false;
169 legacy_wallmounted = false;
170 sound_footstep = SimpleSoundSpec();
171 sound_dig = SimpleSoundSpec("__group");
172 sound_dug = SimpleSoundSpec();
175 void ContentFeatures::serialize(std::ostream &os)
177 writeU8(os, 4); // version
178 os<<serializeString(name);
179 writeU16(os, groups.size());
180 for(ItemGroupList::const_iterator
181 i = groups.begin(); i != groups.end(); i++){
182 os<<serializeString(i->first);
183 writeS16(os, i->second);
185 writeU8(os, drawtype);
186 writeF1000(os, visual_scale);
188 for(u32 i=0; i<6; i++)
189 tiledef[i].serialize(os);
190 writeU8(os, CF_SPECIAL_COUNT);
191 for(u32 i=0; i<CF_SPECIAL_COUNT; i++){
192 tiledef_special[i].serialize(os);
195 writeU8(os, post_effect_color.getAlpha());
196 writeU8(os, post_effect_color.getRed());
197 writeU8(os, post_effect_color.getGreen());
198 writeU8(os, post_effect_color.getBlue());
199 writeU8(os, param_type);
200 writeU8(os, param_type_2);
201 writeU8(os, is_ground_content);
202 writeU8(os, light_propagates);
203 writeU8(os, sunlight_propagates);
204 writeU8(os, walkable);
205 writeU8(os, pointable);
206 writeU8(os, diggable);
207 writeU8(os, climbable);
208 writeU8(os, buildable_to);
209 os<<serializeString(""); // legacy: used to be metadata_name
210 writeU8(os, liquid_type);
211 os<<serializeString(liquid_alternative_flowing);
212 os<<serializeString(liquid_alternative_source);
213 writeU8(os, liquid_viscosity);
214 writeU8(os, light_source);
215 writeU32(os, damage_per_second);
216 selection_box.serialize(os);
217 writeU8(os, legacy_facedir_simple);
218 writeU8(os, legacy_wallmounted);
219 serializeSimpleSoundSpec(sound_footstep, os);
220 serializeSimpleSoundSpec(sound_dig, os);
221 serializeSimpleSoundSpec(sound_dug, os);
224 void ContentFeatures::deSerialize(std::istream &is)
226 int version = readU8(is);
227 if(version != 4 && version != 3)
228 throw SerializationError("unsupported ContentFeatures version");
229 name = deSerializeString(is);
231 u32 groups_size = readU16(is);
232 for(u32 i=0; i<groups_size; i++){
233 std::string name = deSerializeString(is);
234 int value = readS16(is);
235 groups[name] = value;
237 drawtype = (enum NodeDrawType)readU8(is);
238 visual_scale = readF1000(is);
240 throw SerializationError("unsupported tile count");
241 for(u32 i=0; i<6; i++){
243 tiledef[i].deSerialize(is);
244 else if(version == 3) // Allow connecting to older servers
245 tiledef[i].name = deSerializeString(is);
247 if(readU8(is) != CF_SPECIAL_COUNT)
248 throw SerializationError("unsupported CF_SPECIAL_COUNT");
249 for(u32 i=0; i<CF_SPECIAL_COUNT; i++){
251 tiledef_special[i].deSerialize(is);
252 } else if(version == 3){ // Allow connecting to older servers
253 tiledef_special[i].name = deSerializeString(is);
254 tiledef_special[i].backface_culling = readU8(is);
258 post_effect_color.setAlpha(readU8(is));
259 post_effect_color.setRed(readU8(is));
260 post_effect_color.setGreen(readU8(is));
261 post_effect_color.setBlue(readU8(is));
262 param_type = (enum ContentParamType)readU8(is);
263 param_type_2 = (enum ContentParamType2)readU8(is);
264 is_ground_content = readU8(is);
265 light_propagates = readU8(is);
266 sunlight_propagates = readU8(is);
267 walkable = readU8(is);
268 pointable = readU8(is);
269 diggable = readU8(is);
270 climbable = readU8(is);
271 buildable_to = readU8(is);
272 deSerializeString(is); // legacy: used to be metadata_name
273 liquid_type = (enum LiquidType)readU8(is);
274 liquid_alternative_flowing = deSerializeString(is);
275 liquid_alternative_source = deSerializeString(is);
276 liquid_viscosity = readU8(is);
277 light_source = readU8(is);
278 damage_per_second = readU32(is);
279 selection_box.deSerialize(is);
280 legacy_facedir_simple = readU8(is);
281 legacy_wallmounted = readU8(is);
282 deSerializeSimpleSoundSpec(sound_footstep, is);
283 deSerializeSimpleSoundSpec(sound_dig, is);
284 deSerializeSimpleSoundSpec(sound_dug, is);
285 // If you add anything here, insert it primarily inside the try-catch
286 // block to not need to increase the version.
288 }catch(SerializationError &e) {};
295 class CNodeDefManager: public IWritableNodeDefManager
300 m_name_id_mapping.clear();
301 m_name_id_mapping_with_aliases.clear();
303 for(u16 i=0; i<=MAX_CONTENT; i++)
305 ContentFeatures &f = m_content_features[i];
306 f.reset(); // Reset to defaults
313 f.drawtype = NDT_AIRLIKE;
314 f.param_type = CPT_LIGHT;
315 f.light_propagates = true;
316 f.sunlight_propagates = true;
320 f.buildable_to = true;
321 // Insert directly into containers
322 content_t c = CONTENT_AIR;
323 m_content_features[c] = f;
324 addNameIdMapping(c, f.name);
326 // Set CONTENT_IGNORE
330 f.drawtype = NDT_AIRLIKE;
331 f.param_type = CPT_NONE;
332 f.light_propagates = false;
333 f.sunlight_propagates = false;
337 // A way to remove accidental CONTENT_IGNOREs
338 f.buildable_to = true;
339 // Insert directly into containers
340 content_t c = CONTENT_IGNORE;
341 m_content_features[c] = f;
342 addNameIdMapping(c, f.name);
345 // CONTENT_IGNORE = not found
346 content_t getFreeId(bool require_full_param2)
348 // If allowed, first search in the large 4-bit-param2 pool
349 if(!require_full_param2){
350 for(u16 i=0x800; i<=0xfff; i++){
351 const ContentFeatures &f = m_content_features[i];
356 // Then search from the small 8-bit-param2 pool
357 for(u16 i=0; i<=125; i++){
358 const ContentFeatures &f = m_content_features[i];
362 return CONTENT_IGNORE;
368 virtual ~CNodeDefManager()
371 virtual IWritableNodeDefManager* clone()
373 CNodeDefManager *mgr = new CNodeDefManager();
374 for(u16 i=0; i<=MAX_CONTENT; i++)
380 virtual const ContentFeatures& get(content_t c) const
382 assert(c <= MAX_CONTENT);
383 return m_content_features[c];
385 virtual const ContentFeatures& get(const MapNode &n) const
387 return get(n.getContent());
389 virtual bool getId(const std::string &name, content_t &result) const
391 std::map<std::string, content_t>::const_iterator
392 i = m_name_id_mapping_with_aliases.find(name);
393 if(i == m_name_id_mapping_with_aliases.end())
398 virtual content_t getId(const std::string &name) const
400 content_t id = CONTENT_IGNORE;
404 virtual void getIds(const std::string &name, std::set<content_t> &result)
407 if(name.substr(0,6) != "group:"){
408 content_t id = CONTENT_IGNORE;
413 std::string group = name.substr(6);
414 for(u16 id=0; id<=MAX_CONTENT; id++)
416 const ContentFeatures &f = m_content_features[id];
417 if(f.name == "") // Quickly discard undefined nodes
419 if(itemgroup_get(f.groups, group) != 0)
423 virtual const ContentFeatures& get(const std::string &name) const
425 content_t id = CONTENT_IGNORE;
429 // IWritableNodeDefManager
430 virtual void set(content_t c, const ContentFeatures &def)
432 verbosestream<<"registerNode: registering content id \""<<c
433 <<"\": name=\""<<def.name<<"\""<<std::endl;
434 assert(c <= MAX_CONTENT);
435 // Don't allow redefining CONTENT_IGNORE (but allow air)
436 if(def.name == "ignore" || c == CONTENT_IGNORE){
437 infostream<<"registerNode: WARNING: Ignoring "
438 <<"CONTENT_IGNORE redefinition"<<std::endl;
441 // Check that the special contents are not redefined as different id
442 // because it would mess up everything
443 if((def.name == "ignore" && c != CONTENT_IGNORE) ||
444 (def.name == "air" && c != CONTENT_AIR)){
445 errorstream<<"registerNode: IGNORING ERROR: "
446 <<"trying to register built-in type \""
447 <<def.name<<"\" as different id"<<std::endl;
450 m_content_features[c] = def;
452 addNameIdMapping(c, def.name);
454 virtual content_t set(const std::string &name,
455 const ContentFeatures &def)
457 assert(name == def.name);
458 u16 id = CONTENT_IGNORE;
459 bool found = m_name_id_mapping.getId(name, id); // ignore aliases
461 // Determine if full param2 is required
462 bool require_full_param2 = (
463 def.param_type_2 == CPT2_FULL
465 def.param_type_2 == CPT2_FLOWINGLIQUID
467 def.legacy_wallmounted
470 id = getFreeId(require_full_param2);
471 if(id == CONTENT_IGNORE)
472 return CONTENT_IGNORE;
474 addNameIdMapping(id, name);
479 virtual content_t allocateDummy(const std::string &name)
486 virtual void updateAliases(IItemDefManager *idef)
488 std::set<std::string> all = idef->getAll();
489 m_name_id_mapping_with_aliases.clear();
490 for(std::set<std::string>::iterator
491 i = all.begin(); i != all.end(); i++)
493 std::string name = *i;
494 std::string convert_to = idef->getAlias(name);
496 if(m_name_id_mapping.getId(convert_to, id))
498 m_name_id_mapping_with_aliases.insert(
499 std::make_pair(name, id));
503 virtual void updateTextures(ITextureSource *tsrc)
506 infostream<<"CNodeDefManager::updateTextures(): Updating "
507 <<"textures in node definitions"<<std::endl;
509 bool new_style_water = g_settings->getBool("new_style_water");
510 bool new_style_leaves = g_settings->getBool("new_style_leaves");
511 bool opaque_water = g_settings->getBool("opaque_water");
513 for(u16 i=0; i<=MAX_CONTENT; i++)
515 ContentFeatures *f = &m_content_features[i];
517 // Figure out the actual tiles to use
519 for(u32 j=0; j<6; j++)
521 tiledef[j] = f->tiledef[j];
522 if(tiledef[j].name == "")
523 tiledef[j].name = "unknown_block.png";
535 assert(f->liquid_type == LIQUID_SOURCE);
544 f->backface_culling = false;
547 case NDT_FLOWINGLIQUID:
548 assert(f->liquid_type == LIQUID_FLOWING);
555 f->visual_solidness = 1;
559 f->visual_solidness = 1;
561 case NDT_ALLFACES_OPTIONAL:
562 if(new_style_leaves){
563 f->drawtype = NDT_ALLFACES;
565 f->visual_solidness = 1;
567 f->drawtype = NDT_NORMAL;
569 for(u32 i=0; i<6; i++){
570 tiledef[i].name += std::string("^[noalpha");
583 // Tiles (fill in f->tiles[])
584 for(u16 j=0; j<6; j++){
586 f->tiles[j].texture = tsrc->getTexture(tiledef[j].name);
588 f->tiles[j].alpha = f->alpha;
590 f->tiles[j].material_type = MATERIAL_ALPHA_SIMPLE;
592 f->tiles[j].material_type = MATERIAL_ALPHA_VERTEX;
594 f->tiles[j].material_flags = 0;
595 if(f->backface_culling)
596 f->tiles[j].material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
597 if(tiledef[j].animation.type == TAT_VERTICAL_FRAMES)
598 f->tiles[j].material_flags |= MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
599 // Animation parameters
600 if(f->tiles[j].material_flags &
601 MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES)
603 // Get raw texture size to determine frame count by
605 video::ITexture *t = tsrc->getTextureRaw(tiledef[j].name);
606 v2u32 size = t->getOriginalSize();
607 int frame_height = (float)size.X /
608 (float)tiledef[j].animation.aspect_w *
609 (float)tiledef[j].animation.aspect_h;
610 int frame_count = size.Y / frame_height;
611 int frame_length_ms = 1000.0 *
612 tiledef[j].animation.length / frame_count;
613 f->tiles[j].animation_frame_count = frame_count;
614 f->tiles[j].animation_frame_length_ms = frame_length_ms;
616 // If there are no frames for an animation, switch
617 // animation off (so that having specified an animation
618 // for something but not using it in the texture pack
619 // gives no overhead)
620 if(frame_count == 1){
621 f->tiles[j].material_flags &=
622 ~MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
626 // Special tiles (fill in f->special_tiles[])
627 for(u16 j=0; j<CF_SPECIAL_COUNT; j++){
629 f->special_tiles[j].texture =
630 tsrc->getTexture(f->tiledef_special[j].name);
632 f->special_tiles[j].alpha = f->alpha;
634 f->special_tiles[j].material_type = MATERIAL_ALPHA_SIMPLE;
636 f->special_tiles[j].material_type = MATERIAL_ALPHA_VERTEX;
638 f->special_tiles[j].material_flags = 0;
639 if(f->tiledef_special[j].backface_culling)
640 f->special_tiles[j].material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
641 if(f->tiledef_special[j].animation.type == TAT_VERTICAL_FRAMES)
642 f->special_tiles[j].material_flags |= MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
643 // Animation parameters
644 if(f->special_tiles[j].material_flags &
645 MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES)
647 // Get raw texture size to determine frame count by
649 video::ITexture *t = tsrc->getTextureRaw(f->tiledef_special[j].name);
650 v2u32 size = t->getOriginalSize();
651 int frame_height = (float)size.X /
652 (float)f->tiledef_special[j].animation.aspect_w *
653 (float)f->tiledef_special[j].animation.aspect_h;
654 int frame_count = size.Y / frame_height;
655 int frame_length_ms = 1000.0 *
656 f->tiledef_special[j].animation.length / frame_count;
657 f->special_tiles[j].animation_frame_count = frame_count;
658 f->special_tiles[j].animation_frame_length_ms = frame_length_ms;
660 // If there are no frames for an animation, switch
661 // animation off (so that having specified an animation
662 // for something but not using it in the texture pack
663 // gives no overhead)
664 if(frame_count == 1){
665 f->special_tiles[j].material_flags &=
666 ~MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
673 void serialize(std::ostream &os)
675 writeU8(os, 1); // version
677 std::ostringstream os2(std::ios::binary);
678 for(u16 i=0; i<=MAX_CONTENT; i++)
680 if(i == CONTENT_IGNORE || i == CONTENT_AIR)
682 ContentFeatures *f = &m_content_features[i];
686 // Wrap it in a string to allow different lengths without
687 // strict version incompatibilities
688 std::ostringstream wrapper_os(std::ios::binary);
689 f->serialize(wrapper_os);
690 os2<<serializeString(wrapper_os.str());
694 os<<serializeLongString(os2.str());
696 void deSerialize(std::istream &is)
699 int version = readU8(is);
701 throw SerializationError("unsupported NodeDefinitionManager version");
702 u16 count = readU16(is);
703 std::istringstream is2(deSerializeLongString(is), std::ios::binary);
704 for(u16 n=0; n<count; n++){
705 u16 i = readU16(is2);
707 errorstream<<"ContentFeatures::deSerialize(): "
708 <<"Too large content id: "<<i<<std::endl;
711 /*// Do not deserialize special types
712 if(i == CONTENT_IGNORE || i == CONTENT_AIR)
714 ContentFeatures *f = &m_content_features[i];
715 // Read it from the string wrapper
716 std::string wrapper = deSerializeString(is2);
717 std::istringstream wrapper_is(wrapper, std::ios::binary);
718 f->deSerialize(wrapper_is);
719 verbosestream<<"deserialized "<<f->name<<std::endl;
721 addNameIdMapping(i, f->name);
725 void addNameIdMapping(content_t i, std::string name)
727 m_name_id_mapping.set(i, name);
728 m_name_id_mapping_with_aliases.insert(std::make_pair(name, i));
731 // Features indexed by id
732 ContentFeatures m_content_features[MAX_CONTENT+1];
733 // A mapping for fast converting back and forth between names and ids
734 NameIdMapping m_name_id_mapping;
735 // Like m_name_id_mapping, but only from names to ids, and includes
736 // item aliases too. Updated by updateAliases()
737 // Note: Not serialized.
738 std::map<std::string, content_t> m_name_id_mapping_with_aliases;
741 IWritableNodeDefManager* createNodeDefManager()
743 return new CNodeDefManager();