Translated using Weblate (Italian)
[oweals/minetest.git] / src / nodedef.cpp
index 83e3968c3d3c784a38fb40c534cbca4d9c5339e0..a84338752ac8aa9ab38af794a8ea06aa6418accc 100644 (file)
@@ -368,9 +368,12 @@ void ContentFeatures::reset()
        floodable = false;
        rightclickable = true;
        leveled = 0;
+       leveled_max = LEVELED_MAX;
        liquid_type = LIQUID_NONE;
        liquid_alternative_flowing = "";
+       liquid_alternative_flowing_id = CONTENT_IGNORE;
        liquid_alternative_source = "";
+       liquid_alternative_source_id = CONTENT_IGNORE;
        liquid_viscosity = 0;
        liquid_renewable = true;
        liquid_range = LIQUID_LEVEL_MAX+1;
@@ -478,6 +481,7 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const
        writeU8(os, legacy_wallmounted);
 
        os << serializeString(node_dig_prediction);
+       writeU8(os, leveled_max);
 }
 
 void ContentFeatures::correctAlpha(TileDef *tiles, int length)
@@ -586,6 +590,10 @@ void ContentFeatures::deSerialize(std::istream &is)
 
        try {
                node_dig_prediction = deSerializeString(is);
+               u8 tmp_leveled_max = readU8(is);
+               if (is.eof()) /* readU8 doesn't throw exceptions so we have to do this */
+                       throw SerializationError("");
+               leveled_max = tmp_leveled_max;
        } catch(SerializationError &e) {};
 }
 
@@ -600,8 +608,9 @@ static void fillTileAttribs(ITextureSource *tsrc, TileLayer *layer,
        layer->material_type = material_type;
 
        bool has_scale = tiledef.scale > 0;
-       if (((tsettings.autoscale_mode == AUTOSCALE_ENABLE) && !has_scale) ||
-                       (tsettings.autoscale_mode == AUTOSCALE_FORCE)) {
+       bool use_autoscale = tsettings.autoscale_mode == AUTOSCALE_FORCE ||
+               (tsettings.autoscale_mode == AUTOSCALE_ENABLE && !has_scale);
+       if (use_autoscale && layer->texture) {
                auto texture_size = layer->texture->getOriginalSize();
                float base_size = tsettings.node_texture_size;
                float size = std::fmin(texture_size.Width, texture_size.Height);
@@ -1202,6 +1211,26 @@ inline void NodeDefManager::fixSelectionBoxIntUnion()
 }
 
 
+void NodeDefManager::eraseIdFromGroups(content_t id)
+{
+       // For all groups in m_group_to_items...
+       for (auto iter_groups = m_group_to_items.begin();
+                       iter_groups != m_group_to_items.end();) {
+               // Get the group items vector.
+               std::vector<content_t> &items = iter_groups->second;
+
+               // Remove any occurence of the id in the group items vector.
+               items.erase(std::remove(items.begin(), items.end(), id), items.end());
+
+               // If group is empty, erase its vector from the map.
+               if (items.empty())
+                       iter_groups = m_group_to_items.erase(iter_groups);
+               else
+                       ++iter_groups;
+       }
+}
+
+
 // IWritableNodeDefManager
 content_t NodeDefManager::set(const std::string &name, const ContentFeatures &def)
 {
@@ -1222,19 +1251,24 @@ content_t NodeDefManager::set(const std::string &name, const ContentFeatures &de
                assert(id != CONTENT_IGNORE);
                addNameIdMapping(id, name);
        }
+
+       // If there is already ContentFeatures registered for this id, clear old groups
+       if (id < m_content_features.size())
+               eraseIdFromGroups(id);
+
        m_content_features[id] = def;
        verbosestream << "NodeDefManager: registering content id \"" << id
                << "\": name=\"" << def.name << "\""<<std::endl;
 
        getNodeBoxUnion(def.selection_box, def, &m_selection_box_union);
        fixSelectionBoxIntUnion();
+
        // 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 (const auto &group : def.groups) {
                const std::string &group_name = group.first;
                m_group_to_items[group_name].push_back(id);
        }
+
        return id;
 }
 
@@ -1260,18 +1294,7 @@ void NodeDefManager::removeNode(const std::string &name)
                m_name_id_mapping_with_aliases.erase(name);
        }
 
-       // Erase node content from all groups it belongs to
-       for (std::unordered_map<std::string, std::vector<content_t>>::iterator iter_groups =
-                       m_group_to_items.begin(); iter_groups != m_group_to_items.end();) {
-               std::vector<content_t> &items = iter_groups->second;
-               items.erase(std::remove(items.begin(), items.end(), id), items.end());
-
-               // Check if group is empty
-               if (items.empty())
-                       m_group_to_items.erase(iter_groups++);
-               else
-                       ++iter_groups;
-       }
+       eraseIdFromGroups(id);
 }
 
 
@@ -1290,57 +1313,35 @@ void NodeDefManager::updateAliases(IItemDefManager *idef)
        }
 }
 
