summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/biome.cpp84
-rw-r--r--src/biome.h4
-rw-r--r--src/emerge.cpp18
-rw-r--r--src/mapgen.cpp170
-rw-r--r--src/mapgen.h37
-rw-r--r--src/nodedef.cpp167
-rw-r--r--src/nodedef.h40
-rw-r--r--src/script/common/c_converter.cpp30
-rw-r--r--src/script/common/c_converter.h42
-rw-r--r--src/script/lua_api/l_mapgen.cpp194
-rw-r--r--src/server.cpp3
11 files changed, 446 insertions, 343 deletions
diff --git a/src/biome.cpp b/src/biome.cpp
index e1dfc47af..94a2435f2 100644
--- a/src/biome.cpp
+++ b/src/biome.cpp
@@ -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;
}
diff --git a/src/biome.h b/src/biome.h
index aa83c4e0b..fdfefeaf9 100644
--- a/src/biome.h
+++ b/src/biome.h
@@ -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);
diff --git a/src/emerge.cpp b/src/emerge.cpp
index b6e2080a6..a4b0752e5 100644
--- a/src/emerge.cpp
+++ b/src/emerge.cpp
@@ -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) {
diff --git a/src/mapgen.cpp b/src/mapgen.cpp
index 176c8a8a3..b7c929be7 100644
--- a/src/mapgen.cpp
+++ b/src/mapgen.cpp
@@ -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;
diff --git a/src/mapgen.h b/src/mapgen.h
index b272b5cb2..01ab22730 100644
--- a/src/mapgen.h
+++ b/src/mapgen.h
@@ -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);
diff --git a/src/nodedef.cpp b/src/nodedef.cpp
index cf30d76b3..3fc9bbc11 100644
--- a/src/nodedef.cpp
+++ b/src/nodedef.cpp
@@ -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;
+}
diff --git a/src/nodedef.h b/src/nodedef.h
index 27d67b481..bd29b92b6 100644
--- a/src/nodedef.h
+++ b/src/nodedef.h
@@ -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;
};
-IWritableNodeDefManager* createNodeDefManager();
+IWritableNodeDefManager *createNodeDefManager();
#endif
diff --git a/src/script/common/c_converter.cpp b/src/script/common/c_converter.cpp
index b2ef0573c..a906171d3 100644
--- a/src/script/common/c_converter.cpp
+++ b/src/script/common/c_converter.cpp
@@ -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)
{
diff --git a/src/script/common/c_converter.h b/src/script/common/c_converter.h
index 0c051a803..3b7eb6f7d 100644
--- a/src/script/common/c_converter.h
+++ b/src/script/common/c_converter.h
@@ -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);
diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp
index d31e84b3d..b75488815 100644
--- a/src/script/lua_api/l_mapgen.cpp
+++ b/src/script/lua_api/l_mapgen.cpp
@@ -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);
diff --git a/src/server.cpp b/src/server.cpp
index d4d9816dd..812ab6410 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -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();