X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fnodedef.cpp;h=d644dc229d2c4af9f3fbf3edc073aba6f818aaee;hb=43ebec2be1949aa5eac127df7cb902d37e4e461b;hp=57807449e4247fe2925afd001a19ce7c051fd043;hpb=c1202a2ecca352d5491364877fbe11e509cda8d3;p=minetest.git diff --git a/src/nodedef.cpp b/src/nodedef.cpp index 57807449e..d644dc229 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -3,16 +3,16 @@ Minetest-c55 Copyright (C) 2010 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,125 +20,382 @@ 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/serialize.h" -ContentFeatures::~ContentFeatures() +/* + NodeBox +*/ + +void NodeBox::reset() { - delete initial_metadata; -#ifndef SERVER - delete special_material; - delete special_atlas; -#endif + 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); } -#ifndef SERVER -void ContentFeatures::setTexture(ITextureSource *tsrc, - u16 i, std::string name, u8 alpha) +void NodeBox::serialize(std::ostream &os) const { - used_texturenames.insert(name); - - if(tsrc) + writeU8(os, 1); // version + writeU8(os, type); + + if(type == NODEBOX_FIXED) { - tiles[i].texture = tsrc->getTexture(name); + writeU16(os, fixed.size()); + for(std::vector::const_iterator + i = fixed.begin(); + i != fixed.end(); i++) + { + writeV3F1000(os, i->MinEdge); + writeV3F1000(os, i->MaxEdge); + } } - - if(alpha != 255) + else if(type == NODEBOX_WALLMOUNTED) { - tiles[i].alpha = alpha; - tiles[i].material_type = MATERIAL_ALPHA_VERTEX; + 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); } - - if(inventory_texture == NULL) - setInventoryTexture(name, tsrc); } -void ContentFeatures::setInventoryTexture(std::string imgname, - ITextureSource *tsrc) +void NodeBox::deSerialize(std::istream &is) { - if(tsrc == NULL) - return; - - imgname += "^[forcesingle"; + int version = readU8(is); + if(version != 1) + throw SerializationError("unsupported NodeBox version"); + + reset(); + + type = (enum NodeBoxType)readU8(is); + + if(type == NODEBOX_FIXED) + { + 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); + } +} + +/* + TileDef +*/ - inventory_texture_name = imgname; - inventory_texture = tsrc->getTextureRaw(imgname); +void TileDef::serialize(std::ostream &os) const +{ + writeU8(os, 0); // version + os<getTextureRaw(imgname_full); } + +void ContentFeatures::reset() +{ + /* + Cached stuff + */ +#ifndef SERVER + solidness = 2; + visual_solidness = 0; + backface_culling = true; #endif + has_on_construct = false; + has_on_destruct = false; + has_after_destruct = false; + /* + Actual data + + NOTE: Most of this is always overridden by the default values given + in builtin.lua + */ + name = ""; + groups.clear(); + // Unknown nodes can be dug + groups["dig_immediate"] = 2; + drawtype = NDT_NORMAL; + visual_scale = 1.0; + for(u32 i=0; i<6; i++) + tiledef[i] = TileDef(); + for(u16 j=0; jfirst); + 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); + writeU8(os, CF_SPECIAL_COUNT); + for(u32 i=0; ireset(); - - for(u16 j=0; j<6; j++) - f->tiles[j].material_type = initial_material_type; + ContentFeatures &f = m_content_features[i]; + f.reset(); // Reset to defaults } -#endif - /* - Initially set every block to be shown as an unknown block. - Don't touch CONTENT_IGNORE or CONTENT_AIR. - */ - for(u16 i=0; i<=MAX_CONTENT; i++) + + // Set CONTENT_AIR { - if(i == CONTENT_IGNORE || i == CONTENT_AIR) - continue; - ContentFeatures *f = &m_content_features[i]; - f->setAllTextures(tsrc, "unknown_block.png"); - f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1"; + 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; + // Insert directly into containers + content_t c = CONTENT_AIR; + m_content_features[c] = f; + addNameIdMapping(c, f.name); } - // Make CONTENT_IGNORE to not block the view when occlusion culling - m_content_features[CONTENT_IGNORE].solidness = 0; + // 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; + // A way to remove accidental CONTENT_IGNOREs + f.buildable_to = true; + // Insert directly into containers + content_t c = CONTENT_IGNORE; + m_content_features[c] = f; + addNameIdMapping(c, f.name); + } + } + // CONTENT_IGNORE = not found + content_t getFreeId() + { + for(u32 i=0; i<=0xffff; i++){ + const ContentFeatures &f = m_content_features[i]; + if(f.name == "") + return i; + } + return CONTENT_IGNORE; + } + CNodeDefManager() + { + clear(); } virtual ~CNodeDefManager() { } virtual IWritableNodeDefManager* clone() { - CNodeDefManager *mgr = new CNodeDefManager(NULL); + CNodeDefManager *mgr = new CNodeDefManager(); for(u16 i=0; i<=MAX_CONTENT; i++) { mgr->set(i, get(i)); @@ -154,48 +411,351 @@ class CNodeDefManager: public IWritableNodeDefManager { return get(n.getContent()); } - // Writable + virtual bool 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; + } + virtual content_t getId(const std::string &name) const + { + content_t id = CONTENT_IGNORE; + getId(name, id); + return id; + } + virtual void getIds(const std::string &name, std::set &result) + const + { + 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); + for(u16 id=0; id<=MAX_CONTENT; id++) + { + const ContentFeatures &f = m_content_features[id]; + if(f.name == "") // Quickly discard undefined nodes + continue; + if(itemgroup_get(f.groups, group) != 0) + result.insert(id); + } + } + virtual const ContentFeatures& get(const std::string &name) const + { + content_t id = CONTENT_IGNORE; + getId(name, id); + return get(id); + } + // IWritableNodeDefManager virtual void set(content_t c, const ContentFeatures &def) { - infostream<<"registerNode: registering content \""< 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) { #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 opaque_water = g_settings->getBool("opaque_water"); + for(u16 i=0; i<=MAX_CONTENT; i++) { ContentFeatures *f = &m_content_features[i]; - for(u16 j=0; j<6; j++) - tsrc->updateAP(f->tiles[j].texture); - if(f->special_atlas){ - tsrc->updateAP(*(f->special_atlas)); - if(f->special_material) - f->special_material->setTexture(0, f->special_atlas->atlas); - if(f->special_material2) - f->special_material2->setTexture(0, f->special_atlas->atlas); + + // 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_block.png"; + } + + 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; + } + break; + case NDT_FLOWINGLIQUID: + assert(f->liquid_type == LIQUID_FLOWING); + f->solidness = 0; + if(opaque_water) + f->alpha = 255; + break; + case NDT_GLASSLIKE: + f->solidness = 0; + f->visual_solidness = 1; + 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"); + } + } + break; + case NDT_TORCHLIKE: + case NDT_SIGNLIKE: + case NDT_PLANTLIKE: + case NDT_FENCELIKE: + case NDT_RAILLIKE: + case NDT_NODEBOX: + f->solidness = 0; + break; + } + + // Tiles (fill in f->tiles[]) + for(u16 j=0; j<6; j++){ + // Texture + f->tiles[j].texture = tsrc->getTexture(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 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 + if(f->tiles[j].material_flags & + MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES) + { + // Get raw texture size to determine frame count by + // aspect ratio + video::ITexture *t = tsrc->getTextureRaw(tiledef[j].name); + v2u32 size = t->getOriginalSize(); + int frame_height = (float)size.X / + (float)tiledef[j].animation.aspect_w * + (float)tiledef[j].animation.aspect_h; + int 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 there are no frames for an animation, switch + // animation off (so that having specified an animation + // for something but not using it in the texture pack + // gives no overhead) + if(frame_count == 1){ + f->tiles[j].material_flags &= + ~MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES; + } + } } - if(f->inventory_texture_name != ""){ - f->inventory_texture = - tsrc->getTextureRaw(f->inventory_texture_name); + // Special tiles (fill in f->special_tiles[]) + for(u16 j=0; jspecial_tiles[j].texture = + tsrc->getTexture(f->tiledef_special[j].name); + // Alpha + f->special_tiles[j].alpha = f->alpha; + if(f->alpha == 255) + f->special_tiles[j].material_type = MATERIAL_ALPHA_SIMPLE; + else + f->special_tiles[j].material_type = MATERIAL_ALPHA_VERTEX; + // 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 + if(f->special_tiles[j].material_flags & + MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES) + { + // Get raw texture size to determine frame count by + // aspect ratio + video::ITexture *t = tsrc->getTextureRaw(f->tiledef_special[j].name); + v2u32 size = t->getOriginalSize(); + int frame_height = (float)size.X / + (float)f->tiledef_special[j].animation.aspect_w * + (float)f->tiledef_special[j].animation.aspect_h; + int 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 there are no frames for an animation, switch + // animation off (so that having specified an animation + // for something but not using it in the texture pack + // gives no overhead) + if(frame_count == 1){ + f->special_tiles[j].material_flags &= + ~MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES; + } + } } } #endif } + void serialize(std::ostream &os) + { + writeU8(os, 1); // version + u16 count = 0; + std::ostringstream os2(std::ios::binary); + for(u16 i=0; i<=MAX_CONTENT; i++) + { + if(i == CONTENT_IGNORE || i == CONTENT_AIR) + 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); + os2< MAX_CONTENT){ + errorstream<<"ContentFeatures::deSerialize(): " + <<"Too large content id: "<deSerialize(wrapper_is); + verbosestream<<"deserialized "<name<name != "") + addNameIdMapping(i, f->name); + } + } +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)); + } private: + // Features indexed by id ContentFeatures m_content_features[MAX_CONTENT+1]; + // 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; }; -IWritableNodeDefManager* createNodeDefManager(ITextureSource *tsrc) +IWritableNodeDefManager* createNodeDefManager() { - return new CNodeDefManager(tsrc); + return new CNodeDefManager(); }