From 01ce57ade534f83d80bbb1f0c48630891b338237 Mon Sep 17 00:00:00 2001 From: kwolekr Date: Fri, 3 Oct 2014 03:16:43 -0400 Subject: Clean up nodedef.cpp --- src/nodedef.cpp | 1102 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 562 insertions(+), 540 deletions(-) diff --git a/src/nodedef.cpp b/src/nodedef.cpp index 8a5cff3bf..92e4b59b3 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -370,592 +370,612 @@ void ContentFeatures::deSerialize(std::istream &is) CNodeDefManager */ -class CNodeDefManager: public IWritableNodeDefManager -{ +class CNodeDefManager: public IWritableNodeDefManager { public: - void clear() - { - m_content_features.clear(); - m_name_id_mapping.clear(); - m_name_id_mapping_with_aliases.clear(); - m_group_to_items.clear(); - m_next_id = 0; - - u32 initial_length = 0; - initial_length = MYMAX(initial_length, CONTENT_UNKNOWN + 1); - initial_length = MYMAX(initial_length, CONTENT_AIR + 1); - initial_length = MYMAX(initial_length, CONTENT_IGNORE + 1); - m_content_features.resize(initial_length); - - // Set CONTENT_UNKNOWN - { - ContentFeatures f; - f.name = "unknown"; - // Insert directly into containers - content_t c = CONTENT_UNKNOWN; - m_content_features[c] = f; - addNameIdMapping(c, f.name); - } + CNodeDefManager(); + virtual ~CNodeDefManager(); + void clear(); + virtual IWritableNodeDefManager *clone(); + virtual const ContentFeatures& get(content_t c) const; + virtual const ContentFeatures& get(const MapNode &n) const; + virtual bool getId(const std::string &name, content_t &result) const; + virtual content_t getId(const std::string &name) const; + virtual void getIds(const std::string &name, std::set &result) const; + virtual const ContentFeatures& get(const std::string &name) const; + content_t allocateId(); + virtual content_t set(const std::string &name, const ContentFeatures &def); + virtual content_t allocateDummy(const std::string &name); + virtual void updateAliases(IItemDefManager *idef); + virtual void updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc); + void serialize(std::ostream &os, u16 protocol_version); + void deSerialize(std::istream &is); - // Set CONTENT_AIR - { - ContentFeatures f; - f.name = "air"; - f.drawtype = NDT_AIRLIKE; - f.param_type = CPT_LIGHT; - f.light_propagates = true; - f.sunlight_propagates = true; - f.walkable = false; - f.pointable = false; - f.diggable = false; - f.buildable_to = true; - f.is_ground_content = true; - // Insert directly into containers - content_t c = CONTENT_AIR; - m_content_features[c] = f; - addNameIdMapping(c, f.name); - } +private: + void addNameIdMapping(content_t i, std::string name); +#ifndef SERVER + void fillTileAttribs(ITextureSource *tsrc, TileSpec *tile, TileDef *tiledef, + u32 shader_id, bool use_normal_texture, u8 alpha, u8 material_type); +#endif - // Set CONTENT_IGNORE - { - ContentFeatures f; - f.name = "ignore"; - f.drawtype = NDT_AIRLIKE; - f.param_type = CPT_NONE; - f.light_propagates = false; - f.sunlight_propagates = false; - f.walkable = false; - f.pointable = false; - f.diggable = false; - f.buildable_to = true; // A way to remove accidental CONTENT_IGNOREs - f.is_ground_content = true; - // Insert directly into containers - content_t c = CONTENT_IGNORE; - m_content_features[c] = f; - addNameIdMapping(c, f.name); - } - } - CNodeDefManager() - { - clear(); - } - virtual ~CNodeDefManager() - { - } - virtual IWritableNodeDefManager* clone() - { - CNodeDefManager *mgr = new CNodeDefManager(); - *mgr = *this; - return mgr; - } - virtual const ContentFeatures& get(content_t c) const + // Features indexed by id + std::vector m_content_features; + + // A mapping for fast converting back and forth between names and ids + NameIdMapping m_name_id_mapping; + + // Like m_name_id_mapping, but only from names to ids, and includes + // item aliases too. Updated by updateAliases() + // Note: Not serialized. + + std::map m_name_id_mapping_with_aliases; + + // A mapping from groups to a list of content_ts (and their levels) + // that belong to it. Necessary for a direct lookup in getIds(). + // Note: Not serialized. + std::map m_group_to_items; + + // Next possibly free id + content_t m_next_id; +}; + + +CNodeDefManager::CNodeDefManager() +{ + clear(); +} + + +CNodeDefManager::~CNodeDefManager() +{ +} + + +void CNodeDefManager::clear() +{ + m_content_features.clear(); + m_name_id_mapping.clear(); + m_name_id_mapping_with_aliases.clear(); + m_group_to_items.clear(); + m_next_id = 0; + + u32 initial_length = 0; + initial_length = MYMAX(initial_length, CONTENT_UNKNOWN + 1); + initial_length = MYMAX(initial_length, CONTENT_AIR + 1); + initial_length = MYMAX(initial_length, CONTENT_IGNORE + 1); + m_content_features.resize(initial_length); + + // Set CONTENT_UNKNOWN { - if(c < m_content_features.size()) - return m_content_features[c]; - else - return m_content_features[CONTENT_UNKNOWN]; + ContentFeatures f; + f.name = "unknown"; + // Insert directly into containers + content_t c = CONTENT_UNKNOWN; + m_content_features[c] = f; + addNameIdMapping(c, f.name); } - virtual const ContentFeatures& get(const MapNode &n) const + + // Set CONTENT_AIR { - return get(n.getContent()); + ContentFeatures f; + f.name = "air"; + f.drawtype = NDT_AIRLIKE; + f.param_type = CPT_LIGHT; + f.light_propagates = true; + f.sunlight_propagates = true; + f.walkable = false; + f.pointable = false; + f.diggable = false; + f.buildable_to = true; + f.is_ground_content = true; + // Insert directly into containers + content_t c = CONTENT_AIR; + m_content_features[c] = f; + addNameIdMapping(c, f.name); } - virtual bool getId(const std::string &name, content_t &result) const + + // Set CONTENT_IGNORE { - std::map::const_iterator - i = m_name_id_mapping_with_aliases.find(name); - if(i == m_name_id_mapping_with_aliases.end()) - return false; - result = i->second; - return true; + ContentFeatures f; + f.name = "ignore"; + f.drawtype = NDT_AIRLIKE; + f.param_type = CPT_NONE; + f.light_propagates = false; + f.sunlight_propagates = false; + f.walkable = false; + f.pointable = false; + f.diggable = false; + f.buildable_to = true; // A way to remove accidental CONTENT_IGNOREs + f.is_ground_content = true; + // Insert directly into containers + content_t c = CONTENT_IGNORE; + m_content_features[c] = f; + addNameIdMapping(c, f.name); } - virtual content_t getId(const std::string &name) const - { +} + + +IWritableNodeDefManager *CNodeDefManager::clone() +{ + CNodeDefManager *mgr = new CNodeDefManager(); + *mgr = *this; + return mgr; +} + + +const ContentFeatures& CNodeDefManager::get(content_t c) const +{ + if (c < m_content_features.size()) + return m_content_features[c]; + else + return m_content_features[CONTENT_UNKNOWN]; +} + + +const ContentFeatures& CNodeDefManager::get(const MapNode &n) const +{ + return get(n.getContent()); +} + + +bool CNodeDefManager::getId(const std::string &name, content_t &result) const +{ + std::map::const_iterator + i = m_name_id_mapping_with_aliases.find(name); + if(i == m_name_id_mapping_with_aliases.end()) + return false; + result = i->second; + return true; +} + + +content_t CNodeDefManager::getId(const std::string &name) const +{ + content_t id = CONTENT_IGNORE; + getId(name, id); + return id; +} + + +void CNodeDefManager::getIds(const std::string &name, std::set &result) + const +{ + //TimeTaker t("getIds", NULL, PRECISION_MICRO); + if (name.substr(0,6) != "group:") { content_t id = CONTENT_IGNORE; - getId(name, id); - return id; + if(getId(name, id)) + result.insert(id); + return; } - virtual void getIds(const std::string &name, std::set &result) - const - { - //TimeTaker t("getIds", NULL, PRECISION_MICRO); - if(name.substr(0,6) != "group:"){ - content_t id = CONTENT_IGNORE; - if(getId(name, id)) - result.insert(id); - return; + std::string group = name.substr(6); + + std::map::const_iterator + i = m_group_to_items.find(group); + if (i == m_group_to_items.end()) + return; + + const GroupItems &items = i->second; + for (GroupItems::const_iterator j = items.begin(); + j != items.end(); ++j) { + if ((*j).second != 0) + result.insert((*j).first); + } + //printf("getIds: %dus\n", t.stop()); +} + + +const ContentFeatures& CNodeDefManager::get(const std::string &name) const +{ + content_t id = CONTENT_UNKNOWN; + getId(name, id); + return get(id); +} + + +// returns CONTENT_IGNORE if no free ID found +content_t CNodeDefManager::allocateId() +{ + for (content_t id = m_next_id; + id >= m_next_id; // overflow? + ++id) { + while (id >= m_content_features.size()) { + m_content_features.push_back(ContentFeatures()); } - std::string group = name.substr(6); - - std::map::const_iterator - i = m_group_to_items.find(group); - if (i == m_group_to_items.end()) - return; - - const GroupItems &items = i->second; - for (GroupItems::const_iterator j = items.begin(); - j != items.end(); ++j) { - if ((*j).second != 0) - result.insert((*j).first); + const ContentFeatures &f = m_content_features[id]; + if (f.name == "") { + m_next_id = id + 1; + return id; } - //printf("getIds: %dus\n", t.stop()); - } - virtual const ContentFeatures& get(const std::string &name) const - { - content_t id = CONTENT_UNKNOWN; - getId(name, id); - return get(id); } - // returns CONTENT_IGNORE if no free ID found - content_t allocateId() - { - for(content_t id = m_next_id; - id >= m_next_id; // overflow? - ++id){ - while(id >= m_content_features.size()){ - m_content_features.push_back(ContentFeatures()); - } - const ContentFeatures &f = m_content_features[id]; - if(f.name == ""){ - m_next_id = id + 1; - return id; - } - } - // If we arrive here, an overflow occurred in id. - // That means no ID was found + // If we arrive here, an overflow occurred in id. + // That means no ID was found + return CONTENT_IGNORE; +} + + +// IWritableNodeDefManager +content_t CNodeDefManager::set(const std::string &name, const ContentFeatures &def) +{ + assert(name != ""); + assert(name == def.name); + + // Don't allow redefining ignore (but allow air and unknown) + if (name == "ignore") { + infostream << "NodeDefManager: WARNING: Ignoring " + "CONTENT_IGNORE redefinition"<first; - - std::map::iterator - j = m_group_to_items.find(group_name); - if (j == m_group_to_items.end()) { - m_group_to_items[group_name].push_back( - std::make_pair(id, i->second)); - } else { - GroupItems &items = j->second; - items.push_back(std::make_pair(id, i->second)); - } + // Add this content to the list of all groups it belongs to + // FIXME: This should remove a node from groups it no longer + // belongs to when a node is re-registered + for (ItemGroupList::const_iterator i = def.groups.begin(); + i != def.groups.end(); ++i) { + std::string group_name = i->first; + + std::map::iterator + j = m_group_to_items.find(group_name); + if (j == m_group_to_items.end()) { + m_group_to_items[group_name].push_back( + std::make_pair(id, i->second)); + } else { + GroupItems &items = j->second; + items.push_back(std::make_pair(id, i->second)); } - return id; } - virtual content_t allocateDummy(const std::string &name) - { - assert(name != ""); - ContentFeatures f; - f.name = name; - return set(name, f); - } - virtual void updateAliases(IItemDefManager *idef) - { - std::set all = idef->getAll(); - m_name_id_mapping_with_aliases.clear(); - for(std::set::iterator - i = all.begin(); i != all.end(); i++) - { - std::string name = *i; - std::string convert_to = idef->getAlias(name); - content_t id; - if(m_name_id_mapping.getId(convert_to, id)) - { - m_name_id_mapping_with_aliases.insert( - std::make_pair(name, id)); - } + return id; +} + + +content_t CNodeDefManager::allocateDummy(const std::string &name) +{ + assert(name != ""); + ContentFeatures f; + f.name = name; + return set(name, f); +} + + +void CNodeDefManager::updateAliases(IItemDefManager *idef) +{ + std::set all = idef->getAll(); + m_name_id_mapping_with_aliases.clear(); + for (std::set::iterator + i = all.begin(); i != all.end(); i++) { + std::string name = *i; + std::string convert_to = idef->getAlias(name); + content_t id; + if (m_name_id_mapping.getId(convert_to, id)) { + m_name_id_mapping_with_aliases.insert( + std::make_pair(name, id)); } } - virtual void updateTextures(ITextureSource *tsrc, - IShaderSource *shdsrc) - { +} + + +void CNodeDefManager::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc) +{ #ifndef SERVER - infostream<<"CNodeDefManager::updateTextures(): Updating " - <<"textures in node definitions"<getBool("new_style_water"); - bool new_style_leaves = g_settings->getBool("new_style_leaves"); - bool connected_glass = g_settings->getBool("connected_glass"); - bool opaque_water = g_settings->getBool("opaque_water"); - bool enable_shaders = g_settings->getBool("enable_shaders"); - bool enable_bumpmapping = g_settings->getBool("enable_bumpmapping"); - bool enable_parallax_occlusion = g_settings->getBool("enable_parallax_occlusion"); - - for(u32 i=0; itiledef[j]; - if(tiledef[j].name == "") - tiledef[j].name = "unknown_node.png"; - } + infostream << "CNodeDefManager::updateTextures(): Updating " + "textures in node definitions" << std::endl; - bool is_liquid = false; - bool is_water_surface = false; + bool new_style_water = g_settings->getBool("new_style_water"); + bool new_style_leaves = g_settings->getBool("new_style_leaves"); + bool connected_glass = g_settings->getBool("connected_glass"); + bool opaque_water = g_settings->getBool("opaque_water"); + bool enable_shaders = g_settings->getBool("enable_shaders"); + bool enable_bumpmapping = g_settings->getBool("enable_bumpmapping"); + bool enable_parallax_occlusion = g_settings->getBool("enable_parallax_occlusion"); - u8 material_type; - material_type = (f->alpha == 255) ? TILE_MATERIAL_BASIC : TILE_MATERIAL_ALPHA; + bool use_normal_texture = enable_shaders && + (enable_bumpmapping || enable_parallax_occlusion); - switch(f->drawtype){ - default: - case NDT_NORMAL: - f->solidness = 2; - break; - case NDT_AIRLIKE: - f->solidness = 0; - break; - case NDT_LIQUID: - assert(f->liquid_type == LIQUID_SOURCE); - if(opaque_water) - f->alpha = 255; - if(new_style_water){ - f->solidness = 0; - } else { - f->solidness = 1; - f->backface_culling = false; - } - is_liquid = true; - break; - case NDT_FLOWINGLIQUID: - assert(f->liquid_type == LIQUID_FLOWING); - f->solidness = 0; - if(opaque_water) - f->alpha = 255; - is_liquid = true; - break; - case NDT_GLASSLIKE: - f->solidness = 0; - f->visual_solidness = 1; - break; - case NDT_GLASSLIKE_FRAMED: - f->solidness = 0; - f->visual_solidness = 1; - break; - case NDT_GLASSLIKE_FRAMED_OPTIONAL: - f->solidness = 0; - f->visual_solidness = 1; - if (connected_glass) { - f->drawtype = NDT_GLASSLIKE_FRAMED; - } else { - f->drawtype = NDT_GLASSLIKE; - } - break; - case NDT_ALLFACES: - f->solidness = 0; - f->visual_solidness = 1; - break; - case NDT_ALLFACES_OPTIONAL: - if(new_style_leaves){ - f->drawtype = NDT_ALLFACES; - f->solidness = 0; - f->visual_solidness = 1; - } else { - f->drawtype = NDT_NORMAL; - f->solidness = 2; - for(u32 i=0; i<6; i++){ - tiledef[i].name += std::string("^[noalpha"); - } - } - if (f->waving == 1) - material_type = TILE_MATERIAL_WAVING_LEAVES; - break; - case NDT_PLANTLIKE: + for (u32 i = 0; i < m_content_features.size(); i++) { + ContentFeatures *f = &m_content_features[i]; + + // Figure out the actual tiles to use + TileDef tiledef[6]; + for (u32 j = 0; j < 6; j++) { + tiledef[j] = f->tiledef[j]; + if (tiledef[j].name == "") + tiledef[j].name = "unknown_node.png"; + } + + bool is_liquid = false; + bool is_water_surface = false; + + u8 material_type = (f->alpha == 255) ? + TILE_MATERIAL_BASIC : TILE_MATERIAL_ALPHA; + + switch (f->drawtype) { + default: + case NDT_NORMAL: + f->solidness = 2; + break; + case NDT_AIRLIKE: + f->solidness = 0; + break; + case NDT_LIQUID: + assert(f->liquid_type == LIQUID_SOURCE); + if (opaque_water) + f->alpha = 255; + if (new_style_water){ f->solidness = 0; + } else { + f->solidness = 1; f->backface_culling = false; - if (f->waving == 1) - material_type = TILE_MATERIAL_WAVING_PLANTS; - break; - case NDT_FIRELIKE: - f->backface_culling = false; - case NDT_TORCHLIKE: - case NDT_SIGNLIKE: - case NDT_FENCELIKE: - case NDT_RAILLIKE: - case NDT_NODEBOX: + } + is_liquid = true; + break; + case NDT_FLOWINGLIQUID: + assert(f->liquid_type == LIQUID_FLOWING); + f->solidness = 0; + if (opaque_water) + f->alpha = 255; + is_liquid = true; + break; + case NDT_GLASSLIKE: + f->solidness = 0; + f->visual_solidness = 1; + break; + case NDT_GLASSLIKE_FRAMED: + f->solidness = 0; + f->visual_solidness = 1; + break; + case NDT_GLASSLIKE_FRAMED_OPTIONAL: + f->solidness = 0; + f->visual_solidness = 1; + f->drawtype = connected_glass ? NDT_GLASSLIKE_FRAMED : NDT_GLASSLIKE; + break; + case NDT_ALLFACES: + f->solidness = 0; + f->visual_solidness = 1; + break; + case NDT_ALLFACES_OPTIONAL: + if (new_style_leaves) { + f->drawtype = NDT_ALLFACES; f->solidness = 0; - break; + f->visual_solidness = 1; + } else { + f->drawtype = NDT_NORMAL; + f->solidness = 2; + for (u32 i = 0; i < 6; i++) + tiledef[i].name += std::string("^[noalpha"); } + if (f->waving == 1) + material_type = TILE_MATERIAL_WAVING_LEAVES; + break; + case NDT_PLANTLIKE: + f->solidness = 0; + f->backface_culling = false; + if (f->waving == 1) + material_type = TILE_MATERIAL_WAVING_PLANTS; + break; + case NDT_FIRELIKE: + f->backface_culling = false; + case NDT_TORCHLIKE: + case NDT_SIGNLIKE: + case NDT_FENCELIKE: + case NDT_RAILLIKE: + case NDT_NODEBOX: + f->solidness = 0; + break; + } - if (is_liquid){ - material_type = (f->alpha == 255) ? TILE_MATERIAL_LIQUID_OPAQUE : TILE_MATERIAL_LIQUID_TRANSPARENT; - if (f->name == "default:water_source") - is_water_surface = true; - } - u32 tile_shader[6]; - for(u16 j=0; j<6; j++) - tile_shader[j] = shdsrc->getShader("nodes_shader",material_type, f->drawtype); - - if (is_water_surface) - tile_shader[0] = shdsrc->getShader("water_surface_shader",material_type, f->drawtype); - - // Tiles (fill in f->tiles[]) - for(u16 j = 0; j < 6; j++){ - // Shader - f->tiles[j].shader_id = tile_shader[j]; - // Texture - f->tiles[j].texture = tsrc->getTexture( - tiledef[j].name, - &f->tiles[j].texture_id); - // Normal texture - if (enable_shaders && (enable_bumpmapping || enable_parallax_occlusion)) - f->tiles[j].normal_texture = tsrc->getNormalTexture(tiledef[j].name); - // Alpha - f->tiles[j].alpha = f->alpha; - // Material type - f->tiles[j].material_type = material_type; - // Material flags - f->tiles[j].material_flags = 0; - if(f->backface_culling) - f->tiles[j].material_flags |= MATERIAL_FLAG_BACKFACE_CULLING; - if(tiledef[j].animation.type == TAT_VERTICAL_FRAMES) - f->tiles[j].material_flags |= MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES; - // Animation parameters - int frame_count = 1; - if(f->tiles[j].material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES) { - // Get texture size to determine frame count by - // aspect ratio - v2u32 size = f->tiles[j].texture->getOriginalSize(); - int frame_height = (float)size.X / - (float)tiledef[j].animation.aspect_w * - (float)tiledef[j].animation.aspect_h; - frame_count = size.Y / frame_height; - int frame_length_ms = 1000.0 * - tiledef[j].animation.length / frame_count; - f->tiles[j].animation_frame_count = frame_count; - f->tiles[j].animation_frame_length_ms = frame_length_ms; - } - if(frame_count == 1) { - f->tiles[j].material_flags &= ~MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES; - } else { - std::ostringstream os(std::ios::binary); - for (int i = 0; i < frame_count; i++) { - FrameSpec frame; - os.str(""); - os<getTexture(os.str(), &frame.texture_id); - if (f->tiles[j].normal_texture) - frame.normal_texture = tsrc->getNormalTexture(os.str()); - f->tiles[j].frames[i]=frame; - } - } - } - // Special tiles (fill in f->special_tiles[]) - for(u16 j=0; jspecial_tiles[j].shader_id = tile_shader[j]; - // Texture - f->special_tiles[j].texture = tsrc->getTexture( - f->tiledef_special[j].name, - &f->special_tiles[j].texture_id); - // Normal texture - if (enable_shaders && (enable_bumpmapping || enable_parallax_occlusion)) - f->special_tiles[j].normal_texture = tsrc->getNormalTexture(f->tiledef_special[j].name); - // Alpha - f->special_tiles[j].alpha = f->alpha; - // Material type - f->special_tiles[j].material_type = material_type; - // Material flags - f->special_tiles[j].material_flags = 0; - if(f->tiledef_special[j].backface_culling) - f->special_tiles[j].material_flags |= MATERIAL_FLAG_BACKFACE_CULLING; - if(f->tiledef_special[j].animation.type == TAT_VERTICAL_FRAMES) - f->special_tiles[j].material_flags |= MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES; - // Animation parameters - int frame_count = 1; - if(f->special_tiles[j].material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES) { - // Get texture size to determine frame count by - // aspect ratio - v2u32 size = f->special_tiles[j].texture->getOriginalSize(); - int frame_height = (float)size.X / - (float)f->tiledef_special[j].animation.aspect_w * - (float)f->tiledef_special[j].animation.aspect_h; - frame_count = size.Y / frame_height; - int frame_length_ms = 1000.0 * - f->tiledef_special[j].animation.length / frame_count; - f->special_tiles[j].animation_frame_count = frame_count; - f->special_tiles[j].animation_frame_length_ms = frame_length_ms; - } - if(frame_count == 1) { - f->special_tiles[j].material_flags &= ~MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES; - } else { - std::ostringstream os(std::ios::binary); - for (int i = 0; i < frame_count; i++) { - FrameSpec frame; - os.str(""); - os<tiledef_special[j].name<<"^[verticalframe:"<getTexture(os.str(), &frame.texture_id); - if (f->special_tiles[j].normal_texture) - frame.normal_texture = tsrc->getNormalTexture(os.str()); - f->special_tiles[j].frames[i]=frame; - } - } - } + if (is_liquid) { + material_type = (f->alpha == 255) ? + TILE_MATERIAL_LIQUID_OPAQUE : TILE_MATERIAL_LIQUID_TRANSPARENT; + if (f->name == "default:water_source") + is_water_surface = true; + } + + u32 tile_shader[6]; + for (u16 j = 0; j < 6; j++) { + tile_shader[j] = shdsrc->getShader("nodes_shader", + material_type, f->drawtype); + } + + if (is_water_surface) { + tile_shader[0] = shdsrc->getShader("water_surface_shader", + material_type, f->drawtype); + } + + // Tiles (fill in f->tiles[]) + for (u16 j = 0; j < 6; j++) { + fillTileAttribs(tsrc, &f->tiles[j], &tiledef[j], tile_shader[j], + use_normal_texture, f->alpha, material_type); + } + + // Special tiles (fill in f->special_tiles[]) + for (u16 j = 0; j < CF_SPECIAL_COUNT; j++) { + fillTileAttribs(tsrc, &f->special_tiles[j], &f->tiledef_special[j], + tile_shader[j], use_normal_texture, f->alpha, material_type); } + } #endif +} + + +#ifndef SERVER +void CNodeDefManager::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile, + TileDef *tiledef, u32 shader_id, bool use_normal_texture, + u8 alpha, u8 material_type) +{ + tile->shader_id = shader_id; + tile->texture = tsrc->getTexture(tiledef->name, &tile->texture_id); + tile->alpha = alpha; + tile->material_type = material_type; + + // Normal texture + if (use_normal_texture) + tile->normal_texture = tsrc->getNormalTexture(tiledef->name); + + // Material flags + tile->material_flags = 0; + if (tiledef->backface_culling) + tile->material_flags |= MATERIAL_FLAG_BACKFACE_CULLING; + if (tiledef->animation.type == TAT_VERTICAL_FRAMES) + tile->material_flags |= MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES; + + // Animation parameters + int frame_count = 1; + if (tile->material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES) { + // Get texture size to determine frame count by aspect ratio + v2u32 size = tile->texture->getOriginalSize(); + int frame_height = (float)size.X / + (float)tiledef->animation.aspect_w * + (float)tiledef->animation.aspect_h; + frame_count = size.Y / frame_height; + int frame_length_ms = 1000.0 * tiledef->animation.length / frame_count; + tile->animation_frame_count = frame_count; + tile->animation_frame_length_ms = frame_length_ms; } - void serialize(std::ostream &os, u16 protocol_version) - { - writeU8(os, 1); // version - u16 count = 0; - std::ostringstream os2(std::ios::binary); - for(u32 i = 0; i < m_content_features.size(); i++) - { - if(i == CONTENT_IGNORE || i == CONTENT_AIR - || i == CONTENT_UNKNOWN) - continue; - ContentFeatures *f = &m_content_features[i]; - if(f->name == "") - continue; - writeU16(os2, i); - // Wrap it in a string to allow different lengths without - // strict version incompatibilities - std::ostringstream wrapper_os(std::ios::binary); - f->serialize(wrapper_os, protocol_version); - os2< count); // must not overflow - count++; + + if (frame_count == 1) { + tile->material_flags &= ~MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES; + } else { + std::ostringstream os(std::ios::binary); + for (int i = 0; i < frame_count; i++) { + FrameSpec frame; + + os.str(""); + os << tiledef->name << "^[verticalframe:" + << frame_count << ":" << i; + + frame.texture = tsrc->getTexture(os.str(), &frame.texture_id); + if (tile->normal_texture) + frame.normal_texture = tsrc->getNormalTexture(os.str()); + tile->frames[i] = frame; } - writeU16(os, count); - os<= m_content_features.size()) - m_content_features.resize((u32)(i) + 1); - m_content_features[i] = f; - addNameIdMapping(i, f.name); - verbosestream<<"deserialized "<name == "") + continue; + writeU16(os2, i); + // Wrap it in a string to allow different lengths without + // strict version incompatibilities + std::ostringstream wrapper_os(std::ios::binary); + f->serialize(wrapper_os, protocol_version); + os2< count); // must not overflow + count++; } -private: - void addNameIdMapping(content_t i, std::string name) - { - m_name_id_mapping.set(i, name); - m_name_id_mapping_with_aliases.insert(std::make_pair(name, i)); + writeU16(os, count); + os << serializeLongString(os2.str()); +} + + +void CNodeDefManager::deSerialize(std::istream &is) +{ + clear(); + int version = readU8(is); + if (version != 1) + throw SerializationError("unsupported NodeDefinitionManager version"); + u16 count = readU16(is); + std::istringstream is2(deSerializeLongString(is), std::ios::binary); + ContentFeatures f; + for (u16 n = 0; n < count; n++) { + u16 i = readU16(is2); + + // Read it from the string wrapper + std::string wrapper = deSerializeString(is2); + std::istringstream wrapper_is(wrapper, std::ios::binary); + f.deSerialize(wrapper_is); + + // Check error conditions + if (i == CONTENT_IGNORE || i == CONTENT_AIR || i == CONTENT_UNKNOWN) { + infostream << "NodeDefManager::deSerialize(): WARNING: " + "not changing builtin node " << i << std::endl; + continue; + } + if (f.name == "") { + infostream << "NodeDefManager::deSerialize(): WARNING: " + "received empty name" << std::endl; + continue; + } + + // Ignore aliases + u16 existing_id; + if (m_name_id_mapping.getId(f.name, existing_id) && i != existing_id) { + infostream << "NodeDefManager::deSerialize(): WARNING: " + "already defined with different ID: " << f.name << std::endl; + continue; + } + + // All is ok, add node definition with the requested ID + if (i >= m_content_features.size()) + m_content_features.resize((u32)(i) + 1); + m_content_features[i] = f; + addNameIdMapping(i, f.name); + verbosestream << "deserialized " << f.name << std::endl; } -private: - // Features indexed by id - std::vector m_content_features; - // A mapping for fast converting back and forth between names and ids - NameIdMapping m_name_id_mapping; - // Like m_name_id_mapping, but only from names to ids, and includes - // item aliases too. Updated by updateAliases() - // Note: Not serialized. - std::map m_name_id_mapping_with_aliases; - // A mapping from groups to a list of content_ts (and their levels) - // that belong to it. Necessary for a direct lookup in getIds(). - // Note: Not serialized. - std::map m_group_to_items; - // Next possibly free id - content_t m_next_id; -}; +} + -IWritableNodeDefManager* createNodeDefManager() +void CNodeDefManager::addNameIdMapping(content_t i, std::string name) +{ + m_name_id_mapping.set(i, name); + m_name_id_mapping_with_aliases.insert(std::make_pair(name, i)); +} + + +IWritableNodeDefManager *createNodeDefManager() { return new CNodeDefManager(); } -/* - Serialization of old ContentFeatures formats -*/ +//// Serialization of old ContentFeatures formats void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) { - if(protocol_version == 13) + if (protocol_version == 13) { writeU8(os, 5); // version os<first); writeS16(os, i->second); } writeU8(os, drawtype); writeF1000(os, visual_scale); writeU8(os, 6); - for(u32 i = 0; i < 6; i++) + for (u32 i = 0; i < 6; i++) tiledef[i].serialize(os, protocol_version); //CF_SPECIAL_COUNT = 2 before cf ver. 7 and protocol ver. 24 writeU8(os, 2); - for(u32 i = 0; i < 2; i++){ + for (u32 i = 0; i < 2; i++) tiledef_special[i].serialize(os, protocol_version); - } writeU8(os, alpha); writeU8(os, post_effect_color.getAlpha()); writeU8(os, post_effect_color.getRed()); @@ -990,21 +1010,20 @@ void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) writeU8(os, 6); // version os<first); writeS16(os, i->second); } writeU8(os, drawtype); writeF1000(os, visual_scale); writeU8(os, 6); - for(u32 i = 0; i < 6; i++) + for (u32 i = 0; i < 6; i++) tiledef[i].serialize(os, protocol_version); //CF_SPECIAL_COUNT = 2 before cf ver. 7 and protocol ver. 24 writeU8(os, 2); - for(u32 i = 0; i < 2; i++){ + for (u32 i = 0; i < 2; i++) tiledef_special[i].serialize(os, protocol_version); - } writeU8(os, alpha); writeU8(os, post_effect_color.getAlpha()); writeU8(os, post_effect_color.getRed()); @@ -1040,12 +1059,14 @@ void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) writeU8(os, leveled); writeU8(os, liquid_range); } else - throw SerializationError("ContentFeatures::serialize(): Unsupported version requested"); + throw SerializationError("ContentFeatures::serialize(): " + "Unsupported version requested"); } + void ContentFeatures::deSerializeOld(std::istream &is, int version) { - if(version == 5) // In PROTOCOL_VERSION 13 + if (version == 5) // In PROTOCOL_VERSION 13 { name = deSerializeString(is); groups.clear(); @@ -1057,13 +1078,13 @@ void ContentFeatures::deSerializeOld(std::istream &is, int version) } drawtype = (enum NodeDrawType)readU8(is); visual_scale = readF1000(is); - if(readU8(is) != 6) + if (readU8(is) != 6) throw SerializationError("unsupported tile count"); - for(u32 i=0; i<6; i++) + for (u32 i = 0; i < 6; i++) tiledef[i].deSerialize(is); - if(readU8(is) != CF_SPECIAL_COUNT) + if (readU8(is) != CF_SPECIAL_COUNT) throw SerializationError("unsupported CF_SPECIAL_COUNT"); - for(u32 i=0; i