X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fnodedef.cpp;h=93751c70e3160e3355e7042ec3f47ee2c3ebea08;hb=86a0f5603b9e936b8527ae22c4aeaf5714c9d279;hp=9f2d4f0af4552dbfc129d58a7f6b74704549a5dc;hpb=d566ffaa5fc8400d4b457b2c0b4edd36189417d9;p=oweals%2Fminetest.git diff --git a/src/nodedef.cpp b/src/nodedef.cpp index 9f2d4f0af..93751c70e 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -1,18 +1,18 @@ /* -Minetest-c55 -Copyright (C) 2010 celeron55, Perttu Ahola +Minetest +Copyright (C) 2013 celeron55, Perttu Ahola This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GNU Lesser General Public License for more details. -You should have received a copy of the GNU General Public License along +You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ @@ -20,62 +20,141 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "nodedef.h" #include "main.h" // For g_settings -#include "nodemetadata.h" +#include "itemdef.h" #ifndef SERVER #include "tile.h" #endif #include "log.h" #include "settings.h" #include "nameidmapping.h" +#include "util/numeric.h" +#include "util/serialize.h" +//#include "profiler.h" // For TimeTaker /* NodeBox */ -void NodeBox::serialize(std::ostream &os) const +void NodeBox::reset() { - writeU8(os, 0); // version - writeU8(os, type); - writeV3F1000(os, fixed.MinEdge); - writeV3F1000(os, fixed.MaxEdge); - writeV3F1000(os, wall_top.MinEdge); - writeV3F1000(os, wall_top.MaxEdge); - writeV3F1000(os, wall_bottom.MinEdge); - writeV3F1000(os, wall_bottom.MaxEdge); - writeV3F1000(os, wall_side.MinEdge); - writeV3F1000(os, wall_side.MaxEdge); + type = NODEBOX_REGULAR; + // default is empty + fixed.clear(); + // default is sign/ladder-like + wall_top = aabb3f(-BS/2, BS/2-BS/16., -BS/2, BS/2, BS/2, BS/2); + wall_bottom = aabb3f(-BS/2, -BS/2, -BS/2, BS/2, -BS/2+BS/16., BS/2); + wall_side = aabb3f(-BS/2, -BS/2, -BS/2, -BS/2+BS/16., BS/2, BS/2); +} + +void NodeBox::serialize(std::ostream &os, u16 protocol_version) const +{ + int version = protocol_version >= 21 ? 2 : 1; + writeU8(os, version); + + if (version == 1 && type == NODEBOX_LEVELED) + writeU8(os, NODEBOX_FIXED); + else + writeU8(os, type); + + if(type == NODEBOX_FIXED || type == NODEBOX_LEVELED) + { + writeU16(os, fixed.size()); + for(std::vector::const_iterator + i = fixed.begin(); + i != fixed.end(); i++) + { + writeV3F1000(os, i->MinEdge); + writeV3F1000(os, i->MaxEdge); + } + } + else if(type == NODEBOX_WALLMOUNTED) + { + writeV3F1000(os, wall_top.MinEdge); + writeV3F1000(os, wall_top.MaxEdge); + writeV3F1000(os, wall_bottom.MinEdge); + writeV3F1000(os, wall_bottom.MaxEdge); + writeV3F1000(os, wall_side.MinEdge); + writeV3F1000(os, wall_side.MaxEdge); + } } void NodeBox::deSerialize(std::istream &is) { int version = readU8(is); - if(version != 0) + if(version < 1 || version > 2) throw SerializationError("unsupported NodeBox version"); + + reset(); + type = (enum NodeBoxType)readU8(is); - fixed.MinEdge = readV3F1000(is); - fixed.MaxEdge = readV3F1000(is); - wall_top.MinEdge = readV3F1000(is); - wall_top.MaxEdge = readV3F1000(is); - wall_bottom.MinEdge = readV3F1000(is); - wall_bottom.MaxEdge = readV3F1000(is); - wall_side.MinEdge = readV3F1000(is); - wall_side.MaxEdge = readV3F1000(is); + + if(type == NODEBOX_FIXED || type == NODEBOX_LEVELED) + { + u16 fixed_count = readU16(is); + while(fixed_count--) + { + aabb3f box; + box.MinEdge = readV3F1000(is); + box.MaxEdge = readV3F1000(is); + fixed.push_back(box); + } + } + else if(type == NODEBOX_WALLMOUNTED) + { + wall_top.MinEdge = readV3F1000(is); + wall_top.MaxEdge = readV3F1000(is); + wall_bottom.MinEdge = readV3F1000(is); + wall_bottom.MaxEdge = readV3F1000(is); + wall_side.MinEdge = readV3F1000(is); + wall_side.MaxEdge = readV3F1000(is); + } } /* - MaterialSpec + TileDef */ -void MaterialSpec::serialize(std::ostream &os) const +void TileDef::serialize(std::ostream &os, u16 protocol_version) const { - os<= 17) + writeU8(os, 1); + else + writeU8(os, 0); + os<= 17) + writeU8(os, backface_culling); +} + +void TileDef::deSerialize(std::istream &is) +{ + int version = readU8(is); + name = deSerializeString(is); + animation.type = (TileAnimationType)readU8(is); + animation.aspect_w = readU16(is); + animation.aspect_h = readU16(is); + animation.length = readF1000(is); + if(version >= 1) + backface_culling = readU8(is); } -void MaterialSpec::deSerialize(std::istream &is) +/* + SimpleSoundSpec serialization +*/ + +static void serializeSimpleSoundSpec(const SimpleSoundSpec &ss, + std::ostream &os) +{ + os<first); + writeS16(os, i->second); + } writeU8(os, drawtype); writeF1000(os, visual_scale); writeU8(os, 6); - for(u32 i=0; i<6; i++) - os<set(i, get(i)); - } + *mgr = *this; return mgr; } virtual const ContentFeatures& get(content_t c) const { - assert(c <= MAX_CONTENT); - return m_content_features[c]; + if(c < m_content_features.size()) + return m_content_features[c]; + else + return m_content_features[CONTENT_UNKNOWN]; } virtual const ContentFeatures& get(const MapNode &n) const { @@ -400,7 +460,12 @@ public: } virtual bool getId(const std::string &name, content_t &result) const { - return m_name_id_mapping.getId(name, result); + 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; } virtual content_t getId(const std::string &name) const { @@ -408,62 +473,104 @@ public: getId(name, id); return id; } + 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()); + } virtual const ContentFeatures& get(const std::string &name) const { - content_t id = CONTENT_IGNORE; + content_t id = CONTENT_UNKNOWN; getId(name, id); return get(id); } - // IWritableNodeDefManager - virtual void set(content_t c, const ContentFeatures &def) + // returns CONTENT_IGNORE if no free ID found + content_t allocateId() { - infostream<<"registerNode: registering content 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; + } } - m_content_features[c] = def; - if(def.name != "") - m_name_id_mapping.set(c, def.name); + // If we arrive here, an overflow occurred in id. + // That means no ID was found + return CONTENT_IGNORE; } + // IWritableNodeDefManager virtual content_t set(const std::string &name, const ContentFeatures &def) { + assert(name != ""); assert(name == def.name); - u16 id = CONTENT_IGNORE; - bool found = m_name_id_mapping.getId(name, id); + + // 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)); + } } - set(id, def); return id; } virtual content_t allocateDummy(const std::string &name) @@ -471,12 +578,27 @@ public: assert(name != ""); ContentFeatures f; f.name = name; - f.setAllTextures("unknown_block.png"); - // Make unknown blocks diggable - f.material.diggability = DIGGABLE_NORMAL; return set(name, f); } - virtual void updateTextures(ITextureSource *tsrc) + 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)); + } + } + } + virtual void updateTextures(ITextureSource *tsrc, + IShaderSource *shdsrc) { #ifndef SERVER infostream<<"CNodeDefManager::updateTextures(): Updating " @@ -485,11 +607,29 @@ public: bool new_style_water = g_settings->getBool("new_style_water"); bool new_style_leaves = g_settings->getBool("new_style_leaves"); bool opaque_water = g_settings->getBool("opaque_water"); - - for(u16 i=0; i<=MAX_CONTENT; i++) + 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"; + } + + bool is_liquid = false; + bool is_water_surface = false; + + u8 material_type; + material_type = (f->alpha == 255) ? TILE_MATERIAL_BASIC : TILE_MATERIAL_ALPHA; + switch(f->drawtype){ default: case NDT_NORMAL: @@ -506,21 +646,25 @@ public: f->solidness = 0; } else { f->solidness = 1; - if(f->alpha == 255) - f->solidness = 2; 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_ALLFACES: f->solidness = 0; f->visual_solidness = 1; @@ -534,113 +678,238 @@ public: f->drawtype = NDT_NORMAL; f->solidness = 2; for(u32 i=0; i<6; i++){ - f->setTexture(i, f->tname_tiles[i] - + std::string("^[noalpha")); + 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_TORCHLIKE: case NDT_SIGNLIKE: - case NDT_PLANTLIKE: case NDT_FENCELIKE: case NDT_RAILLIKE: + case NDT_NODEBOX: f->solidness = 0; break; } - // Inventory texture - if(f->tname_inventory != "") - f->inventory_texture = tsrc->getTextureRaw(f->tname_inventory); - else - f->inventory_texture = NULL; - // Tile textures - for(u16 j=0; j<6; j++){ - if(f->tname_tiles[j] == "") - continue; - f->tiles[j].texture = tsrc->getTexture(f->tname_tiles[j]); + 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; - if(f->alpha == 255) - f->tiles[j].material_type = MATERIAL_ALPHA_SIMPLE; - else - f->tiles[j].material_type = MATERIAL_ALPHA_VERTEX; + // 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; - else - 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 textures + // Special tiles (fill in f->special_tiles[]) for(u16 j=0; jspecial_aps[j]){ - delete f->special_aps[j]; - f->special_aps[j] = NULL; + // Shader + f->special_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(f->special_materials[j]){ - delete f->special_materials[j]; - f->special_materials[j] = NULL; + 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; + } } - // Skip if should not exist - if(f->mspec_special[j].tname == "") - continue; - // Create all stuff - f->special_aps[j] = new AtlasPointer( - tsrc->getTexture(f->mspec_special[j].tname)); - f->special_materials[j] = new video::SMaterial; - f->special_materials[j]->setFlag(video::EMF_LIGHTING, false); - f->special_materials[j]->setFlag(video::EMF_BACK_FACE_CULLING, - f->mspec_special[j].backface_culling); - f->special_materials[j]->setFlag(video::EMF_BILINEAR_FILTER, false); - f->special_materials[j]->setFlag(video::EMF_FOG_ENABLE, true); - f->special_materials[j]->setTexture(0, f->special_aps[j]->atlas); - if(f->alpha != 255) - f->special_materials[j]->MaterialType = - video::EMT_TRANSPARENT_VERTEX_ALPHA; } } #endif } - void serialize(std::ostream &os) + void serialize(std::ostream &os, u16 protocol_version) { + writeU8(os, 1); // version u16 count = 0; - std::ostringstream tmp_os(std::ios::binary); - for(u16 i=0; i<=MAX_CONTENT; i++) + std::ostringstream os2(std::ios::binary); + for(u32 i = 0; i < m_content_features.size(); i++) { - if(i == CONTENT_IGNORE || i == CONTENT_AIR) + if(i == CONTENT_IGNORE || i == CONTENT_AIR + || i == CONTENT_UNKNOWN) continue; ContentFeatures *f = &m_content_features[i]; if(f->name == "") continue; - writeU16(tmp_os, i); - f->serialize(tmp_os); + 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++; } writeU16(os, count); - os< MAX_CONTENT){ - errorstream<<"ContentFeatures::deSerialize(): " - <<"Too large content id: "<deSerialize(tmp_is, gamedef); - if(f->name != "") - m_name_id_mapping.set(i, f->name); + if(f.name == ""){ + infostream<<"NodeDefManager::deSerialize(): WARNING: " + <<"received empty name"<= m_content_features.size()) + m_content_features.resize((u32)(i) + 1); + m_content_features[i] = f; + addNameIdMapping(i, f.name); + verbosestream<<"deserialized "< 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() @@ -648,3 +917,224 @@ IWritableNodeDefManager* createNodeDefManager() return new CNodeDefManager(); } +/* + Serialization of old ContentFeatures formats +*/ + +void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) +{ + 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++) + 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++){ + tiledef_special[i].serialize(os, protocol_version); + } + writeU8(os, alpha); + writeU8(os, post_effect_color.getAlpha()); + writeU8(os, post_effect_color.getRed()); + writeU8(os, post_effect_color.getGreen()); + writeU8(os, post_effect_color.getBlue()); + writeU8(os, param_type); + writeU8(os, param_type_2); + writeU8(os, is_ground_content); + writeU8(os, light_propagates); + writeU8(os, sunlight_propagates); + writeU8(os, walkable); + writeU8(os, pointable); + writeU8(os, diggable); + writeU8(os, climbable); + writeU8(os, buildable_to); + os< 13 && protocol_version < 24) { + 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++) + 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++){ + tiledef_special[i].serialize(os, protocol_version); + } + writeU8(os, alpha); + writeU8(os, post_effect_color.getAlpha()); + writeU8(os, post_effect_color.getRed()); + writeU8(os, post_effect_color.getGreen()); + writeU8(os, post_effect_color.getBlue()); + writeU8(os, param_type); + writeU8(os, param_type_2); + writeU8(os, is_ground_content); + writeU8(os, light_propagates); + writeU8(os, sunlight_propagates); + writeU8(os, walkable); + writeU8(os, pointable); + writeU8(os, diggable); + writeU8(os, climbable); + writeU8(os, buildable_to); + os<