]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/mapgen/mg_schematic.cpp
Merge pull request #59 from PrairieAstronomer/readme_irrlicht_change
[dragonfireclient.git] / src / mapgen / mg_schematic.cpp
index 598c044d605f7cb469b1024b86bb32b29b81b73f..b9ba70302a57b66f522e8edfabf85dbbd1c9bec6 100644 (file)
@@ -35,11 +35,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 ///////////////////////////////////////////////////////////////////////////////
 
+
 SchematicManager::SchematicManager(Server *server) :
-               ObjDefManager(server, OBJDEF_SCHEMATIC), m_server(server)
+       ObjDefManager(server, OBJDEF_SCHEMATIC),
+       m_server(server)
 {
 }
 
+
 SchematicManager *SchematicManager::clone() const
 {
        auto mgr = new SchematicManager();
@@ -48,6 +51,7 @@ SchematicManager *SchematicManager::clone() const
        return mgr;
 }
 
+
 void SchematicManager::clear()
 {
        EmergeManager *emerge = m_server->getEmergeManager();
@@ -68,14 +72,14 @@ void SchematicManager::clear()
        ObjDefManager::clear();
 }
 
+
 ///////////////////////////////////////////////////////////////////////////////
 
-Schematic::Schematic() = default;
 
 Schematic::~Schematic()
 {
-       delete[] schemdata;
-       delete[] slice_probs;
+       delete []schemdata;
+       delete []slice_probs;
 }
 
 ObjDef *Schematic::clone() const
@@ -97,18 +101,26 @@ ObjDef *Schematic::clone() const
        return def;
 }
 
+
 void Schematic::resolveNodeNames()
 {
+       c_nodes.clear();
        getIdsFromNrBacklog(&c_nodes, true, CONTENT_AIR);
 
        size_t bufsize = size.X * size.Y * size.Z;
        for (size_t i = 0; i != bufsize; i++) {
                content_t c_original = schemdata[i].getContent();
-               content_t c_new = c_nodes[c_original];
-               schemdata[i].setContent(c_new);
+               if (c_original >= c_nodes.size()) {
+                       errorstream << "Corrupt schematic. name=\"" << name
+                               << "\" at index " << i << std::endl;
+                       c_original = 0;
+               }
+               // Unfold condensed ID layout to content_t
+               schemdata[i].setContent(c_nodes[c_original]);
        }
 }
 
