diff options
Diffstat (limited to 'src/nodedef.cpp')
-rw-r--r-- | src/nodedef.cpp | 240 |
1 files changed, 191 insertions, 49 deletions
diff --git a/src/nodedef.cpp b/src/nodedef.cpp index 269c2b9d6..3a2cb00b1 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -33,6 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "exceptions.h" #include "debug.h" #include "gamedef.h" +#include "mapnode.h" #include <fstream> // Used in applyTextureOverrides() /* @@ -48,44 +49,91 @@ void NodeBox::reset() 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); + // no default for other parts + connect_top.clear(); + connect_bottom.clear(); + connect_front.clear(); + connect_left.clear(); + connect_back.clear(); + connect_right.clear(); } void NodeBox::serialize(std::ostream &os, u16 protocol_version) const { - int version = protocol_version >= 21 ? 2 : 1; + int version = 1; + if (protocol_version >= 27) + version = 3; + else if (protocol_version >= 21) + version = 2; writeU8(os, version); - if (version == 1 && type == NODEBOX_LEVELED) - writeU8(os, NODEBOX_FIXED); - else - writeU8(os, type); + switch (type) { + case NODEBOX_LEVELED: + case NODEBOX_FIXED: + if (version == 1) + writeU8(os, NODEBOX_FIXED); + else + writeU8(os, type); - if(type == NODEBOX_FIXED || type == NODEBOX_LEVELED) - { writeU16(os, fixed.size()); - for(std::vector<aabb3f>::const_iterator + for (std::vector<aabb3f>::const_iterator i = fixed.begin(); - i != fixed.end(); i++) + i != fixed.end(); ++i) { writeV3F1000(os, i->MinEdge); writeV3F1000(os, i->MaxEdge); } - } - else if(type == NODEBOX_WALLMOUNTED) - { + break; + case NODEBOX_WALLMOUNTED: + writeU8(os, type); + 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); + break; + case NODEBOX_CONNECTED: + if (version <= 2) { + // send old clients nodes that can't be walked through + // to prevent abuse + writeU8(os, NODEBOX_FIXED); + + writeU16(os, 1); + writeV3F1000(os, v3f(-BS/2, -BS/2, -BS/2)); + writeV3F1000(os, v3f(BS/2, BS/2, BS/2)); + } else { + writeU8(os, type); + +#define WRITEBOX(box) do { \ + writeU16(os, (box).size()); \ + for (std::vector<aabb3f>::const_iterator \ + i = (box).begin(); \ + i != (box).end(); ++i) { \ + writeV3F1000(os, i->MinEdge); \ + writeV3F1000(os, i->MaxEdge); \ + }; } while (0) + + WRITEBOX(fixed); + WRITEBOX(connect_top); + WRITEBOX(connect_bottom); + WRITEBOX(connect_front); + WRITEBOX(connect_left); + WRITEBOX(connect_back); + WRITEBOX(connect_right); + } + break; + default: + writeU8(os, type); + break; } } void NodeBox::deSerialize(std::istream &is) { int version = readU8(is); - if(version < 1 || version > 2) + if (version < 1 || version > 3) throw SerializationError("unsupported NodeBox version"); reset(); @@ -112,6 +160,26 @@ void NodeBox::deSerialize(std::istream &is) wall_side.MinEdge = readV3F1000(is); wall_side.MaxEdge = readV3F1000(is); } + else if (type == NODEBOX_CONNECTED) + { +#define READBOXES(box) do { \ + count = readU16(is); \ + (box).reserve(count); \ + while (count--) { \ + v3f min = readV3F1000(is); \ + v3f max = readV3F1000(is); \ + (box).push_back(aabb3f(min, max)); }; } while (0) + + u16 count; + + READBOXES(fixed); + READBOXES(connect_top); + READBOXES(connect_bottom); + READBOXES(connect_front); + READBOXES(connect_left); + READBOXES(connect_back); + READBOXES(connect_right); + } } /* @@ -139,7 +207,7 @@ void TileDef::serialize(std::ostream &os, u16 protocol_version) const } } -void TileDef::deSerialize(std::istream &is) +void TileDef::deSerialize(std::istream &is, const u8 contenfeatures_version, const NodeDrawType drawtype) { int version = readU8(is); name = deSerializeString(is); @@ -153,6 +221,13 @@ void TileDef::deSerialize(std::istream &is) tileable_horizontal = readU8(is); tileable_vertical = readU8(is); } + + if ((contenfeatures_version < 8) && + ((drawtype == NDT_MESH) || + (drawtype == NDT_FIRELIKE) || + (drawtype == NDT_LIQUID) || + (drawtype == NDT_PLANTLIKE))) + backface_culling = false; } @@ -233,6 +308,7 @@ void ContentFeatures::reset() diggable = true; climbable = false; buildable_to = false; + floodable = false; rightclickable = true; leveled = 0; liquid_type = LIQUID_NONE; @@ -253,6 +329,9 @@ void ContentFeatures::reset() sound_footstep = SimpleSoundSpec(); sound_dig = SimpleSoundSpec("__group"); sound_dug = SimpleSoundSpec(); + connects_to.clear(); + connects_to_ids.clear(); + connect_sides = 0; } void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const @@ -262,11 +341,12 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const return; } - writeU8(os, 7); // version + writeU8(os, protocol_version < 27 ? 7 : 8); + os<<serializeString(name); writeU16(os, groups.size()); for(ItemGroupList::const_iterator - i = groups.begin(); i != groups.end(); i++){ + i = groups.begin(); i != groups.end(); ++i){ os<<serializeString(i->first); writeS16(os, i->second); } @@ -318,14 +398,22 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const // the protocol version os<<serializeString(mesh); collision_box.serialize(os, protocol_version); + writeU8(os, floodable); + writeU16(os, connects_to_ids.size()); + for (std::set<content_t>::const_iterator i = connects_to_ids.begin(); + i != connects_to_ids.end(); ++i) + writeU16(os, *i); + writeU8(os, connect_sides); } void ContentFeatures::deSerialize(std::istream &is) { int version = readU8(is); - if(version != 7){ + if (version < 7) { deSerializeOld(is, version); return; + } else if (version > 8) { + throw SerializationError("unsupported ContentFeatures version"); } name = deSerializeString(is); @@ -337,15 +425,16 @@ void ContentFeatures::deSerialize(std::istream &is) groups[name] = value; } drawtype = (enum NodeDrawType)readU8(is); + visual_scale = readF1000(is); if(readU8(is) != 6) throw SerializationError("unsupported tile count"); for(u32 i = 0; i < 6; i++) - tiledef[i].deSerialize(is); + tiledef[i].deSerialize(is, version, drawtype); if(readU8(is) != CF_SPECIAL_COUNT) throw SerializationError("unsupported CF_SPECIAL_COUNT"); for(u32 i = 0; i < CF_SPECIAL_COUNT; i++) - tiledef_special[i].deSerialize(is); + tiledef_special[i].deSerialize(is, version, drawtype); alpha = readU8(is); post_effect_color.setAlpha(readU8(is)); post_effect_color.setRed(readU8(is)); @@ -388,6 +477,12 @@ void ContentFeatures::deSerialize(std::istream &is) // otherwise changes the protocol version mesh = deSerializeString(is); collision_box.deSerialize(is); + floodable = readU8(is); + u16 connects_to_size = readU16(is); + connects_to_ids.clear(); + for (u16 i = 0; i < connects_to_size; i++) + connects_to_ids.insert(readU16(is)); + connect_sides = readU8(is); }catch(SerializationError &e) {}; } @@ -405,7 +500,7 @@ public: inline 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<content_t> &result) const; + virtual bool getIds(const std::string &name, std::set<content_t> &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); @@ -425,6 +520,8 @@ public: virtual bool cancelNodeResolveCallback(NodeResolver *nr); virtual void runNodeResolveCallbacks(); virtual void resetNodeResolveState(); + virtual void mapNodeboxConnections(); + virtual bool nodeboxConnects(MapNode from, MapNode to, u8 connect_face); private: void addNameIdMapping(content_t i, std::string name); @@ -520,6 +617,7 @@ void CNodeDefManager::clear() f.pointable = false; f.diggable = false; f.buildable_to = true; + f.floodable = true; f.is_ground_content = true; // Insert directly into containers content_t c = CONTENT_AIR; @@ -588,22 +686,23 @@ content_t CNodeDefManager::getId(const std::string &name) const } -void CNodeDefManager::getIds(const std::string &name, +bool CNodeDefManager::getIds(const std::string &name, std::set<content_t> &result) const { //TimeTaker t("getIds", NULL, PRECISION_MICRO); if (name.substr(0,6) != "group:") { content_t id = CONTENT_IGNORE; - if(getId(name, id)) + bool exists = getId(name, id); + if (exists) result.insert(id); - return; + return exists; } std::string group = name.substr(6); std::map<std::string, GroupItems>::const_iterator i = m_group_to_items.find(group); if (i == m_group_to_items.end()) - return; + return true; const GroupItems &items = i->second; for (GroupItems::const_iterator j = items.begin(); @@ -612,6 +711,7 @@ void CNodeDefManager::getIds(const std::string &name, result.insert((*j).first); } //printf("getIds: %dus\n", t.stop()); + return true; } @@ -653,7 +753,7 @@ content_t CNodeDefManager::set(const std::string &name, const ContentFeatures &d // Don't allow redefining ignore (but allow air and unknown) if (name == "ignore") { - infostream << "NodeDefManager: WARNING: Ignoring " + warningstream << "NodeDefManager: Ignoring " "CONTENT_IGNORE redefinition"<<std::endl; return CONTENT_IGNORE; } @@ -663,7 +763,7 @@ content_t CNodeDefManager::set(const std::string &name, const ContentFeatures &d // Get new id id = allocateId(); if (id == CONTENT_IGNORE) { - infostream << "NodeDefManager: WARNING: Absolute " + warningstream << "NodeDefManager: Absolute " "limit reached" << std::endl; return CONTENT_IGNORE; } @@ -709,7 +809,7 @@ void CNodeDefManager::updateAliases(IItemDefManager *idef) std::set<std::string> all = idef->getAll(); m_name_id_mapping_with_aliases.clear(); for (std::set<std::string>::iterator - i = all.begin(); i != all.end(); i++) { + i = all.begin(); i != all.end(); ++i) { std::string name = *i; std::string convert_to = idef->getAlias(name); content_t id; @@ -791,7 +891,6 @@ void CNodeDefManager::updateTextures(IGameDef *gamedef, scene::ISceneManager* smgr = gamedef->getSceneManager(); scene::IMeshManipulator* meshmanip = smgr->getMeshManipulator(); - bool new_style_water = g_settings->getBool("new_style_water"); bool connected_glass = g_settings->getBool("connected_glass"); bool opaque_water = g_settings->getBool("opaque_water"); bool enable_shaders = g_settings->getBool("enable_shaders"); @@ -839,12 +938,7 @@ void CNodeDefManager::updateTextures(IGameDef *gamedef, 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; - } + f->solidness = 1; is_liquid = true; break; case NDT_FLOWINGLIQUID: @@ -895,17 +989,14 @@ void CNodeDefManager::updateTextures(IGameDef *gamedef, 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; f->solidness = 0; break; case NDT_MESH: f->solidness = 0; - f->backface_culling = false; break; case NDT_TORCHLIKE: case NDT_SIGNLIKE: @@ -937,7 +1028,7 @@ void CNodeDefManager::updateTextures(IGameDef *gamedef, // 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->backface_culling, f->alpha, material_type); + use_normal_texture, f->tiledef[j].backface_culling, f->alpha, material_type); } // Special tiles (fill in f->special_tiles[]) @@ -964,7 +1055,7 @@ void CNodeDefManager::updateTextures(IGameDef *gamedef, //Convert regular nodebox nodes to meshnodes //Change the drawtype and apply scale f->drawtype = NDT_MESH; - f->mesh_ptr[0] = convertNodeboxNodeToMesh(f); + f->mesh_ptr[0] = convertNodeboxesToMesh(f->node_box.fixed); v3f scale = v3f(1.0, 1.0, 1.0) * f->visual_scale; scaleMesh(f->mesh_ptr[0], scale); recalculateBoundingBox(f->mesh_ptr[0]); @@ -1112,12 +1203,12 @@ void CNodeDefManager::deSerialize(std::istream &is) // Check error conditions if (i == CONTENT_IGNORE || i == CONTENT_AIR || i == CONTENT_UNKNOWN) { - infostream << "NodeDefManager::deSerialize(): WARNING: " + warningstream << "NodeDefManager::deSerialize(): " "not changing builtin node " << i << std::endl; continue; } if (f.name == "") { - infostream << "NodeDefManager::deSerialize(): WARNING: " + warningstream << "NodeDefManager::deSerialize(): " "received empty name" << std::endl; continue; } @@ -1125,7 +1216,7 @@ void CNodeDefManager::deSerialize(std::istream &is) // Ignore aliases u16 existing_id; if (m_name_id_mapping.getId(f.name, existing_id) && i != existing_id) { - infostream << "NodeDefManager::deSerialize(): WARNING: " + warningstream << "NodeDefManager::deSerialize(): " "already defined with different ID: " << f.name << std::endl; continue; } @@ -1162,7 +1253,7 @@ void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const os<<serializeString(name); writeU16(os, groups.size()); for (ItemGroupList::const_iterator - i = groups.begin(); i != groups.end(); i++) { + i = groups.begin(); i != groups.end(); ++i) { os<<serializeString(i->first); writeS16(os, i->second); } @@ -1210,7 +1301,7 @@ void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const os<<serializeString(name); writeU16(os, groups.size()); for (ItemGroupList::const_iterator - i = groups.begin(); i != groups.end(); i++) { + i = groups.begin(); i != groups.end(); ++i) { os<<serializeString(i->first); writeS16(os, i->second); } @@ -1262,7 +1353,6 @@ void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const "Unsupported version requested"); } - void ContentFeatures::deSerializeOld(std::istream &is, int version) { if (version == 5) // In PROTOCOL_VERSION 13 @@ -1276,15 +1366,16 @@ void ContentFeatures::deSerializeOld(std::istream &is, int version) groups[name] = value; } drawtype = (enum NodeDrawType)readU8(is); + visual_scale = readF1000(is); if (readU8(is) != 6) throw SerializationError("unsupported tile count"); for (u32 i = 0; i < 6; i++) - tiledef[i].deSerialize(is); + tiledef[i].deSerialize(is, version, drawtype); if (readU8(is) != CF_SPECIAL_COUNT) throw SerializationError("unsupported CF_SPECIAL_COUNT"); for (u32 i = 0; i < CF_SPECIAL_COUNT; i++) - tiledef_special[i].deSerialize(is); + tiledef_special[i].deSerialize(is, version, drawtype); alpha = readU8(is); post_effect_color.setAlpha(readU8(is)); post_effect_color.setRed(readU8(is)); @@ -1328,12 +1419,12 @@ void ContentFeatures::deSerializeOld(std::istream &is, int version) if (readU8(is) != 6) throw SerializationError("unsupported tile count"); for (u32 i = 0; i < 6; i++) - tiledef[i].deSerialize(is); + tiledef[i].deSerialize(is, version, drawtype); // CF_SPECIAL_COUNT in version 6 = 2 if (readU8(is) != 2) throw SerializationError("unsupported CF_SPECIAL_COUNT"); for (u32 i = 0; i < 2; i++) - tiledef_special[i].deSerialize(is); + tiledef_special[i].deSerialize(is, version, drawtype); alpha = readU8(is); post_effect_color.setAlpha(readU8(is)); post_effect_color.setRed(readU8(is)); @@ -1430,6 +1521,57 @@ void CNodeDefManager::resetNodeResolveState() m_pending_resolve_callbacks.clear(); } +void CNodeDefManager::mapNodeboxConnections() +{ + for (u32 i = 0; i < m_content_features.size(); i++) { + ContentFeatures *f = &m_content_features[i]; + if ((f->drawtype != NDT_NODEBOX) || (f->node_box.type != NODEBOX_CONNECTED)) + continue; + for (std::vector<std::string>::iterator it = f->connects_to.begin(); + it != f->connects_to.end(); ++it) { + getIds(*it, f->connects_to_ids); + } + } +} + +bool CNodeDefManager::nodeboxConnects(MapNode from, MapNode to, u8 connect_face) +{ + const ContentFeatures &f1 = get(from); + + if ((f1.drawtype != NDT_NODEBOX) || (f1.node_box.type != NODEBOX_CONNECTED)) + return false; + + // lookup target in connected set + if (f1.connects_to_ids.find(to.param0) == f1.connects_to_ids.end()) + return false; + + const ContentFeatures &f2 = get(to); + + if ((f2.drawtype == NDT_NODEBOX) && (f2.node_box.type == NODEBOX_CONNECTED)) + // ignores actually looking if back connection exists + return (f2.connects_to_ids.find(from.param0) != f2.connects_to_ids.end()); + + // does to node declare usable faces? + if (f2.connect_sides > 0) { + if ((f2.param_type_2 == CPT2_FACEDIR) && (connect_face >= 4)) { + static const u8 rot[33 * 4] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 32, 16, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 - back + 8, 4, 32, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 - right + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16, 8, 4, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - front + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 32, 16, 8, 4 // 32 - left + }; + return (f2.connect_sides & rot[(connect_face * 4) + to.param2]); + } + return (f2.connect_sides & connect_face); + } + // the target is just a regular node, so connect no matter back connection + return true; +} //// //// NodeResolver |