-void NodeDefManager::applyTextureOverrides(const std::string &override_filepath)
+void NodeDefManager::applyTextureOverrides(const std::vector<TextureOverride> &overrides)
 {
        infostream << "NodeDefManager::applyTextureOverrides(): Applying "
-               "overrides to textures from " << override_filepath << std::endl;
-
-       std::ifstream infile(override_filepath.c_str());
-       std::string line;
-       int line_c = 0;
-       while (std::getline(infile, line)) {
-               line_c++;
-               if (trim(line).empty())
-                       continue;
-               std::vector<std::string> splitted = str_split(line, ' ');
-               if (splitted.size() != 3) {
-                       errorstream << override_filepath
-                               << ":" << line_c << " Could not apply texture override \""
-                               << line << "\": Syntax error" << std::endl;
-                       continue;
-               }
+               "overrides to textures" << std::endl;
 
+       for (const TextureOverride& texture_override : overrides) {
                content_t id;
-               if (!getId(splitted[0], id))
+               if (!getId(texture_override.id, id))
                        continue; // Ignore unknown node
 
                ContentFeatures &nodedef = m_content_features[id];
 
-               if (splitted[1] == "top")
-                       nodedef.tiledef[0].name = splitted[2];
-               else if (splitted[1] == "bottom")
-                       nodedef.tiledef[1].name = splitted[2];
-               else if (splitted[1] == "right")
-                       nodedef.tiledef[2].name = splitted[2];
-               else if (splitted[1] == "left")
-                       nodedef.tiledef[3].name = splitted[2];
-               else if (splitted[1] == "back")
-                       nodedef.tiledef[4].name = splitted[2];
-               else if (splitted[1] == "front")
-                       nodedef.tiledef[5].name = splitted[2];
-               else if (splitted[1] == "all" || splitted[1] == "*")
-                       for (TileDef &i : nodedef.tiledef)
-                               i.name = splitted[2];
-               else if (splitted[1] == "sides")
-                       for (int i = 2; i < 6; i++)
-                               nodedef.tiledef[i].name = splitted[2];
-               else {
-                       errorstream << override_filepath
-                               << ":" << line_c << " Could not apply texture override \""
-                               << line << "\": Unknown node side \""
-                               << splitted[1] << "\"" << std::endl;
-                       continue;
-               }
+               if (texture_override.hasTarget(OverrideTarget::TOP))
+                       nodedef.tiledef[0].name = texture_override.texture;
+
+               if (texture_override.hasTarget(OverrideTarget::BOTTOM))
+                       nodedef.tiledef[1].name = texture_override.texture;
+
+               if (texture_override.hasTarget(OverrideTarget::RIGHT))
+                       nodedef.tiledef[2].name = texture_override.texture;
+
+               if (texture_override.hasTarget(OverrideTarget::LEFT))
+                       nodedef.tiledef[3].name = texture_override.texture;
+
+               if (texture_override.hasTarget(OverrideTarget::BACK))
+                       nodedef.tiledef[4].name = texture_override.texture;
+
+               if (texture_override.hasTarget(OverrideTarget::FRONT))
+                       nodedef.tiledef[5].name = texture_override.texture;
        }
 }
 
@@ -1441,11 +1442,15 @@ void NodeDefManager::deSerialize(std::istream &is)
                        m_content_features.resize((u32)(i) + 1);
                m_content_features[i] = f;
                addNameIdMapping(i, f.name);
-               verbosestream << "deserialized " << f.name << std::endl;
+               TRACESTREAM(<< "NodeDef: deserialized " << f.name << std::endl);
 
                getNodeBoxUnion(f.selection_box, f, &m_selection_box_union);
                fixSelectionBoxIntUnion();
        }
+
+       // Since liquid_alternative_flowing_id and liquid_alternative_source_id
+       // are not sent, resolve them client-side too.
+       resolveCrossrefs();
 }
 
 
@@ -1506,15 +1511,28 @@ void NodeDefManager::resetNodeResolveState()
        m_pending_resolve_callbacks.clear();
 }
 
-void NodeDefManager::mapNodeboxConnections()
+static void removeDupes(std::vector<content_t> &list)
+{
+       std::sort(list.begin(), list.end());
+       auto new_end = std::unique(list.begin(), list.end());
+       list.erase(new_end, list.end());
+}
+
+void NodeDefManager::resolveCrossrefs()
 {
        for (ContentFeatures &f : m_content_features) {
+               if (f.liquid_type != LIQUID_NONE) {
+                       f.liquid_alternative_flowing_id = getId(f.liquid_alternative_flowing);
+                       f.liquid_alternative_source_id = getId(f.liquid_alternative_source);
+                       continue;
+               }
                if (f.drawtype != NDT_NODEBOX || f.node_box.type != NODEBOX_CONNECTED)
                        continue;
 
                for (const std::string &name : f.connects_to) {
                        getIds(name, f.connects_to_ids);
                }
+               removeDupes(f.connects_to_ids);
        }
 }
 
@@ -1580,6 +1598,18 @@ NodeResolver::~NodeResolver()
 }
 
 
+void NodeResolver::cloneTo(NodeResolver *res) const
+{
+       FATAL_ERROR_IF(!m_resolve_done, "NodeResolver can only be cloned"
+               " after resolving has completed");
+       /* We don't actually do anything significant. Since the node resolving has
+        * already completed, the class that called us will already have the
+        * resolved IDs in its data structures (which it copies on its own) */
+       res->m_ndef = m_ndef;
+       res->m_resolve_done = true;
+}
+
+
 void NodeResolver::nodeResolveInternal()
 {
        m_nodenames_idx   = 0;