+
 void Schematic::blitToVManip(MMVManip *vm, v3s16 p, Rotation rot, bool force_place)
 {
        assert(schemdata && slice_probs);
@@ -124,33 +136,33 @@ void Schematic::blitToVManip(MMVManip *vm, v3s16 p, Rotation rot, bool force_pla
 
        int i_start, i_step_x, i_step_z;
        switch (rot) {
-       case ROTATE_90:
-               i_start = sx - 1;
-               i_step_x = zstride;
-               i_step_z = -xstride;
-               SWAP(s16, sx, sz);
-               break;
-       case ROTATE_180:
-               i_start = zstride * (sz - 1) + sx - 1;
-               i_step_x = -xstride;
-               i_step_z = -zstride;
-               break;
-       case ROTATE_270:
-               i_start = zstride * (sz - 1);
-               i_step_x = -zstride;
-               i_step_z = xstride;
-               SWAP(s16, sx, sz);
-               break;
-       default:
-               i_start = 0;
-               i_step_x = xstride;
-               i_step_z = zstride;
+               case ROTATE_90:
+                       i_start  = sx - 1;
+                       i_step_x = zstride;
+                       i_step_z = -xstride;
+                       SWAP(s16, sx, sz);
+                       break;
+               case ROTATE_180:
+                       i_start  = zstride * (sz - 1) + sx - 1;
+                       i_step_x = -xstride;
+                       i_step_z = -zstride;
+                       break;
+               case ROTATE_270:
+                       i_start  = zstride * (sz - 1);
+                       i_step_x = -zstride;
+                       i_step_z = xstride;
+                       SWAP(s16, sx, sz);
+                       break;
+               default:
+                       i_start  = 0;
+                       i_step_x = xstride;
+                       i_step_z = zstride;
        }
 
        s16 y_map = p.Y;
        for (s16 y = 0; y != sy; y++) {
                if ((slice_probs[y] != MTSCHEM_PROB_ALWAYS) &&
-                               (slice_probs[y] <= myrand_range(1, MTSCHEM_PROB_ALWAYS)))
+                       (slice_probs[y] <= myrand_range(1, MTSCHEM_PROB_ALWAYS)))
                        continue;
 
                for (s16 z = 0; z != sz; z++) {
@@ -163,10 +175,8 @@ void Schematic::blitToVManip(MMVManip *vm, v3s16 p, Rotation rot, bool force_pla
                                if (schemdata[i].getContent() == CONTENT_IGNORE)
                                        continue;
 
-                               u8 placement_prob =
-                                               schemdata[i].param1 & MTSCHEM_PROB_MASK;
-                               bool force_place_node =
-                                               schemdata[i].param1 & MTSCHEM_FORCE_PLACE;
+                               u8 placement_prob     = schemdata[i].param1 & MTSCHEM_PROB_MASK;
+                               bool force_place_node = schemdata[i].param1 & MTSCHEM_FORCE_PLACE;
 
                                if (placement_prob == MTSCHEM_PROB_NEVER)
                                        continue;
@@ -179,8 +189,7 @@ void Schematic::blitToVManip(MMVManip *vm, v3s16 p, Rotation rot, bool force_pla
                                }
 
                                if ((placement_prob != MTSCHEM_PROB_ALWAYS) &&
-                                               (placement_prob <=
-                                                               myrand_range(1, MTSCHEM_PROB_ALWAYS)))
+                                       (placement_prob <= myrand_range(1, MTSCHEM_PROB_ALWAYS)))
                                        continue;
 
                                vm->m_data[vi] = schemdata[i];
@@ -194,8 +203,9 @@ void Schematic::blitToVManip(MMVManip *vm, v3s16 p, Rotation rot, bool force_pla
        }
 }
 
-bool Schematic::placeOnVManip(
-               MMVManip *vm, v3s16 p, u32 flags, Rotation rot, bool force_place)
+
+bool Schematic::placeOnVManip(MMVManip *vm, v3s16 p, u32 flags,
+       Rotation rot, bool force_place)
 {
        assert(vm != NULL);
        assert(schemdata && slice_probs);
@@ -205,8 +215,8 @@ bool Schematic::placeOnVManip(
        if (rot == ROTATE_RAND)
                rot = (Rotation)myrand_range(ROTATE_0, ROTATE_270);
 
-       v3s16 s = (rot == ROTATE_90 || rot == ROTATE_270) ? v3s16(size.Z, size.Y, size.X)
-                                                         : size;
+       v3s16 s = (rot == ROTATE_90 || rot == ROTATE_270) ?
+               v3s16(size.Z, size.Y, size.X) : size;
 
        //// Adjust placement position if necessary
        if (flags & DECO_PLACE_CENTER_X)
@@ -221,8 +231,8 @@ bool Schematic::placeOnVManip(
        return vm->m_area.contains(VoxelArea(p, p + s - v3s16(1, 1, 1)));
 }
 
-void Schematic::placeOnMap(
-               ServerMap *map, v3s16 p, u32 flags, Rotation rot, bool force_place)
+void Schematic::placeOnMap(ServerMap *map, v3s16 p, u32 flags,
+       Rotation rot, bool force_place)
 {
        std::map<v3s16, MapBlock *> lighting_modified_blocks;
        std::map<v3s16, MapBlock *> modified_blocks;
@@ -236,8 +246,8 @@ void Schematic::placeOnMap(
        if (rot == ROTATE_RAND)
                rot = (Rotation)myrand_range(ROTATE_0, ROTATE_270);
 
-       v3s16 s = (rot == ROTATE_90 || rot == ROTATE_270) ? v3s16(size.Z, size.Y, size.X)
-                                                         : size;
+       v3s16 s = (rot == ROTATE_90 || rot == ROTATE_270) ?
+                       v3s16(size.Z, size.Y, size.X) : size;
 
        //// Adjust placement position if necessary
        if (flags & DECO_PLACE_CENTER_X)
@@ -270,7 +280,8 @@ void Schematic::placeOnMap(
        map->dispatchEvent(event);
 }
 
-bool Schematic::deserializeFromMts(std::istream *is, std::vector<std::string> *names)
+
+bool Schematic::deserializeFromMts(std::istream *is)
 {
        std::istream &ss = *is;
        content_t cignore = CONTENT_IGNORE;
@@ -279,20 +290,16 @@ bool Schematic::deserializeFromMts(std::istream *is, std::vector<std::string> *n
        //// Read signature
        u32 signature = readU32(ss);
        if (signature != MTSCHEM_FILE_SIGNATURE) {
-               errorstream << __FUNCTION__
-                           << ": invalid schematic "
-                              "file"
-                           << std::endl;
+               errorstream << __FUNCTION__ << ": invalid schematic "
+                       "file" << std::endl;
                return false;
        }
 
        //// Read version
        u16 version = readU16(ss);
        if (version > MTSCHEM_FILE_VER_HIGHEST_READ) {
-               errorstream << __FUNCTION__
-                           << ": unsupported schematic "
-                              "file version"
-                           << std::endl;
+               errorstream << __FUNCTION__ << ": unsupported schematic "
+                       "file version" << std::endl;
                return false;
        }
 
@@ -300,15 +307,17 @@ bool Schematic::deserializeFromMts(std::istream *is, std::vector<std::string> *n
        size = readV3S16(ss);
 
        //// Read Y-slice probability values
-       delete[] slice_probs;
+       delete []slice_probs;
        slice_probs = new u8[size.Y];
        for (int y = 0; y != size.Y; y++)
                slice_probs[y] = (version >= 3) ? readU8(ss) : MTSCHEM_PROB_ALWAYS_OLD;
 
        //// Read node names
+       NodeResolver::reset();
+
        u16 nidmapcount = readU16(ss);
        for (int i = 0; i != nidmapcount; i++) {
-               std::string name = deSerializeString(ss);
+               std::string name = deSerializeString16(ss);
 
                // Instances of "ignore" from v1 are converted to air (and instances
                // are fixed to have MTSCHEM_PROB_NEVER later on).
@@ -318,17 +327,22 @@ bool Schematic::deserializeFromMts(std::istream *is, std::vector<std::string> *n
                        have_cignore = true;
                }
 
-               names->push_back(name);
+               m_nodenames.push_back(name);
        }
 
+       // Prepare for node resolver
+       m_nnlistsizes.push_back(m_nodenames.size());
+
        //// Read node data
        size_t nodecount = size.X * size.Y * size.Z;
 
-       delete[] schemdata;
+       delete []schemdata;
        schemdata = new MapNode[nodecount];
 
-       MapNode::deSerializeBulk(
-                       ss, SER_FMT_VER_HIGHEST_READ, schemdata, nodecount, 2, 2, true);
+       std::stringstream d_ss(std::ios_base::binary | std::ios_base::in | std::ios_base::out);
+       decompress(ss, d_ss, MTSCHEM_MAPNODE_SER_FMT_VER);
+       MapNode::deSerializeBulk(d_ss, MTSCHEM_MAPNODE_SER_FMT_VER, schemdata,
+               nodecount, 2, 2);
 
        // Fix probability values for nodes that were ignore; removed in v2
        if (version < 2) {
@@ -351,31 +365,37 @@ bool Schematic::deserializeFromMts(std::istream *is, std::vector<std::string> *n
        return true;
 }
 
-bool Schematic::serializeToMts(
-               std::ostream *os, const std::vector<std::string> &names) const
+
+bool Schematic::serializeToMts(std::ostream *os) const
 {
+       // Nodes must not be resolved (-> condensed)
+       // checking here is not possible because "schemdata" might be temporary.
+
        std::ostream &ss = *os;
 
-       writeU32(ss, MTSCHEM_FILE_SIGNATURE);         // signature
+       writeU32(ss, MTSCHEM_FILE_SIGNATURE);         // signature
        writeU16(ss, MTSCHEM_FILE_VER_HIGHEST_WRITE); // version
-       writeV3S16(ss, size);                         // schematic size
+       writeV3S16(ss, size);                         // schematic size
 
-       for (int y = 0; y != size.Y; y++) // Y slice probabilities
+       for (int y = 0; y != size.Y; y++)             // Y slice probabilities
                writeU8(ss, slice_probs[y]);
 
-       writeU16(ss, names.size()); // name count
-       for (size_t i = 0; i != names.size(); i++)
-               ss << serializeString(names[i]); // node names
+       writeU16(ss, m_nodenames.size()); // name count
+       for (size_t i = 0; i != m_nodenames.size(); i++) {
+               ss << serializeString16(m_nodenames[i]); // node names
+       }
 
        // compressed bulk node data
-       MapNode::serializeBulk(ss, SER_FMT_VER_HIGHEST_WRITE, schemdata,
-                       size.X * size.Y * size.Z, 2, 2, true);
+       SharedBuffer<u8> buf = MapNode::serializeBulk(MTSCHEM_MAPNODE_SER_FMT_VER,
+               schemdata, size.X * size.Y * size.Z, 2, 2);
+       compress(buf, ss, MTSCHEM_MAPNODE_SER_FMT_VER);
 
        return true;
 }
 
-bool Schematic::serializeToLua(std::ostream *os, const std::vector<std::string> &names,
-               bool use_comments, u32 indent_spaces) const
+
+bool Schematic::serializeToLua(std::ostream *os, bool use_comments,
+       u32 indent_spaces) const
 {
        std::ostream &ss = *os;
 
@@ -383,12 +403,17 @@ bool Schematic::serializeToLua(std::ostream *os, const std::vector<std::string>
        if (indent_spaces > 0)
                indent.assign(indent_spaces, ' ');
 
+       bool resolve_done = isResolveDone();
+       FATAL_ERROR_IF(resolve_done && !m_ndef, "serializeToLua: NodeDefManager is required");
+
        //// Write header
        {
                ss << "schematic = {" << std::endl;
                ss << indent << "size = "
-                  << "{x=" << size.X << ", y=" << size.Y << ", z=" << size.Z << "},"
-                  << std::endl;
+                       << "{x=" << size.X
+                       << ", y=" << size.Y
+                       << ", z=" << size.Z
+                       << "}," << std::endl;
        }
 
        //// Write y-slice probabilities
@@ -399,8 +424,9 @@ bool Schematic::serializeToLua(std::ostream *os, const std::vector<std::string>
                        u8 probability = slice_probs[y] & MTSCHEM_PROB_MASK;
 
                        ss << indent << indent << "{"
-                          << "ypos=" << y << ", prob=" << (u16)probability * 2 << "},"
-                          << std::endl;
+                               << "ypos=" << y
+                               << ", prob=" << (u16)probability * 2
+                               << "}," << std::endl;
                }
 
                ss << indent << "}," << std::endl;
@@ -412,31 +438,42 @@ bool Schematic::serializeToLua(std::ostream *os, const std::vector<std::string>
 
                u32 i = 0;
                for (u16 z = 0; z != size.Z; z++)
-                       for (u16 y = 0; y != size.Y; y++) {
-                               if (use_comments) {
-                                       ss << std::endl
-                                          << indent << indent << "-- z=" << z
-                                          << ", y=" << y << std::endl;
-                               }
+               for (u16 y = 0; y != size.Y; y++) {
+                       if (use_comments) {
+                               ss << std::endl
+                                       << indent << indent
+                                       << "-- z=" << z
+                                       << ", y=" << y << std::endl;
+                       }
 
-                               for (u16 x = 0; x != size.X; x++, i++) {
-                                       u8 probability = schemdata[i].param1 &
-                                                        MTSCHEM_PROB_MASK;
-                                       bool force_place = schemdata[i].param1 &
-                                                          MTSCHEM_FORCE_PLACE;
+                       for (u16 x = 0; x != size.X; x++, i++) {
+                               u8 probability   = schemdata[i].param1 & MTSCHEM_PROB_MASK;
+                               bool force_place = schemdata[i].param1 & MTSCHEM_FORCE_PLACE;
 
-                                       ss << indent << indent << "{"
-                                          << "name=\""
-                                          << names[schemdata[i].getContent()]
-                                          << "\", prob=" << (u16)probability * 2
-                                          << ", param2=" << (u16)schemdata[i].param2;
+                               // After node resolving: real content_t, lookup using NodeDefManager
+                               // Prior node resolving: condensed ID, lookup using m_nodenames
+                               content_t c = schemdata[i].getContent();
 
-                                       if (force_place)
-                                               ss << ", force_place=true";
+                               ss << indent << indent << "{" << "name=\"";
 
-                                       ss << "}," << std::endl;
+                               if (!resolve_done) {
+                                       // Prior node resolving (eg. direct schematic load)
+                                       FATAL_ERROR_IF(c >= m_nodenames.size(), "Invalid node list");
+                                       ss << m_nodenames[c];
+                               } else  {
+                                       // After node resolving (eg. biome decoration)
+                                       ss << m_ndef->get(c).name;
                                }
+
+                               ss << "\", prob=" << (u16)probability * 2
+                                       << ", param2=" << (u16)schemdata[i].param2;
+
+                               if (force_place)
+                                       ss << ", force_place=true";
+
+                               ss << "}," << std::endl;
                        }
+               }
 
                ss << indent << "}," << std::endl;
        }
@@ -446,69 +483,63 @@ bool Schematic::serializeToLua(std::ostream *os, const std::vector<std::string>
        return true;
 }
 
+
 bool Schematic::loadSchematicFromFile(const std::string &filename,
-               const NodeDefManager *ndef, StringMap *replace_names)
+       const NodeDefManager *ndef, StringMap *replace_names)
 {
        std::ifstream is(filename.c_str(), std::ios_base::binary);
        if (!is.good()) {
-               errorstream << __FUNCTION__ << ": unable to open file '" << filename
-                           << "'" << std::endl;
+               errorstream << __FUNCTION__ << ": unable to open file '"
+                       << filename << "'" << std::endl;
                return false;
        }
 
-       size_t origsize = m_nodenames.size();
-       if (!deserializeFromMts(&is, &m_nodenames))
-               return false;
+       if (!m_ndef)
+               m_ndef = ndef;
 
-       m_nnlistsizes.push_back(m_nodenames.size() - origsize);
+       if (!deserializeFromMts(&is))
+               return false;
 
        name = filename;
 
        if (replace_names) {
-               for (size_t i = origsize; i < m_nodenames.size(); i++) {
-                       std::string &node_name = m_nodenames[i];
+               for (std::string &node_name : m_nodenames) {
                        StringMap::iterator it = replace_names->find(node_name);
                        if (it != replace_names->end())
                                node_name = it->second;
                }
        }
 
-       if (ndef)
-               ndef->pendNodeResolve(this);
+       if (m_ndef)
+               m_ndef->pendNodeResolve(this);
 
        return true;
 }
 
-bool Schematic::saveSchematicToFile(
-               const std::string &filename, const NodeDefManager *ndef)
+
+bool Schematic::saveSchematicToFile(const std::string &filename,
+       const NodeDefManager *ndef)
 {
-       MapNode *orig_schemdata = schemdata;
-       std::vector<std::string> ndef_nodenames;
-       std::vector<std::string> *names;
+       Schematic *schem = this;
 
-       if (m_resolve_done && ndef == NULL)
-               ndef = m_ndef;
+       bool needs_condense = isResolveDone();
 
-       if (ndef) {
-               names = &ndef_nodenames;
+       if (!m_ndef)
+               m_ndef = ndef;
 
-               u32 volume = size.X * size.Y * size.Z;
-               schemdata = new MapNode[volume];
-               for (u32 i = 0; i != volume; i++)
-                       schemdata[i] = orig_schemdata[i];
+       if (needs_condense) {
+               if (!m_ndef)
+                       return false;
 
-               generate_nodelist_and_update_ids(schemdata, volume, names, ndef);
-       } else { // otherwise, use the names we have on hand in the list
-               names = &m_nodenames;
+               schem = (Schematic *)this->clone();
+               schem->condenseContentIds();
        }
 
        std::ostringstream os(std::ios_base::binary);
-       bool status = serializeToMts(&os, *names);
+       bool status = schem->serializeToMts(&os);
 
-       if (ndef) {
-               delete[] schemdata;
-               schemdata = orig_schemdata;
-       }
+       if (needs_condense)
+               delete schem;
 
        if (!status)
                return false;
@@ -516,6 +547,7 @@ bool Schematic::saveSchematicToFile(
        return fs::safeWriteToFile(filename, os.str());
 }
 
+
 bool Schematic::getSchematicFromMap(Map *map, v3s16 p1, v3s16 p2)
 {
        MMVManip *vm = new MMVManip(map);
@@ -534,20 +566,26 @@ bool Schematic::getSchematicFromMap(Map *map, v3s16 p1, v3s16 p2)
 
        u32 i = 0;
        for (s16 z = p1.Z; z <= p2.Z; z++)
-               for (s16 y = p1.Y; y <= p2.Y; y++) {
-                       u32 vi = vm->m_area.index(p1.X, y, z);
-                       for (s16 x = p1.X; x <= p2.X; x++, i++, vi++) {
-                               schemdata[i] = vm->m_data[vi];
-                               schemdata[i].param1 = MTSCHEM_PROB_ALWAYS;
-                       }
+       for (s16 y = p1.Y; y <= p2.Y; y++) {
+               u32 vi = vm->m_area.index(p1.X, y, z);
+               for (s16 x = p1.X; x <= p2.X; x++, i++, vi++) {
+                       schemdata[i] = vm->m_data[vi];
+                       schemdata[i].param1 = MTSCHEM_PROB_ALWAYS;
                }
+       }
 
        delete vm;
+
+       // Reset and mark as complete
+       NodeResolver::reset(true);
+
        return true;
 }
 
-void Schematic::applyProbabilities(v3s16 p0, std::vector<std::pair<v3s16, u8>> *plist,
-               std::vector<std::pair<s16, u8>> *splist)
+
+void Schematic::applyProbabilities(v3s16 p0,
+       std::vector<std::pair<v3s16, u8> > *plist,
+       std::vector<std::pair<s16, u8> > *splist)
 {
        for (size_t i = 0; i != plist->size(); i++) {
                v3s16 p = (*plist)[i].first - p0;
@@ -563,32 +601,36 @@ void Schematic::applyProbabilities(v3s16 p0, std::vector<std::pair<v3s16, u8>> *
        }
 
        for (size_t i = 0; i != splist->size(); i++) {
-               s16 y = (*splist)[i].first - p0.Y;
-               slice_probs[y] = (*splist)[i].second;
+               s16 slice = (*splist)[i].first;
+               if (slice < size.Y)
+                       slice_probs[slice] = (*splist)[i].second;
        }
 }
 
-void generate_nodelist_and_update_ids(MapNode *nodes, size_t nodecount,
-               std::vector<std::string> *usednodes, const NodeDefManager *ndef)
+
+void Schematic::condenseContentIds()
 {
        std::unordered_map<content_t, content_t> nodeidmap;
        content_t numids = 0;
 
+       // Reset node resolve fields
+       NodeResolver::reset();
+
+       size_t nodecount = size.X * size.Y * size.Z;
        for (size_t i = 0; i != nodecount; i++) {
                content_t id;
-               content_t c = nodes[i].getContent();
+               content_t c = schemdata[i].getContent();
 
-               std::unordered_map<content_t, content_t>::const_iterator it =
-                               nodeidmap.find(c);
+               auto it = nodeidmap.find(c);
                if (it == nodeidmap.end()) {
                        id = numids;
                        numids++;
 
-                       usednodes->push_back(ndef->get(c).name);
-                       nodeidmap.insert(std::make_pair(c, id));
+                       m_nodenames.push_back(m_ndef->get(c).name);
+                       nodeidmap.emplace(std::make_pair(c, id));
                } else {
                        id = it->second;
                }
-               nodes[i].setContent(id);
+               schemdata[i].setContent(id);
        }
 }