]> git.lizzy.rs Git - minetest.git/blobdiff - src/mapblock.cpp
Translated using Weblate (Malay)
[minetest.git] / src / mapblock.cpp
index 0ca71e643d83f11a8413636eabeeff6d90102916..2bbc0ebbf9f76d9ab0750afb7d24f2caf5920a1b 100644 (file)
@@ -218,61 +218,39 @@ void MapBlock::expireDayNightDiff()
        m_day_night_differs_expired = true;
 }
 
-s16 MapBlock::getGroundLevel(v2s16 p2d)
-{
-       if(isDummy())
-               return -3;
-       try
-       {
-               s16 y = MAP_BLOCKSIZE-1;
-               for(; y>=0; y--)
-               {
-                       MapNode n = getNodeRef(p2d.X, y, p2d.Y);
-                       if (m_gamedef->ndef()->get(n).walkable) {
-                               if(y == MAP_BLOCKSIZE-1)
-                                       return -2;
-
-                               return y;
-                       }
-               }
-               return -1;
-       }
-       catch(InvalidPositionException &e)
-       {
-               return -3;
-       }
-}
-
 /*
        Serialization
 */
+
 // List relevant id-name pairs for ids in the block using nodedef
-// Renumbers the content IDs (starting at 0 and incrementing
-// use static memory requires about 65535 * sizeof(int) ram in order to be
-// sure we can handle all content ids. But it's absolutely worth it as it's
-// a speedup of 4 for one of the major time consuming functions on storing
-// mapblocks.
-static content_t getBlockNodeIdMapping_mapping[USHRT_MAX + 1];
+// Renumbers the content IDs (starting at 0 and incrementing)
 static void getBlockNodeIdMapping(NameIdMapping *nimap, MapNode *nodes,
        const NodeDefManager *nodedef)
 {
-       memset(getBlockNodeIdMapping_mapping, 0xFF, (USHRT_MAX + 1) * sizeof(content_t));
-
-       std::set<content_t> unknown_contents;
+       // The static memory requires about 65535 * sizeof(int) RAM in order to be
+       // sure we can handle all content ids. But it's absolutely worth it as it's
+       // a speedup of 4 for one of the major time consuming functions on storing
+       // mapblocks.
+       thread_local std::unique_ptr<content_t[]> mapping;
+       static_assert(sizeof(content_t) == 2, "content_t must be 16-bit");
+       if (!mapping)
+               mapping = std::make_unique<content_t[]>(USHRT_MAX + 1);
+
+       memset(mapping.get(), 0xFF, (USHRT_MAX + 1) * sizeof(content_t));
+
+       std::unordered_set<content_t> unknown_contents;
        content_t id_counter = 0;
        for (u32 i = 0; i < MapBlock::nodecount; i++) {
                content_t global_id = nodes[i].getContent();
                content_t id = CONTENT_IGNORE;
 
                // Try to find an existing mapping
-               if (getBlockNodeIdMapping_mapping[global_id] != 0xFFFF) {
-                       id = getBlockNodeIdMapping_mapping[global_id];
-               }
-               else
-               {
+               if (mapping[global_id] != 0xFFFF) {
+                       id = mapping[global_id];
+               } else {
                        // We have to assign a new mapping
                        id = id_counter++;
-                       getBlockNodeIdMapping_mapping[global_id] = id;
+                       mapping[global_id] = id;
 
                        const ContentFeatures &f = nodedef->get(global_id);
                        const std::string &name = f.name;
@@ -290,6 +268,7 @@ static void getBlockNodeIdMapping(NameIdMapping *nimap, MapNode *nodes,
                                << "Name for node id " << unknown_content << " not known" << std::endl;
        }
 }
+
 // Correct ids in the block to match nodedef based on names.
 // Unknown ones are added to nodedef.
 // Will not update itself to match id-name pairs in nodedef.
@@ -355,7 +334,7 @@ static void correctBlockNodeIds(const NameIdMapping *nimap, MapNode *nodes,
        }
 }
 
-void MapBlock::serialize(std::ostream &os, u8 version, bool disk, int compression_level)
+void MapBlock::serialize(std::ostream &os_compressed, u8 version, bool disk, int compression_level)
 {
        if(!ser_ver_supported(version))
                throw VersionMismatchException("ERROR: MapBlock format not supported");
@@ -365,6 +344,9 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk, int compressio
 
        FATAL_ERROR_IF(version < SER_FMT_VER_LOWEST_WRITE, "Serialisation version error");
 
+       std::ostringstream os_raw(std::ios_base::binary);
+       std::ostream &os = version >= 29 ? os_raw : os_compressed;
+
        // First byte
        u8 flags = 0;
        if(is_underground)
@@ -382,37 +364,52 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk, int compressio
                Bulk node data
        */
        NameIdMapping nimap;
-       if(disk)
+       SharedBuffer<u8> buf;
+       const u8 content_width = 2;
+       const u8 params_width = 2;
+       if(disk)
        {
                MapNode *tmp_nodes = new MapNode[nodecount];
-               for(u32 i=0; i<nodecount; i++)
-                       tmp_nodes[i] = data[i];
+               memcpy(tmp_nodes, data, nodecount * sizeof(MapNode));
                getBlockNodeIdMapping(&nimap, tmp_nodes, m_gamedef->ndef());
 
-               u8 content_width = 2;
-               u8 params_width = 2;
-               writeU8(os, content_width);
-               writeU8(os, params_width);
-               MapNode::serializeBulk(os, version, tmp_nodes, nodecount,
-                               content_width, params_width, compression_level);
+               buf = MapNode::serializeBulk(version, tmp_nodes, nodecount,
+                               content_width, params_width);
                delete[] tmp_nodes;
+
+               // write timestamp and node/id mapping first
+               if (version >= 29) {
+                       writeU32(os, getTimestamp());
+
+                       nimap.serialize(os);
+               }
        }
        else
        {
-               u8 content_width = 2;
-               u8 params_width = 2;
-               writeU8(os, content_width);
-               writeU8(os, params_width);
-               MapNode::serializeBulk(os, version, data, nodecount,
-                               content_width, params_width, compression_level);
+               buf = MapNode::serializeBulk(version, data, nodecount,
+                               content_width, params_width);
+       }
+
+       writeU8(os, content_width);
+       writeU8(os, params_width);
+       if (version >= 29) {
+               os.write(reinterpret_cast<char*>(*buf), buf.getSize());
+       } else {
+               // prior to 29 node data was compressed individually
+               compress(buf, os, version, compression_level);
        }
 
        /*
                Node metadata
        */
-       std::ostringstream oss(std::ios_base::binary);
-       m_node_metadata.serialize(oss, version, disk);
-       compressZlib(oss.str(), os, compression_level);
+       if (version >= 29) {
+               m_node_metadata.serialize(os, version, disk);
+       } else {
+               // use os_raw from above to avoid allocating another stream object
+               m_node_metadata.serialize(os_raw, version, disk);
+               // prior to 29 node data was compressed individually
+               compress(os_raw.str(), os, version, compression_level);
+       }
 
        /*
                Data that goes to disk, but not the network
@@ -427,17 +424,24 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk, int compressio
                // Static objects
                m_static_objects.serialize(os);
 
-               // Timestamp
-               writeU32(os, getTimestamp());
+               if(version < 29){
+                       // Timestamp
+                       writeU32(os, getTimestamp());
 
-               // Write block-specific node definition id mapping
-               nimap.serialize(os);
+                       // Write block-specific node definition id mapping
+                       nimap.serialize(os);
+               }
 
                if(version >= 25){
                        // Node timers
                        m_node_timers.serialize(os, version);
                }
        }
+
+       if (version >= 29) {
+               // now compress the whole thing
+               compress(os_raw.str(), os_compressed, version, compression_level);
+       }
 }
 
 void MapBlock::serializeNetworkSpecific(std::ostream &os)
@@ -449,7 +453,7 @@ void MapBlock::serializeNetworkSpecific(std::ostream &os)
        writeU8(os, 2); // version
 }
 
-void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
+void MapBlock::deSerialize(std::istream &in_compressed, u8 version, bool disk)
 {
        if(!ser_ver_supported(version))
                throw VersionMismatchException("ERROR: MapBlock format not supported");
@@ -460,10 +464,16 @@ void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
 
        if(version <= 21)
        {
-               deSerialize_pre22(is, version, disk);
+               deSerialize_pre22(in_compressed, version, disk);
                return;
        }
 
+       // Decompress the whole block (version >= 29)
+       std::stringstream in_raw(std::ios_base::binary | std::ios_base::in | std::ios_base::out);
+       if (version >= 29)
+               decompress(in_compressed, in_raw, version);
+       std::istream &is = version >= 29 ? in_raw : in_compressed;
+
        u8 flags = readU8(is);
        is_underground = (flags & 0x01) != 0;
        m_day_night_differs = (flags & 0x02) != 0;
@@ -473,9 +483,20 @@ void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
                m_lighting_complete = readU16(is);
        m_generated = (flags & 0x08) == 0;
 
-       /*
-               Bulk node data
-       */
+       NameIdMapping nimap;
+       if (disk && version >= 29) {
+               // Timestamp
+               TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
+                               <<": Timestamp"<<std::endl);
+               setTimestampNoChangedFlag(readU32(is));
+               m_disk_timestamp = m_timestamp;
+
+               // Node/id mapping
+               TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
+                               <<": NameIdMapping"<<std::endl);
+               nimap.deSerialize(is);
+       }
+
        TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
                        <<": Bulk node data"<<std::endl);
        u8 content_width = readU8(is);
