Add NodeResolver and clean up node name -> content ID resolution system
authorkwolekr <kwolekr@minetest.net>
Wed, 8 Oct 2014 19:28:14 +0000 (15:28 -0400)
committerkwolekr <kwolekr@minetest.net>
Mon, 27 Oct 2014 03:55:45 +0000 (23:55 -0400)
src/biome.cpp
src/biome.h
src/emerge.cpp
src/mapgen.cpp
src/mapgen.h
src/nodedef.cpp
src/nodedef.h
src/script/common/c_converter.cpp
src/script/common/c_converter.h
src/script/lua_api/l_mapgen.cpp
src/server.cpp

index e1dfc47afbb021c31bf06e03a79d7f27c8d3d327..94a2435f299ad129d7a938f7b8cb6e40ffb28080 100644 (file)
@@ -30,7 +30,7 @@ NoiseParams nparams_biome_def_heat(50, 50, v3f(500.0, 500.0, 500.0), 5349, 3, 0.
 NoiseParams nparams_biome_def_humidity(50, 50, v3f(500.0, 500.0, 500.0), 842, 3, 0.55);
 
 
-BiomeDefManager::BiomeDefManager() {
+BiomeDefManager::BiomeDefManager(NodeResolver *resolver) {
        biome_registration_finished = false;
        np_heat     = &nparams_biome_def_heat;
        np_humidity = &nparams_biome_def_humidity;
@@ -38,30 +38,22 @@ BiomeDefManager::BiomeDefManager() {
        // Create default biome to be used in case none exist
        Biome *b = new Biome;
        
-       b->id    = 0;
-       b->name  = "Default";
-       b->flags = 0;
-       
-       b->depth_top    = 0;
-       b->depth_filler = 0;
-
-       b->nname_top        = "air";
-       b->nname_filler     = "air";
-       b->nname_water      = "mapgen_water_source";
-       b->nname_dust       = "air";
-       b->nname_dust_water = "mapgen_water_source";
-
-       b->c_top        = CONTENT_IGNORE;
-       b->c_filler     = CONTENT_IGNORE;
-       b->c_water      = CONTENT_IGNORE;
-       b->c_dust       = CONTENT_IGNORE;
-       b->c_dust_water = CONTENT_IGNORE;
-
+       b->id             = 0;
+       b->name           = "Default";
+       b->flags          = 0;
+       b->depth_top      = 0;
+       b->depth_filler   = 0;
        b->height_min     = -MAP_GENERATION_LIMIT;
        b->height_max     = MAP_GENERATION_LIMIT;
        b->heat_point     = 0.0;
        b->humidity_point = 0.0;
 
+       resolver->addNode("air",                 "", CONTENT_AIR, &b->c_top);
+       resolver->addNode("air",                 "", CONTENT_AIR, &b->c_filler);
+       resolver->addNode("mapgen_water_source", "", CONTENT_AIR, &b->c_water);
+       resolver->addNode("air",                 "", CONTENT_AIR, &b->c_dust);
+       resolver->addNode("mapgen_water_source", "", CONTENT_AIR, &b->c_dust_water);
+
        biomes.push_back(b);
 }
 
@@ -106,62 +98,18 @@ void BiomeDefManager::calcBiomes(BiomeNoiseInput *input, u8 *biomeid_map) {
 }
 
 
-void BiomeDefManager::resolveNodeNames(INodeDefManager *ndef) {
-       Biome *b;
-       
-       biome_registration_finished = true;
-       
-       for (size_t i = 0; i < biomes.size(); i++) {
-               b = biomes[i];
-
-               b->c_top = ndef->getId(b->nname_top);
-               if (b->c_top == CONTENT_IGNORE) {
-                       errorstream << "BiomeDefManager::resolveNodeNames: node '"
-                               << b->nname_top << "' not defined" << std::endl;
-                       b->c_top     = CONTENT_AIR;
-                       b->depth_top = 0;
-               }
-       
-               b->c_filler = ndef->getId(b->nname_filler);
-               if (b->c_filler == CONTENT_IGNORE) {
-                       errorstream << "BiomeDefManager::resolveNodeNames: node '"
-                               << b->nname_filler << "' not defined" << std::endl;
-                       b->c_filler     = CONTENT_AIR;
-                       b->depth_filler = 0;
-               }
-               
-               b->c_water = ndef->getId(b->nname_water);
-               if (b->c_water == CONTENT_IGNORE) {
-                       errorstream << "BiomeDefManager::resolveNodeNames: node '"
-                               << b->nname_water << "' not defined" << std::endl;
-                       b->c_water = CONTENT_AIR;
-               }
-               
-               b->c_dust = ndef->getId(b->nname_dust);
-               if (b->c_dust == CONTENT_IGNORE) {
-                       errorstream << "BiomeDefManager::resolveNodeNames: node '"
-                               << b->nname_dust << "' not defined" << std::endl;
-               }
-               
-               b->c_dust_water = ndef->getId(b->nname_dust_water);
-               if (b->c_dust_water == CONTENT_IGNORE) {
-                       errorstream << "BiomeDefManager::resolveNodeNames: node '"
-                               << b->nname_dust_water << "' not defined" << std::endl;
-               }
-       }
-}
-
-
 void BiomeDefManager::addBiome(Biome *b) {
        if (biome_registration_finished) {
-               errorstream << "BIomeDefManager: biome registration already finished, dropping " << b->name <<std::endl;
+               errorstream << "BIomeDefManager: biome registration already "
+                       "finished, dropping " << b->name << std::endl;
                delete b;
                return;
        }
        
        size_t nbiomes = biomes.size();
        if (nbiomes >= 0xFF) {
-               errorstream << "BiomeDefManager: too many biomes, dropping " << b->name << std::endl;
+               errorstream << "BiomeDefManager: too many biomes, dropping "
+                       << b->name << std::endl;
                delete b;
                return;
        }
index aa83c4e0b25ff9ec22b6ed375d8b8d3bd601d418..fdfefeaf9be0c3853cc64de4c2b41588f4713ce1 100644 (file)
@@ -45,11 +45,13 @@ public:
        std::string name;
        u32 flags;
        
+/*
        std::string nname_top;
        std::string nname_filler;
        std::string nname_water;
        std::string nname_dust;
        std::string nname_dust_water;
+*/
 
        content_t c_top;
        content_t c_filler;
@@ -81,7 +83,7 @@ public:
        NoiseParams *np_heat;
        NoiseParams *np_humidity;
 
-       BiomeDefManager();
+       BiomeDefManager(NodeResolver *resolver);
        ~BiomeDefManager();
        
        Biome *createBiome(BiomeTerrainType btt);
index b6e2080a6efa97d2d43a080e96e8e4305738aa2c..a4b0752e5b7fe87b2513ee0b04d1dd104d26ed2b 100644 (file)
@@ -85,7 +85,7 @@ EmergeManager::EmergeManager(IGameDef *gamedef) {
        registerMapgen("singlenode", new MapgenFactorySinglenode());
 
        this->ndef     = gamedef->getNodeDefManager();
-       this->biomedef = new BiomeDefManager();
+       this->biomedef = new BiomeDefManager(gamedef->getNodeDefManager()->getResolver());
        this->gennotify = 0;
 
        // Note that accesses to this variable are not synchronized.
@@ -145,9 +145,9 @@ EmergeManager::~EmergeManager() {
                delete decorations[i];
        decorations.clear();
 
-       for (std::map<std::string, MapgenFactory *>::iterator iter = mglist.begin();
-                       iter != mglist.end(); iter ++) {
-               delete iter->second;
+       for (std::map<std::string, MapgenFactory *>::iterator it = mglist.begin();
+                       it != mglist.end(); ++it) {
+               delete it->second;
        }
        mglist.clear();
 
@@ -176,16 +176,6 @@ void EmergeManager::initMapgens() {
        if (mapgen.size())
                return;
 
-       // Resolve names of nodes for things that were registered
-       // (at this point, the registration period is over)
-       biomedef->resolveNodeNames(ndef);
-
-       for (size_t i = 0; i != ores.size(); i++)
-               ores[i]->resolveNodeNames(ndef);
-
-       for (size_t i = 0; i != decorations.size(); i++)
-               decorations[i]->resolveNodeNames(ndef);
-
        if (!params.sparams) {
                params.sparams = createMapgenParams(params.mg_name);
                if (!params.sparams) {
index 176c8a8a36c46b4178baa70cf91f44b28dd752e1..b7c929be7d6cb4185c416f739a54f1849e6c9eec 100644 (file)
@@ -96,28 +96,6 @@ Ore::~Ore() {
 }
 
 
-void Ore::resolveNodeNames(INodeDefManager *ndef) {
-       if (ore == CONTENT_IGNORE) {
-               ore = ndef->getId(ore_name);
-               if (ore == CONTENT_IGNORE) {
-                       errorstream << "Ore::resolveNodeNames: ore node '"
-                               << ore_name << "' not defined";
-                       ore = CONTENT_AIR;
-                       wherein.push_back(CONTENT_AIR);
-                       return;
-               }
-       }
-
-       for (size_t i=0; i != wherein_names.size(); i++) {
-               std::string name = wherein_names[i];
-               content_t c = ndef->getId(name);
-               if (c != CONTENT_IGNORE) {
-                       wherein.push_back(c);
-               }
-       }
-}
-
-
 void Ore::placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) {
        int in_range = 0;
 
@@ -147,7 +125,7 @@ void Ore::placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) {
 void OreScatter::generate(ManualMapVoxelManipulator *vm, int seed,
                                                  u32 blockseed, v3s16 nmin, v3s16 nmax) {
        PseudoRandom pr(blockseed);
-       MapNode n_ore(ore, 0, ore_param2);
+       MapNode n_ore(c_ore, 0, ore_param2);
 
        int volume = (nmax.X - nmin.X + 1) *
                                 (nmax.Y - nmin.Y + 1) *
@@ -171,8 +149,8 @@ void OreScatter::generate(ManualMapVoxelManipulator *vm, int seed,
                                continue;
 
                        u32 i = vm->m_area.index(x0 + x1, y0 + y1, z0 + z1);
-                       for (size_t ii = 0; ii < wherein.size(); ii++)
-                               if (vm->m_data[i].getContent() == wherein[ii])
+                       for (size_t ii = 0; ii < c_wherein.size(); ii++)
+                               if (vm->m_data[i].getContent() == c_wherein[ii])
                                        vm->m_data[i] = n_ore;
                }
        }
@@ -182,7 +160,7 @@ void OreScatter::generate(ManualMapVoxelManipulator *vm, int seed,
 void OreSheet::generate(ManualMapVoxelManipulator *vm, int seed,
                                                u32 blockseed, v3s16 nmin, v3s16 nmax) {
        PseudoRandom pr(blockseed + 4234);
-       MapNode n_ore(ore, 0, ore_param2);
+       MapNode n_ore(c_ore, 0, ore_param2);
 
        int max_height = clust_size;
        int y_start = pr.range(nmin.Y, nmax.Y - max_height);
@@ -210,9 +188,12 @@ void OreSheet::generate(ManualMapVoxelManipulator *vm, int seed,
                        if (!vm->m_area.contains(i))
                                continue;
 
-                       for (size_t ii = 0; ii < wherein.size(); ii++)
-                               if (vm->m_data[i].getContent() == wherein[ii])
+                       for (size_t ii = 0; ii < c_wherein.size(); ii++) {
+                               if (vm->m_data[i].getContent() == c_wherein[ii]) {
                                        vm->m_data[i] = n_ore;
+                                       break;
+                               }
+                       }
                }
        }
 }
@@ -248,14 +229,6 @@ Decoration::~Decoration() {
 }
 
 
-void Decoration::resolveNodeNames(INodeDefManager *ndef) {
-       this->ndef = ndef;
-
-       if (c_place_on == CONTENT_IGNORE)
-               c_place_on = ndef->getId(place_on_name);
-}
-
-
 void Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) {
        PseudoRandom ps(blockseed + 53);
        int carea_size = nmax.X - nmin.X + 1;
@@ -388,48 +361,17 @@ void Decoration::placeCutoffs(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
 ///////////////////////////////////////////////////////////////////////////////
 
 
-void DecoSimple::resolveNodeNames(INodeDefManager *ndef) {
-       Decoration::resolveNodeNames(ndef);
-
-       if (c_deco == CONTENT_IGNORE && !decolist_names.size()) {
-               c_deco = ndef->getId(deco_name);
-               if (c_deco == CONTENT_IGNORE) {
-                       errorstream << "DecoSimple::resolveNodeNames: decoration node '"
-                               << deco_name << "' not defined" << std::endl;
-                       c_deco = CONTENT_AIR;
-               }
-       }
-       if (c_spawnby == CONTENT_IGNORE) {
-               c_spawnby = ndef->getId(spawnby_name);
-               if (c_spawnby == CONTENT_IGNORE) {
-                       errorstream << "DecoSimple::resolveNodeNames: spawnby node '"
-                               << spawnby_name << "' not defined" << std::endl;
-                       nspawnby = -1;
-                       c_spawnby = CONTENT_AIR;
-               }
-       }
-
-       if (c_decolist.size())
-               return;
-
-       for (size_t i = 0; i != decolist_names.size(); i++) {
-               content_t c = ndef->getId(decolist_names[i]);
-               if (c == CONTENT_IGNORE) {
-                       errorstream << "DecoSimple::resolveNodeNames: decolist node '"
-                               << decolist_names[i] << "' not defined" << std::endl;
-                       c = CONTENT_AIR;
-               }
-               c_decolist.push_back(c);
-       }
-}
-
-
 void DecoSimple::generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p) {
        ManualMapVoxelManipulator *vm = mg->vm;
 
        u32 vi = vm->m_area.index(p);
-       if (vm->m_data[vi].getContent() != c_place_on &&
-               c_place_on != CONTENT_IGNORE)
+       content_t c = vm->m_data[vi].getContent();
+       size_t idx;
+       for (idx = 0; idx != c_place_on.size(); idx++) {
+               if (c == c_place_on[idx])
+                       break;
+       }
+       if ((idx != 0) && (idx == c_place_on.size()))
                return;
 
        if (nspawnby != -1) {
@@ -447,17 +389,25 @@ void DecoSimple::generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p) {
 
                for (int i = 0; i != 8; i++) {
                        u32 index = vm->m_area.index(p + dirs[i]);
-                       if (vm->m_area.contains(index) &&
-                               vm->m_data[index].getContent() == c_spawnby)
-                               nneighs++;
+                       if (!vm->m_area.contains(index))
+                               continue;
+
+                       content_t c = vm->m_data[index].getContent();
+                       for (size_t j = 0; j != c_spawnby.size(); j++) {
+                               if (c == c_spawnby[j]) {
+                                       nneighs++;
+                                       break;
+                               }
+                       }
                }
 
                if (nneighs < nspawnby)
                        return;
        }
 
-       size_t ndecos = c_decolist.size();
-       content_t c_place = ndecos ? c_decolist[pr->range(0, ndecos - 1)] : c_deco;
+       if (c_decos.size() == 0)
+               return;
+       content_t c_place = c_decos[pr->range(0, c_decos.size() - 1)];
 
        s16 height = (deco_height_max > 0) ?
                pr->range(deco_height, deco_height_max) : deco_height;
@@ -483,7 +433,7 @@ int DecoSimple::getHeight() {
 
 
 std::string DecoSimple::getName() {
-       return deco_name;
+       return "";
 }
 
 
@@ -491,7 +441,6 @@ std::string DecoSimple::getName() {
 
 
 DecoSchematic::DecoSchematic() {
-       node_names  = NULL;
        schematic   = NULL;
        slice_probs = NULL;
        flags       = 0;
@@ -500,47 +449,19 @@ DecoSchematic::DecoSchematic() {
 
 
 DecoSchematic::~DecoSchematic() {
-       delete node_names;
        delete []schematic;
        delete []slice_probs;
 }
 
 
-void DecoSchematic::resolveNodeNames(INodeDefManager *ndef) {
-       Decoration::resolveNodeNames(ndef);
-
-       if (filename.empty())
-               return;
-
-       if (!node_names) {
-               errorstream << "DecoSchematic::resolveNodeNames: node name list was "
-                       "not created" << std::endl;
+void DecoSchematic::updateContentIds() {
+       if (flags & DECO_SCHEM_CIDS_UPDATED)
                return;
-       }
-
-       for (size_t i = 0; i != node_names->size(); i++) {
-               std::string name = node_names->at(i);
-
-               std::map<std::string, std::string>::iterator it;
-               it = replacements.find(name);
-               if (it != replacements.end())
-                       name = it->second;
 
-               content_t c = ndef->getId(name);
-               if (c == CONTENT_IGNORE) {
-                       errorstream << "DecoSchematic::resolveNodeNames: node '"
-                               << name << "' not defined" << std::endl;
-                       c = CONTENT_AIR;
-               }
-
-               c_nodes.push_back(c);
-       }
+       flags |= DECO_SCHEM_CIDS_UPDATED;
 
        for (int i = 0; i != size.X * size.Y * size.Z; i++)
                schematic[i].setContent(c_nodes[schematic[i].getContent()]);
-
-       delete node_names;
-       node_names = NULL;
 }
 
 
@@ -555,8 +476,13 @@ void DecoSchematic::generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p) {
                p.Z -= (size.Z + 1) / 2;
 
        u32 vi = vm->m_area.index(p);
-       if (vm->m_data[vi].getContent() != c_place_on &&
-               c_place_on != CONTENT_IGNORE)
+       content_t c = vm->m_data[vi].getContent();
+       size_t idx;
+       for (idx = 0; idx != c_place_on.size(); idx++) {
+               if (c == c_place_on[idx])
+                       break;
+       }
+       if ((idx != 0) && (idx == c_place_on.size()))
                return;
 
        Rotation rot = (rotation == ROTATE_RAND) ?
@@ -582,6 +508,8 @@ void DecoSchematic::blitToVManip(v3s16 p, ManualMapVoxelManipulator *vm,
        int ystride = size.X;
        int zstride = size.X * size.Y;
 
+       updateContentIds();
+
        s16 sx = size.X;
        s16 sy = size.Y;
        s16 sz = size.Z;
@@ -694,7 +622,9 @@ void DecoSchematic::placeStructure(Map *map, v3s16 p, bool force_placement) {
 }
 
 
-bool DecoSchematic::loadSchematicFile() {
+bool DecoSchematic::loadSchematicFile(NodeResolver *resolver,
+       std::map<std::string, std::string> &replace_names)
+{
        content_t cignore = CONTENT_IGNORE;
        bool have_cignore = false;
 
@@ -730,7 +660,6 @@ bool DecoSchematic::loadSchematicFile() {
 
        u16 nidmapcount = readU16(is);
 
-       node_names = new std::vector<std::string>;
        for (int i = 0; i != nidmapcount; i++) {
                std::string name = deSerializeString(is);
                if (name == "ignore") {
@@ -738,7 +667,14 @@ bool DecoSchematic::loadSchematicFile() {
                        cignore = i;
                        have_cignore = true;
                }
-               node_names->push_back(name);
+
+               std::map<std::string, std::string>::iterator it;
+
+               it = replace_names.find(name);
+               if (it != replace_names.end())
+                       name = it->second;
+
+               resolver->addNodeList(name.c_str(), &c_nodes);
        }
 
        delete []schematic;
index b272b5cb215424a21d9a0646034bd60b3ff6b135..01ab22730613b2993a4a4dfb7e5f8eadf5eebce4 100644 (file)
@@ -47,9 +47,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #define OREFLAG_NODEISNT  0x04 // not yet implemented
 
 /////////////////// Decoration flags
-#define DECO_PLACE_CENTER_X 1
-#define DECO_PLACE_CENTER_Y 2
-#define DECO_PLACE_CENTER_Z 4
+#define DECO_PLACE_CENTER_X     1
+#define DECO_PLACE_CENTER_Y     2
+#define DECO_PLACE_CENTER_Z     4
+#define DECO_SCHEM_CIDS_UPDATED 8
 
 #define ORE_RANGE_ACTUAL 1
 #define ORE_RANGE_MIRROR 2
@@ -164,10 +165,8 @@ struct MapgenFactory {
 
 class Ore {
 public:
-       std::string ore_name;
-       std::vector<std::string> wherein_names;
-       content_t ore;
-       std::vector<content_t> wherein;  // the node to be replaced
+       content_t c_ore;                  // the node to place
+       std::vector<content_t> c_wherein; // the nodes to be placed in
        u32 clust_scarcity; // ore cluster has a 1-in-clust_scarcity chance of appearing at a node
        s16 clust_num_ores; // how many ore nodes are in a chunk
        s16 clust_size;     // how large (in nodes) a chunk of ore is
@@ -180,14 +179,13 @@ public:
        Noise *noise;
 
        Ore() {
-               ore     = CONTENT_IGNORE;
+               c_ore   = CONTENT_IGNORE;
                np      = NULL;
                noise   = NULL;
        }
 
        virtual ~Ore();
 
-       void resolveNodeNames(INodeDefManager *ndef);
        void placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);
        virtual void generate(ManualMapVoxelManipulator *vm, int seed,
                                                u32 blockseed, v3s16 nmin, v3s16 nmax) = 0;
@@ -234,8 +232,7 @@ public:
        INodeDefManager *ndef;
 
        int mapseed;
-       std::string place_on_name;
-       content_t c_place_on;
+       std::vector<content_t> c_place_on;
        s16 sidelen;
        float fill_ratio;
        NoiseParams *np;
@@ -247,7 +244,6 @@ public:
        Decoration();
        virtual ~Decoration();
 
-       virtual void resolveNodeNames(INodeDefManager *ndef);
        void placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);
        void placeCutoffs(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);
 
@@ -258,20 +254,14 @@ public:
 
 class DecoSimple : public Decoration {
 public:
-       std::string deco_name;
-       std::string spawnby_name;
-       content_t c_deco;
-       content_t c_spawnby;
+       std::vector<content_t> c_decos;
+       std::vector<content_t> c_spawnby;
        s16 deco_height;
        s16 deco_height_max;
        s16 nspawnby;
 
-       std::vector<std::string> decolist_names;
-       std::vector<content_t> c_decolist;
-
        ~DecoSimple() {}
 
-       void resolveNodeNames(INodeDefManager *ndef);
        virtual void generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p);
        virtual int getHeight();
        virtual std::string getName();
@@ -288,9 +278,7 @@ class DecoSchematic : public Decoration {
 public:
        std::string filename;
 
-       std::vector<std::string> *node_names;
        std::vector<content_t> c_nodes;
-       std::map<std::string, std::string> replacements;
 
        u32 flags;
        Rotation rotation;
@@ -301,7 +289,7 @@ public:
        DecoSchematic();
        ~DecoSchematic();
 
-       void resolveNodeNames(INodeDefManager *ndef);
+       void updateContentIds();
        virtual void generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p);
        virtual int getHeight();
        virtual std::string getName();
@@ -309,7 +297,8 @@ public:
        void blitToVManip(v3s16 p, ManualMapVoxelManipulator *vm,
                                        Rotation rot, bool force_placement);
 
-       bool loadSchematicFile();
+       bool loadSchematicFile(NodeResolver *resolver,
+               std::map<std::string, std::string> &replace_names);
        void saveSchematicFile(INodeDefManager *ndef);
 
        bool getSchematicFromMap(Map *map, v3s16 p1, v3s16 p2);
index cf30d76b3f77a3e7683ca45bdb52957851da932a..3fc9bbc11b6291561971c647f75cd5ace566f400 100644 (file)
@@ -402,6 +402,7 @@ public:
        virtual void updateTextures(IGameDef *gamedef);
        void serialize(std::ostream &os, u16 protocol_version);
        void deSerialize(std::istream &is);
+       virtual NodeResolver *getResolver();
 
 private:
        void addNameIdMapping(content_t i, std::string name);
@@ -430,10 +431,14 @@ private:
 
        // Next possibly free id
        content_t m_next_id;
+
+       // NodeResolver to queue pending node resolutions
+       NodeResolver m_resolver;
 };
 
 
-CNodeDefManager::CNodeDefManager()
+CNodeDefManager::CNodeDefManager() :
+       m_resolver(this)
 {
        clear();
 }
@@ -1017,6 +1022,12 @@ void CNodeDefManager::addNameIdMapping(content_t i, std::string name)
 }
 
 
+NodeResolver *CNodeDefManager::getResolver()
+{
+       return &m_resolver;
+}
+
+
 IWritableNodeDefManager *createNodeDefManager()
 {
        return new CNodeDefManager();
@@ -1242,3 +1253,157 @@ void ContentFeatures::deSerializeOld(std::istream &is, int version)
                throw SerializationError("unsupported ContentFeatures version");
        }
 }
+
+/*
+       NodeResolver
+*/
+
+NodeResolver::NodeResolver(INodeDefManager *ndef)
+{
+       m_ndef = ndef;
+       m_is_node_registration_complete = false;
+}
+
+
+NodeResolver::~NodeResolver()
+{
+       while (!m_pending_contents.empty()) {
+               NodeResolveInfo *nri = m_pending_contents.front();
+               m_pending_contents.pop_front();
+               delete nri;
+       }
+}
+
+
+int NodeResolver::addNode(std::string n_wanted, std::string n_alt,
+               content_t c_fallback, content_t *content)
+{
+       if (m_is_node_registration_complete) {
+               if (m_ndef->getId(n_wanted, *content))
+                       return NR_STATUS_SUCCESS;
+
+               if (n_alt == "")
+                       return NR_STATUS_FAILURE;
+
+               return m_ndef->getId(n_alt, *content) ?
+                       NR_STATUS_SUCCESS : NR_STATUS_FAILURE;
+       } else {
+               NodeResolveInfo *nfi = new NodeResolveInfo;
+               nfi->n_wanted   = n_wanted;
+               nfi->n_alt      = n_alt;
+               nfi->c_fallback = c_fallback;
+               nfi->output     = content;
+
+               m_pending_contents.push_back(nfi);
+
+               return NR_STATUS_PENDING;
+       }
+}
+
+
+int NodeResolver::addNodeList(const char *nodename,
+               std::vector<content_t> *content_vec)
+{
+       if (m_is_node_registration_complete) {
+               std::set<content_t> idset;
+               std::set<content_t>::iterator it;
+
+               m_ndef->getIds(nodename, idset);
+               for (it = idset.begin(); it != idset.end(); ++it)
+                       content_vec->push_back(*it);
+
+               return idset.size() ? NR_STATUS_SUCCESS : NR_STATUS_FAILURE;
+       } else {
+               m_pending_content_vecs.push_back(
+                       std::make_pair(std::string(nodename), content_vec));
+               return NR_STATUS_PENDING;
+       }
+}
+
+
+bool NodeResolver::cancelNode(content_t *content)
+{
+       bool found = false;
+
+       std::list<NodeResolveInfo *>::iterator it = m_pending_contents.begin();
+       while (it != m_pending_contents.end()) {
+               NodeResolveInfo *nfi = *it;
+               if (nfi->output == content) {
+                       it = m_pending_contents.erase(it);
+                       delete nfi;
+                       found = true;
+               }
+       }
+
+       return found;
+}
+
+
+int NodeResolver::cancelNodeList(std::vector<content_t> *content_vec)
+{
+       int num_canceled = 0;
+
+       std::list<std::pair<std::string, std::vector<content_t> *> >::iterator it;
+       it = m_pending_content_vecs.begin();
+       while (it != m_pending_content_vecs.end()) {
+               if (it->second == content_vec) {
+                       it = m_pending_content_vecs.erase(it);
+                       num_canceled++;
+               }
+       }
+
+       return num_canceled;
+}
+
+
+int NodeResolver::resolveNodes()
+{
+       int num_failed = 0;
+
+       //// Resolve pending single node name -> content ID mappings
+       while (!m_pending_contents.empty()) {
+               NodeResolveInfo *nri = m_pending_contents.front();              
+               m_pending_contents.pop_front();
+
+               bool success = true;
+               if (!m_ndef->getId(nri->n_wanted, *nri->output)) {
+                       success = (nri->n_alt != "") ?
+                               m_ndef->getId(nri->n_alt, *nri->output) : false;
+               }
+
+               if (!success) {
+                       *nri->output = nri->c_fallback;
+                       num_failed++;
+                       errorstream << "NodeResolver::resolveNodes():  Failed to "
+                               "resolve '" << nri->n_wanted;
+                       if (nri->n_alt != "")
+                               errorstream << "' and '" << nri->n_alt;
+                       errorstream << "' to a content ID" << std::endl;
+               }
+
+               delete nri;
+       }
+
+       //// Resolve pending node names and add to content_t vector
+       while (!m_pending_content_vecs.empty()) {
+               std::pair<std::string, std::vector<content_t> *> item =
+                       m_pending_content_vecs.front();
+               m_pending_content_vecs.pop_front();
+
+               std::string &name = item.first;
+               std::vector<content_t> *output = item.second;
+               
+               std::set<content_t> idset;
+               std::set<content_t>::iterator it;
+
+               m_ndef->getIds(name, idset);
+               for (it = idset.begin(); it != idset.end(); ++it)
+                       output->push_back(*it);
+       }
+
+       //// Mark node registration as complete so future resolve
+       //// requests are satisfied immediately
+       m_is_node_registration_complete = true;
+
+       return num_failed;
+}
index 27d67b481198748086a9457e415a9910a773ccb9..bd29b92b640d3f093acacaa13812aa18759e960d 100644 (file)
@@ -282,6 +282,40 @@ struct ContentFeatures
        }
 };
 
+struct NodeResolveInfo {
+       std::string n_wanted;
+       std::string n_alt;
+       content_t c_fallback;
+       content_t *output;
+};
+
+#define NR_STATUS_FAILURE 0
+#define NR_STATUS_PENDING 1
+#define NR_STATUS_SUCCESS 2
+
+class NodeResolver {
+public:
+       NodeResolver(INodeDefManager *ndef);
+       ~NodeResolver();
+
+       int addNode(std::string n_wanted, std::string n_alt,
+               content_t c_fallback, content_t *content);
+       int addNodeList(const char *nodename, std::vector<content_t> *content_vec);
+
+       bool cancelNode(content_t *content);
+       int cancelNodeList(std::vector<content_t> *content_vec);
+
+       int resolveNodes();
+
+       bool isNodeRegFinished() { return m_is_node_registration_complete; }
+
+private:
+       INodeDefManager *m_ndef;
+       bool m_is_node_registration_complete;
+       std::list<NodeResolveInfo *> m_pending_contents;
+       std::list<std::pair<std::string, std::vector<content_t> *> > m_pending_content_vecs;
+};
+
 class INodeDefManager
 {
 public:
@@ -298,6 +332,8 @@ public:
        virtual const ContentFeatures& get(const std::string &name) const=0;
        
        virtual void serialize(std::ostream &os, u16 protocol_version)=0;
+
+       virtual NodeResolver *getResolver()=0;
 };
 
 class IWritableNodeDefManager : public INodeDefManager
@@ -338,9 +374,11 @@ public:
 
        virtual void serialize(std::ostream &os, u16 protocol_version)=0;
        virtual void deSerialize(std::istream &is)=0;
+
+       virtual NodeResolver *getResolver()=0;
 };
 
-IWritableNodeDefManagercreateNodeDefManager();
+IWritableNodeDefManager *createNodeDefManager();
 
 #endif
 
index b2ef0573cf696c547509adfda8b2599e6c011522..a906171d3665fa6e1be92f27f3d32f7967a21e66 100644 (file)
@@ -227,6 +227,25 @@ std::vector<aabb3f> read_aabb3f_vector(lua_State *L, int index, f32 scale)
        return boxes;
 }
 
+bool read_stringlist(lua_State *L, int index, std::vector<const char *> &result)
+{
+       if (index < 0)
+               index = lua_gettop(L) + 1 + index;
+
+       if (lua_istable(L, index)) {
+               lua_pushnil(L);
+               while (lua_next(L, index)) {
+                       result.push_back(lua_tostring(L, -1));
+                       lua_pop(L, 1);
+               }
+       } else if (lua_isstring(L, index)) {
+               result.push_back(lua_tostring(L, index));
+       } else {
+               return false;
+       }
+       return true;
+}
+
 /*
        Table field getters
 */
@@ -287,6 +306,17 @@ bool getboolfield(lua_State *L, int table,
        return got;
 }
 
+bool getstringlistfield(lua_State *L, int table, const char *fieldname,
+               std::vector<const char *> &result)
+{
+       lua_getfield(L, table, fieldname);
+
+       bool got = read_stringlist(L, -1, result);
+
+       lua_pop(L, 1);
+       return got;
+}
+
 std::string checkstringfield(lua_State *L, int table,
                const char *fieldname)
 {
index 0c051a80328e82c2eb69ae782c18117bc811eada..3b7eb6f7d2f8a1db4bc22bd8aa69d56de48905a5 100644 (file)
@@ -37,7 +37,7 @@ extern "C" {
 #include <lua.h>
 }
 
-std::string        getstringfield_default        (lua_State *L, int table,
+std::string        getstringfield_default(lua_State *L, int table,
                              const char *fieldname, const std::string &default_);
 bool               getboolfield_default(lua_State *L, int table,
                              const char *fieldname, bool default_);
@@ -48,9 +48,12 @@ int                getintfield_default           (lua_State *L, int table,
 
 bool               getstringfield(lua_State *L, int table,
                              const char *fieldname, std::string &result);
+bool               getstringlistfield(lua_State *L, int table,
+                             const char *fieldname,
+                             std::vector<const char *> &result);
 bool               getintfield(lua_State *L, int table,
                              const char *fieldname, int &result);
-void               read_groups                   (lua_State *L, int index,
+void               read_groups(lua_State *L, int index,
                              std::map<std::string, int> &result);
 bool               getboolfield(lua_State *L, int table,
                              const char *fieldname, bool &result);
@@ -68,28 +71,29 @@ void               setboolfield(lua_State *L, int table,
                              const char *fieldname, bool value);
 
 
-v3f           checkFloatPos             (lua_State *L, int index);
-v3f           check_v3f                 (lua_State *L, int index);
-v3s16         check_v3s16               (lua_State *L, int index);
+v3f                 checkFloatPos       (lua_State *L, int index);
+v3f                 check_v3f           (lua_State *L, int index);
+v3s16               check_v3s16         (lua_State *L, int index);
 
-v3f           read_v3f                  (lua_State *L, int index);
-v2f           read_v2f                  (lua_State *L, int index);
-v2s16         read_v2s16                (lua_State *L, int index);
-v2s32         read_v2s32                (lua_State *L, int index);
-video::SColor readARGB8                 (lua_State *L, int index);
-aabb3f        read_aabb3f               (lua_State *L, int index, f32 scale);
-v3s16         read_v3s16                (lua_State *L, int index);
-std::vector<aabb3f>
-              read_aabb3f_vector        (lua_State *L, int index, f32 scale);
+v3f                 read_v3f            (lua_State *L, int index);
+v2f                 read_v2f            (lua_State *L, int index);
+v2s16               read_v2s16          (lua_State *L, int index);
+v2s32               read_v2s32          (lua_State *L, int index);
+video::SColor       readARGB8           (lua_State *L, int index);
+aabb3f              read_aabb3f         (lua_State *L, int index, f32 scale);
+v3s16               read_v3s16          (lua_State *L, int index);
+std::vector<aabb3f> read_aabb3f_vector  (lua_State *L, int index, f32 scale);
+bool                read_stringlist     (lua_State *L, int index,
+                                         std::vector<const char *> &result);
 
-void          push_v3s16                (lua_State *L, v3s16 p);
-void          pushFloatPos              (lua_State *L, v3f p);
-void          push_v3f                  (lua_State *L, v3f p);
-void          push_v2f                  (lua_State *L, v2f p);
+void                push_v3s16          (lua_State *L, v3s16 p);
+void                pushFloatPos        (lua_State *L, v3f p);
+void                push_v3f            (lua_State *L, v3f p);
+void                push_v2f            (lua_State *L, v2f p);
 
 
 
-void               warn_if_field_exists      (lua_State *L,
+void                warn_if_field_exists      (lua_State *L,
                                               int table,
                                               const char *fieldname,
                                               const std::string &message);
index d31e84b3d374f2e50eb413afa3c727eb5aba12ab..b7548881594b79f775e67d7b99e7ea2002fd4215 100644 (file)
@@ -80,26 +80,28 @@ struct EnumString ModApiMapgen::es_Rotation[] =
 };
 
 
-static void read_schematic_replacements(lua_State *L, DecoSchematic *dschem, int index)
+static void read_schematic_replacements(lua_State *L,
+       std::map<std::string, std::string> replace_names, int index)
 {
        lua_pushnil(L);
        while (lua_next(L, index)) {
-               // key at index -2 and value at index -1
                std::string replace_from;
                std::string replace_to;
-               if (lua_istable(L, -1)) {  // Old {{"x", "y"}, ...} format
+
+               if (lua_istable(L, -1)) { // Old {{"x", "y"}, ...} format
                        lua_rawgeti(L, -1, 1);
                        replace_from = lua_tostring(L, -1);
                        lua_pop(L, 1);
+
                        lua_rawgeti(L, -1, 2);
                        replace_to = lua_tostring(L, -1);
                        lua_pop(L, 1);
-               } else {  // New {x = "y", ...} format
+               } else { // New {x = "y", ...} format
                        replace_from = lua_tostring(L, -2);
                        replace_to = lua_tostring(L, -1);
                }
-               dschem->replacements[replace_from] = replace_to;
-               // removes value, keeps key for next iteration
+
+               replace_names[replace_from] = replace_to;
                lua_pop(L, 1);
        }
 }
@@ -298,7 +300,8 @@ int ModApiMapgen::l_register_biome(lua_State *L)
        int index = 1;
        luaL_checktype(L, index, LUA_TTABLE);
 
-       BiomeDefManager *bmgr = getServer(L)->getEmergeManager()->biomedef;
+       NodeResolver *resolver = getServer(L)->getNodeDefManager()->getResolver();
+       BiomeDefManager *bmgr  = getServer(L)->getEmergeManager()->biomedef;
        if (!bmgr) {
                verbosestream << "register_biome: BiomeDefManager not active" << std::endl;
                return 0;
@@ -308,32 +311,25 @@ int ModApiMapgen::l_register_biome(lua_State *L)
                                "terrain_type", es_BiomeTerrainType, BIOME_TERRAIN_NORMAL);
        Biome *b = bmgr->createBiome(terrain);
 
-       b->name         = getstringfield_default(L, index, "name",
-                                                                                               "<no name>");
-       b->nname_top    = getstringfield_default(L, index, "node_top",
-                                                                                               "mapgen_dirt_with_grass");
-       b->nname_filler = getstringfield_default(L, index, "node_filler",
-                                                                                               "mapgen_dirt");
-       b->nname_water  = getstringfield_default(L, index, "node_water",
-                                                                                               "mapgen_water_source");
-       b->nname_dust   = getstringfield_default(L, index, "node_dust",
-                                                                                               "air");
-       b->nname_dust_water = getstringfield_default(L, index, "node_dust_water",
-                                                                                               "mapgen_water_source");
-
+       resolver->addNode(getstringfield_default(L, index, "node_top", ""),
+                "mapgen_dirt_with_grass", CONTENT_AIR, &b->c_top);
+       resolver->addNode(getstringfield_default(L, index, "node_filler", ""),
+               "mapgen_dirt", CONTENT_AIR, &b->c_filler);
+       resolver->addNode(getstringfield_default(L, index, "node_water", ""),
+               "mapgen_water_source", CONTENT_AIR, &b->c_water);
+       resolver->addNode(getstringfield_default(L, index, "node_dust", ""),
+               "air", CONTENT_IGNORE, &b->c_dust);
+       resolver->addNode(getstringfield_default(L, index, "node_dust_water", ""),
+               "mapgen_water_source", CONTENT_IGNORE, &b->c_dust_water);
+
+       b->name           = getstringfield_default(L, index, "name", "<no name>");
        b->depth_top      = getintfield_default(L, index, "depth_top",    1);
        b->depth_filler   = getintfield_default(L, index, "depth_filler", 3);
        b->height_min     = getintfield_default(L, index, "height_min",   0);
        b->height_max     = getintfield_default(L, index, "height_max",   0);
        b->heat_point     = getfloatfield_default(L, index, "heat_point",     0.);
        b->humidity_point = getfloatfield_default(L, index, "humidity_point", 0.);
-
-       b->flags        = 0; //reserved
-       b->c_top        = CONTENT_IGNORE;
-       b->c_filler     = CONTENT_IGNORE;
-       b->c_water      = CONTENT_IGNORE;
-       b->c_dust       = CONTENT_IGNORE;
-       b->c_dust_water = CONTENT_IGNORE;
+       b->flags          = 0; //reserved
 
        verbosestream << "register_biome: " << b->name << std::endl;
        bmgr->addBiome(b);
@@ -349,6 +345,7 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
 
        EmergeManager *emerge = getServer(L)->getEmergeManager();
        BiomeDefManager *bdef = emerge->biomedef;
+       NodeResolver *resolver = getServer(L)->getNodeDefManager()->getResolver();
 
        enum DecorationType decotype = (DecorationType)getenumfield(L, index,
                                "deco_type", es_DecorationType, 0);
@@ -364,11 +361,9 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
                        << decotype << " not implemented";
                return 0;
        }
-
-       deco->c_place_on    = CONTENT_IGNORE;
-       deco->place_on_name = getstringfield_default(L, index, "place_on", "ignore");
-       deco->fill_ratio    = getfloatfield_default(L, index, "fill_ratio", 0.02);
-       deco->sidelen       = getintfield_default(L, index, "sidelen", 8);
+       
+       deco->fill_ratio = getfloatfield_default(L, index, "fill_ratio", 0.02);
+       deco->sidelen    = getintfield_default(L, index, "sidelen", 8);
        if (deco->sidelen <= 0) {
                errorstream << "register_decoration: sidelen must be "
                        "greater than 0" << std::endl;
@@ -376,51 +371,35 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
                return 0;
        }
 
+       //// Get node name(s) to place decoration on
+       std::vector<const char *> place_on_names;
+       getstringlistfield(L, index, "place_on", place_on_names);
+       for (size_t i = 0; i != place_on_names.size(); i++)
+               resolver->addNodeList(place_on_names[i], &deco->c_place_on);
+
+       //// Get NoiseParams to define how decoration is placed
        lua_getfield(L, index, "noise_params");
        deco->np = read_noiseparams(L, -1);
        lua_pop(L, 1);
 
-       lua_getfield(L, index, "biomes");
-       if (lua_istable(L, -1)) {
-               lua_pushnil(L);
-               while (lua_next(L, -2)) {
-                       const char *s = lua_tostring(L, -1);
-                       u8 biomeid = bdef->getBiomeIdByName(s);
-                       if (biomeid)
-                               deco->biomes.insert(biomeid);
-
-                       lua_pop(L, 1);
-               }
-               lua_pop(L, 1);
+       //// Get biomes associated with this decoration (if any)
+       std::vector<const char *> biome_list;
+       getstringlistfield(L, index, "biomes", biome_list);
+       for (size_t i = 0; i != biome_list.size(); i++) {
+               u8 biomeid = bdef->getBiomeIdByName(biome_list[i]);
+               if (biomeid)
+                       deco->biomes.insert(biomeid);
        }
 
+       //// Handle decoration type-specific parameters
        switch (decotype) {
                case DECO_SIMPLE: {
                        DecoSimple *dsimple = (DecoSimple *)deco;
-                       dsimple->c_deco     = CONTENT_IGNORE;
-                       dsimple->c_spawnby  = CONTENT_IGNORE;
-                       dsimple->spawnby_name    = getstringfield_default(L, index, "spawn_by", "air");
+
                        dsimple->deco_height     = getintfield_default(L, index, "height", 1);
                        dsimple->deco_height_max = getintfield_default(L, index, "height_max", 0);
                        dsimple->nspawnby        = getintfield_default(L, index, "num_spawn_by", -1);
 
-                       lua_getfield(L, index, "decoration");
-                       if (lua_istable(L, -1)) {
-                               lua_pushnil(L);
-                               while (lua_next(L, -2)) {
-                                       const char *s = lua_tostring(L, -1);
-                                       std::string str(s);
-                                       dsimple->decolist_names.push_back(str);
-
-                                       lua_pop(L, 1);
-                               }
-                       } else if (lua_isstring(L, -1)) {
-                               dsimple->deco_name = std::string(lua_tostring(L, -1));
-                       } else {
-                               dsimple->deco_name = std::string("air");
-                       }
-                       lua_pop(L, 1);
-
                        if (dsimple->deco_height <= 0) {
                                errorstream << "register_decoration: simple decoration height"
                                        " must be greater than 0" << std::endl;
@@ -428,7 +407,31 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
                                return 0;
                        }
 
-                       break; }
+                       std::vector<const char *> deco_names;
+                       getstringlistfield(L, index, "decoration", deco_names);
+                       if (deco_names.size() == 0) {
+                               errorstream << "register_decoration: no decoration nodes "
+                                       "defined" << std::endl;
+                               delete dsimple;
+                               return 0;
+                       }
+
+                       std::vector<const char *> spawnby_names;
+                       getstringlistfield(L, index, "spawn_by", spawnby_names);
+                       if (dsimple->nspawnby != -1 && spawnby_names.size() == 0) {
+                               errorstream << "register_decoration: no spawn_by nodes defined,"
+                                       " but num_spawn_by specified" << std::endl;
+                               delete dsimple;
+                               return 0;
+                       }
+
+                       for (size_t i = 0; i != deco_names.size(); i++)
+                               resolver->addNodeList(deco_names[i], &dsimple->c_decos);
+                       for (size_t i = 0; i != spawnby_names.size(); i++)
+                               resolver->addNodeList(spawnby_names[i], &dsimple->c_spawnby);
+
+                       break;
+               }
                case DECO_SCHEMATIC: {
                        DecoSchematic *dschem = (DecoSchematic *)deco;
 
@@ -439,10 +442,10 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
                        dschem->rotation = (Rotation)getenumfield(L, index,
                                "rotation", es_Rotation, ROTATE_0);
 
+                       std::map<std::string, std::string> replace_names;
                        lua_getfield(L, index, "replacements");
-                       if (lua_istable(L, -1)) {
-                               read_schematic_replacements(L, dschem, lua_gettop(L));
-                       }
+                       if (lua_istable(L, -1))
+                               read_schematic_replacements(L, replace_names, lua_gettop(L));
                        lua_pop(L, 1);
 
                        lua_getfield(L, index, "schematic");
@@ -452,17 +455,20 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
                        }
                        lua_pop(L, -1);
 
-                       if (!dschem->filename.empty() && !dschem->loadSchematicFile()) {
-                               errorstream << "register_decoration: failed to load schematic file '"
-                                       << dschem->filename << "'" << std::endl;
+                       if (!dschem->filename.empty() &&
+                               !dschem->loadSchematicFile(resolver, replace_names)) {
+                               errorstream << "register_decoration: failed to load schematic"
+                                       " file '" << dschem->filename << "'" << std::endl;
                                delete dschem;
                                return 0;
                        }
-                       break; }
+
+                       break;
+               }
                case DECO_LSYSTEM: {
                        //DecoLSystem *decolsystem = (DecoLSystem *)deco;
-
-                       break; }
+                       break;
+               }
        }
 
        emerge->decorations.push_back(deco);
@@ -478,7 +484,8 @@ int ModApiMapgen::l_register_ore(lua_State *L)
        int index = 1;
        luaL_checktype(L, index, LUA_TTABLE);
 
-       EmergeManager *emerge = getServer(L)->getEmergeManager();
+       EmergeManager *emerge  = getServer(L)->getEmergeManager();
+       NodeResolver *resolver = getServer(L)->getNodeDefManager()->getResolver();
 
        enum OreType oretype = (OreType)getenumfield(L, index,
                                "ore_type", es_OreType, ORE_SCATTER);
@@ -489,7 +496,9 @@ int ModApiMapgen::l_register_ore(lua_State *L)
                return 0;
        }
 
-       ore->ore_name       = getstringfield_default(L, index, "ore", "");
+       resolver->addNode(getstringfield_default(L, index, "ore", ""),
+               "", CONTENT_AIR, &ore->c_ore);
+
        ore->ore_param2     = (u8)getintfield_default(L, index, "ore_param2", 0);
        ore->clust_scarcity = getintfield_default(L, index, "clust_scarcity", 1);
        ore->clust_num_ores = getintfield_default(L, index, "clust_num_ores", 1);
@@ -500,20 +509,10 @@ int ModApiMapgen::l_register_ore(lua_State *L)
        ore->flags          = 0;
        getflagsfield(L, index, "flags", flagdesc_ore, &ore->flags, NULL);
 
-       lua_getfield(L, index, "wherein");
-       if (lua_istable(L, -1)) {
-               int  i = lua_gettop(L);
-               lua_pushnil(L);
-               while(lua_next(L, i) != 0) {
-                       ore->wherein_names.push_back(lua_tostring(L, -1));
-                       lua_pop(L, 1);
-               }
-       } else if (lua_isstring(L, -1)) {
-               ore->wherein_names.push_back(lua_tostring(L, -1));
-       } else {
-               ore->wherein_names.push_back("");
-       }
-       lua_pop(L, 1);
+       std::vector<const char *> wherein_names;
+       getstringlistfield(L, index, "wherein", wherein_names);
+       for (size_t i = 0; i != wherein_names.size(); i++)
+               resolver->addNodeList(wherein_names[i], &ore->c_wherein);
 
        lua_getfield(L, index, "noise_params");
        ore->np = read_noiseparams(L, -1);
@@ -530,8 +529,8 @@ int ModApiMapgen::l_register_ore(lua_State *L)
 
        emerge->ores.push_back(ore);
 
-       verbosestream << "register_ore: ore '" << ore->ore_name
-               << "' registered" << std::endl;
+       //verbosestream << "register_ore: ore '" << ore->ore_name
+       //      << "' registered" << std::endl;
        return 0;
 }
 
@@ -603,7 +602,7 @@ int ModApiMapgen::l_place_schematic(lua_State *L)
        DecoSchematic dschem;
 
        Map *map = &(getEnv(L)->getMap());
-       INodeDefManager *ndef = getServer(L)->getNodeDefManager();
+       NodeResolver *resolver = getServer(L)->getNodeDefManager()->getResolver();
 
        v3s16 p = read_v3s16(L, 1);
        if (!read_schematic(L, 2, &dschem, getServer(L)))
@@ -615,21 +614,20 @@ int ModApiMapgen::l_place_schematic(lua_State *L)
 
        dschem.rotation = (Rotation)rot;
 
-       if (lua_istable(L, 4)) {
-               read_schematic_replacements(L, &dschem, 4);
-       }
+       std::map<std::string, std::string> replace_names;
+       if (lua_istable(L, 4))
+               read_schematic_replacements(L, replace_names, 4);
 
        bool force_placement = true;
        if (lua_isboolean(L, 5))
                force_placement = lua_toboolean(L, 5);
 
        if (!dschem.filename.empty()) {
-               if (!dschem.loadSchematicFile()) {
+               if (!dschem.loadSchematicFile(resolver, replace_names)) {
                        errorstream << "place_schematic: failed to load schematic file '"
                                << dschem.filename << "'" << std::endl;
                        return 0;
                }
-               dschem.resolveNodeNames(ndef);
        }
 
        dschem.placeStructure(map, p, force_placement);
index d4d9816ddc125ca0be984463787d637991a3511b..812ab6410a82fa53d36caa6b1ba626f1c39726e4 100644 (file)
@@ -338,6 +338,9 @@ Server::Server(
        // Apply item aliases in the node definition manager
        m_nodedef->updateAliases(m_itemdef);
 
+       // Perform pending node name resolutions
+       m_nodedef->getResolver()->resolveNodes();
+
        // Load the mapgen params from global settings now after any
        // initial overrides have been set by the mods
        m_emerge->loadMapgenParams();