@@ -484,29 +505,44 @@ void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
                throw SerializationError("MapBlock::deSerialize(): invalid content_width");
        if(params_width != 2)
                throw SerializationError("MapBlock::deSerialize(): invalid params_width");
-       MapNode::deSerializeBulk(is, version, data, nodecount,
+
+       /*
+               Bulk node data
+       */
+       if (version >= 29) {
+               MapNode::deSerializeBulk(is, version, data, nodecount,
+                       content_width, params_width);
+       } else {
+               // use in_raw from above to avoid allocating another stream object
+               decompress(is, in_raw, version);
+               MapNode::deSerializeBulk(in_raw, version, data, nodecount,
                        content_width, params_width);
+       }
 
        /*
                NodeMetadata
        */
        TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
                        <<": Node metadata"<<std::endl);
-       // Ignore errors
-       try {
-               std::ostringstream oss(std::ios_base::binary);
-               decompressZlib(is, oss);
-               std::istringstream iss(oss.str(), std::ios_base::binary);
-               if (version >= 23)
-                       m_node_metadata.deSerialize(iss, m_gamedef->idef());
-               else
-                       content_nodemeta_deserialize_legacy(iss,
-                               &m_node_metadata, &m_node_timers,
-                               m_gamedef->idef());
-       } catch(SerializationError &e) {
-               warningstream<<"MapBlock::deSerialize(): Ignoring an error"
-                               <<" while deserializing node metadata at ("
-                               <<PP(getPos())<<": "<<e.what()<<std::endl;
+       if (version >= 29) {
+               m_node_metadata.deSerialize(is, m_gamedef->idef());
+       } else {
+               try {
+                       // reuse in_raw
+                       in_raw.str("");
+                       in_raw.clear();
+                       decompress(is, in_raw, version);
+                       if (version >= 23)
+                               m_node_metadata.deSerialize(in_raw, m_gamedef->idef());
+                       else
+                               content_nodemeta_deserialize_legacy(in_raw,
+                                       &m_node_metadata, &m_node_timers,
+                                       m_gamedef->idef());
+               } catch(SerializationError &e) {
+                       warningstream<<"MapBlock::deSerialize(): Ignoring an error"
+                                       <<" while deserializing node metadata at ("
+                                       <<PP(getPos())<<": "<<e.what()<<std::endl;
+               }
        }
 
        /*
@@ -530,17 +566,20 @@ void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
                                <<": Static objects"<<std::endl);
                m_static_objects.deSerialize(is);
 
-               // Timestamp
-               TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
-                               <<": Timestamp"<<std::endl);
-               setTimestampNoChangedFlag(readU32(is));
-               m_disk_timestamp = m_timestamp;
+               if(version < 29) {
+                       // Timestamp
+                       TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
+                                   <<": Timestamp"<<std::endl);
+                       setTimestampNoChangedFlag(readU32(is));
+                       m_disk_timestamp = m_timestamp;
+
+                       // Node/id mapping
+                       TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
+                                   <<": NameIdMapping"<<std::endl);
+                       nimap.deSerialize(is);
+               }
 
                // Dynamically re-set ids based on node names
-               TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
-                               <<": NameIdMapping"<<std::endl);
-               NameIdMapping nimap;
-               nimap.deSerialize(is);
                correctBlockNodeIds(&nimap, data, m_gamedef);
 
                if(version >= 25){