Add NodeResolver and clean up node name -> content ID resolution system

This commit is contained in:
kwolekr 2014-10-08 15:28:14 -04:00
parent b49e5cfc70
commit d274cbfce6
11 changed files with 445 additions and 342 deletions

@ -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); 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; biome_registration_finished = false;
np_heat = &nparams_biome_def_heat; np_heat = &nparams_biome_def_heat;
np_humidity = &nparams_biome_def_humidity; np_humidity = &nparams_biome_def_humidity;
@ -41,27 +41,19 @@ BiomeDefManager::BiomeDefManager() {
b->id = 0; b->id = 0;
b->name = "Default"; b->name = "Default";
b->flags = 0; b->flags = 0;
b->depth_top = 0; b->depth_top = 0;
b->depth_filler = 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->height_min = -MAP_GENERATION_LIMIT; b->height_min = -MAP_GENERATION_LIMIT;
b->height_max = MAP_GENERATION_LIMIT; b->height_max = MAP_GENERATION_LIMIT;
b->heat_point = 0.0; b->heat_point = 0.0;
b->humidity_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); 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) { void BiomeDefManager::addBiome(Biome *b) {
if (biome_registration_finished) { 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; delete b;
return; return;
} }
size_t nbiomes = biomes.size(); size_t nbiomes = biomes.size();
if (nbiomes >= 0xFF) { 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; delete b;
return; return;
} }

@ -45,11 +45,13 @@ public:
std::string name; std::string name;
u32 flags; u32 flags;
/*
std::string nname_top; std::string nname_top;
std::string nname_filler; std::string nname_filler;
std::string nname_water; std::string nname_water;
std::string nname_dust; std::string nname_dust;
std::string nname_dust_water; std::string nname_dust_water;
*/
content_t c_top; content_t c_top;
content_t c_filler; content_t c_filler;
@ -81,7 +83,7 @@ public:
NoiseParams *np_heat; NoiseParams *np_heat;
NoiseParams *np_humidity; NoiseParams *np_humidity;
BiomeDefManager(); BiomeDefManager(NodeResolver *resolver);
~BiomeDefManager(); ~BiomeDefManager();
Biome *createBiome(BiomeTerrainType btt); Biome *createBiome(BiomeTerrainType btt);

@ -85,7 +85,7 @@ EmergeManager::EmergeManager(IGameDef *gamedef) {
registerMapgen("singlenode", new MapgenFactorySinglenode()); registerMapgen("singlenode", new MapgenFactorySinglenode());
this->ndef = gamedef->getNodeDefManager(); this->ndef = gamedef->getNodeDefManager();
this->biomedef = new BiomeDefManager(); this->biomedef = new BiomeDefManager(gamedef->getNodeDefManager()->getResolver());
this->gennotify = 0; this->gennotify = 0;
// Note that accesses to this variable are not synchronized. // Note that accesses to this variable are not synchronized.
@ -145,9 +145,9 @@ EmergeManager::~EmergeManager() {
delete decorations[i]; delete decorations[i];
decorations.clear(); decorations.clear();
for (std::map<std::string, MapgenFactory *>::iterator iter = mglist.begin(); for (std::map<std::string, MapgenFactory *>::iterator it = mglist.begin();
iter != mglist.end(); iter ++) { it != mglist.end(); ++it) {
delete iter->second; delete it->second;
} }
mglist.clear(); mglist.clear();
@ -176,16 +176,6 @@ void EmergeManager::initMapgens() {
if (mapgen.size()) if (mapgen.size())
return; 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) { if (!params.sparams) {
params.sparams = createMapgenParams(params.mg_name); params.sparams = createMapgenParams(params.mg_name);
if (!params.sparams) { if (!params.sparams) {

@ -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) { void Ore::placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) {
int in_range = 0; 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, void OreScatter::generate(ManualMapVoxelManipulator *vm, int seed,
u32 blockseed, v3s16 nmin, v3s16 nmax) { u32 blockseed, v3s16 nmin, v3s16 nmax) {
PseudoRandom pr(blockseed); 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) * int volume = (nmax.X - nmin.X + 1) *
(nmax.Y - nmin.Y + 1) * (nmax.Y - nmin.Y + 1) *
@ -171,8 +149,8 @@ void OreScatter::generate(ManualMapVoxelManipulator *vm, int seed,
continue; continue;
u32 i = vm->m_area.index(x0 + x1, y0 + y1, z0 + z1); u32 i = vm->m_area.index(x0 + x1, y0 + y1, z0 + z1);
for (size_t ii = 0; ii < wherein.size(); ii++) for (size_t ii = 0; ii < c_wherein.size(); ii++)
if (vm->m_data[i].getContent() == wherein[ii]) if (vm->m_data[i].getContent() == c_wherein[ii])
vm->m_data[i] = n_ore; vm->m_data[i] = n_ore;
} }
} }
@ -182,7 +160,7 @@ void OreScatter::generate(ManualMapVoxelManipulator *vm, int seed,
void OreSheet::generate(ManualMapVoxelManipulator *vm, int seed, void OreSheet::generate(ManualMapVoxelManipulator *vm, int seed,
u32 blockseed, v3s16 nmin, v3s16 nmax) { u32 blockseed, v3s16 nmin, v3s16 nmax) {
PseudoRandom pr(blockseed + 4234); 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 max_height = clust_size;
int y_start = pr.range(nmin.Y, nmax.Y - max_height); 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)) if (!vm->m_area.contains(i))
continue; continue;
for (size_t ii = 0; ii < wherein.size(); ii++) for (size_t ii = 0; ii < c_wherein.size(); ii++) {
if (vm->m_data[i].getContent() == wherein[ii]) if (vm->m_data[i].getContent() == c_wherein[ii]) {
vm->m_data[i] = n_ore; 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) { void Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) {
PseudoRandom ps(blockseed + 53); PseudoRandom ps(blockseed + 53);
int carea_size = nmax.X - nmin.X + 1; 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) { void DecoSimple::generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p) {
ManualMapVoxelManipulator *vm = mg->vm; ManualMapVoxelManipulator *vm = mg->vm;
u32 vi = vm->m_area.index(p); u32 vi = vm->m_area.index(p);
if (vm->m_data[vi].getContent() != c_place_on && content_t c = vm->m_data[vi].getContent();
c_place_on != CONTENT_IGNORE) 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; return;
if (nspawnby != -1) { 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++) { for (int i = 0; i != 8; i++) {
u32 index = vm->m_area.index(p + dirs[i]); u32 index = vm->m_area.index(p + dirs[i]);
if (vm->m_area.contains(index) && if (!vm->m_area.contains(index))
vm->m_data[index].getContent() == c_spawnby) 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++; nneighs++;
break;
}
}
} }
if (nneighs < nspawnby) if (nneighs < nspawnby)
return; return;
} }
size_t ndecos = c_decolist.size(); if (c_decos.size() == 0)
content_t c_place = ndecos ? c_decolist[pr->range(0, ndecos - 1)] : c_deco; return;
content_t c_place = c_decos[pr->range(0, c_decos.size() - 1)];
s16 height = (deco_height_max > 0) ? s16 height = (deco_height_max > 0) ?
pr->range(deco_height, deco_height_max) : deco_height; pr->range(deco_height, deco_height_max) : deco_height;
@ -483,7 +433,7 @@ int DecoSimple::getHeight() {
std::string DecoSimple::getName() { std::string DecoSimple::getName() {
return deco_name; return "";
} }
@ -491,7 +441,6 @@ std::string DecoSimple::getName() {
DecoSchematic::DecoSchematic() { DecoSchematic::DecoSchematic() {
node_names = NULL;
schematic = NULL; schematic = NULL;
slice_probs = NULL; slice_probs = NULL;
flags = 0; flags = 0;
@ -500,47 +449,19 @@ DecoSchematic::DecoSchematic() {
DecoSchematic::~DecoSchematic() { DecoSchematic::~DecoSchematic() {
delete node_names;
delete []schematic; delete []schematic;
delete []slice_probs; delete []slice_probs;
} }
void DecoSchematic::resolveNodeNames(INodeDefManager *ndef) { void DecoSchematic::updateContentIds() {
Decoration::resolveNodeNames(ndef); if (flags & DECO_SCHEM_CIDS_UPDATED)
if (filename.empty())
return; return;
if (!node_names) { flags |= DECO_SCHEM_CIDS_UPDATED;
errorstream << "DecoSchematic::resolveNodeNames: node name list was "
"not created" << std::endl;
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);
}
for (int i = 0; i != size.X * size.Y * size.Z; i++) for (int i = 0; i != size.X * size.Y * size.Z; i++)
schematic[i].setContent(c_nodes[schematic[i].getContent()]); 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; p.Z -= (size.Z + 1) / 2;
u32 vi = vm->m_area.index(p); u32 vi = vm->m_area.index(p);
if (vm->m_data[vi].getContent() != c_place_on && content_t c = vm->m_data[vi].getContent();
c_place_on != CONTENT_IGNORE) 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; return;
Rotation rot = (rotation == ROTATE_RAND) ? Rotation rot = (rotation == ROTATE_RAND) ?
@ -582,6 +508,8 @@ void DecoSchematic::blitToVManip(v3s16 p, ManualMapVoxelManipulator *vm,
int ystride = size.X; int ystride = size.X;
int zstride = size.X * size.Y; int zstride = size.X * size.Y;
updateContentIds();
s16 sx = size.X; s16 sx = size.X;
s16 sy = size.Y; s16 sy = size.Y;
s16 sz = size.Z; 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; content_t cignore = CONTENT_IGNORE;
bool have_cignore = false; bool have_cignore = false;
@ -730,7 +660,6 @@ bool DecoSchematic::loadSchematicFile() {
u16 nidmapcount = readU16(is); u16 nidmapcount = readU16(is);
node_names = new std::vector<std::string>;
for (int i = 0; i != nidmapcount; i++) { for (int i = 0; i != nidmapcount; i++) {
std::string name = deSerializeString(is); std::string name = deSerializeString(is);
if (name == "ignore") { if (name == "ignore") {
@ -738,7 +667,14 @@ bool DecoSchematic::loadSchematicFile() {
cignore = i; cignore = i;
have_cignore = true; 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; delete []schematic;

@ -50,6 +50,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define DECO_PLACE_CENTER_X 1 #define DECO_PLACE_CENTER_X 1
#define DECO_PLACE_CENTER_Y 2 #define DECO_PLACE_CENTER_Y 2
#define DECO_PLACE_CENTER_Z 4 #define DECO_PLACE_CENTER_Z 4
#define DECO_SCHEM_CIDS_UPDATED 8
#define ORE_RANGE_ACTUAL 1 #define ORE_RANGE_ACTUAL 1
#define ORE_RANGE_MIRROR 2 #define ORE_RANGE_MIRROR 2
@ -164,10 +165,8 @@ struct MapgenFactory {
class Ore { class Ore {
public: public:
std::string ore_name; content_t c_ore; // the node to place
std::vector<std::string> wherein_names; std::vector<content_t> c_wherein; // the nodes to be placed in
content_t ore;
std::vector<content_t> wherein; // the node to be replaced
u32 clust_scarcity; // ore cluster has a 1-in-clust_scarcity chance of appearing at a node 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_num_ores; // how many ore nodes are in a chunk
s16 clust_size; // how large (in nodes) a chunk of ore is s16 clust_size; // how large (in nodes) a chunk of ore is
@ -180,14 +179,13 @@ public:
Noise *noise; Noise *noise;
Ore() { Ore() {
ore = CONTENT_IGNORE; c_ore = CONTENT_IGNORE;
np = NULL; np = NULL;
noise = NULL; noise = NULL;
} }
virtual ~Ore(); virtual ~Ore();
void resolveNodeNames(INodeDefManager *ndef);
void placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax); void placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);
virtual void generate(ManualMapVoxelManipulator *vm, int seed, virtual void generate(ManualMapVoxelManipulator *vm, int seed,
u32 blockseed, v3s16 nmin, v3s16 nmax) = 0; u32 blockseed, v3s16 nmin, v3s16 nmax) = 0;
@ -234,8 +232,7 @@ public:
INodeDefManager *ndef; INodeDefManager *ndef;
int mapseed; int mapseed;
std::string place_on_name; std::vector<content_t> c_place_on;
content_t c_place_on;
s16 sidelen; s16 sidelen;
float fill_ratio; float fill_ratio;
NoiseParams *np; NoiseParams *np;
@ -247,7 +244,6 @@ public:
Decoration(); Decoration();
virtual ~Decoration(); virtual ~Decoration();
virtual void resolveNodeNames(INodeDefManager *ndef);
void placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax); void placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);
void placeCutoffs(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 { class DecoSimple : public Decoration {
public: public:
std::string deco_name; std::vector<content_t> c_decos;
std::string spawnby_name; std::vector<content_t> c_spawnby;
content_t c_deco;
content_t c_spawnby;
s16 deco_height; s16 deco_height;
s16 deco_height_max; s16 deco_height_max;
s16 nspawnby; s16 nspawnby;
std::vector<std::string> decolist_names;
std::vector<content_t> c_decolist;
~DecoSimple() {} ~DecoSimple() {}
void resolveNodeNames(INodeDefManager *ndef);
virtual void generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p); virtual void generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p);
virtual int getHeight(); virtual int getHeight();
virtual std::string getName(); virtual std::string getName();
@ -288,9 +278,7 @@ class DecoSchematic : public Decoration {
public: public:
std::string filename; std::string filename;
std::vector<std::string> *node_names;
std::vector<content_t> c_nodes; std::vector<content_t> c_nodes;
std::map<std::string, std::string> replacements;
u32 flags; u32 flags;
Rotation rotation; Rotation rotation;
@ -301,7 +289,7 @@ public:
DecoSchematic(); DecoSchematic();
~DecoSchematic(); ~DecoSchematic();
void resolveNodeNames(INodeDefManager *ndef); void updateContentIds();
virtual void generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p); virtual void generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p);
virtual int getHeight(); virtual int getHeight();
virtual std::string getName(); virtual std::string getName();
@ -309,7 +297,8 @@ public:
void blitToVManip(v3s16 p, ManualMapVoxelManipulator *vm, void blitToVManip(v3s16 p, ManualMapVoxelManipulator *vm,
Rotation rot, bool force_placement); Rotation rot, bool force_placement);
bool loadSchematicFile(); bool loadSchematicFile(NodeResolver *resolver,
std::map<std::string, std::string> &replace_names);
void saveSchematicFile(INodeDefManager *ndef); void saveSchematicFile(INodeDefManager *ndef);
bool getSchematicFromMap(Map *map, v3s16 p1, v3s16 p2); bool getSchematicFromMap(Map *map, v3s16 p1, v3s16 p2);

@ -402,6 +402,7 @@ public:
virtual void updateTextures(IGameDef *gamedef); virtual void updateTextures(IGameDef *gamedef);
void serialize(std::ostream &os, u16 protocol_version); void serialize(std::ostream &os, u16 protocol_version);
void deSerialize(std::istream &is); void deSerialize(std::istream &is);
virtual NodeResolver *getResolver();
private: private:
void addNameIdMapping(content_t i, std::string name); void addNameIdMapping(content_t i, std::string name);
@ -430,10 +431,14 @@ private:
// Next possibly free id // Next possibly free id
content_t m_next_id; content_t m_next_id;
// NodeResolver to queue pending node resolutions
NodeResolver m_resolver;
}; };
CNodeDefManager::CNodeDefManager() CNodeDefManager::CNodeDefManager() :
m_resolver(this)
{ {
clear(); clear();
} }
@ -1017,6 +1022,12 @@ void CNodeDefManager::addNameIdMapping(content_t i, std::string name)
} }
NodeResolver *CNodeDefManager::getResolver()
{
return &m_resolver;
}
IWritableNodeDefManager *createNodeDefManager() IWritableNodeDefManager *createNodeDefManager()
{ {
return new CNodeDefManager(); return new CNodeDefManager();
@ -1242,3 +1253,157 @@ void ContentFeatures::deSerializeOld(std::istream &is, int version)
throw SerializationError("unsupported ContentFeatures 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;
}

@ -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 class INodeDefManager
{ {
public: public:
@ -298,6 +332,8 @@ public:
virtual const ContentFeatures& get(const std::string &name) const=0; virtual const ContentFeatures& get(const std::string &name) const=0;
virtual void serialize(std::ostream &os, u16 protocol_version)=0; virtual void serialize(std::ostream &os, u16 protocol_version)=0;
virtual NodeResolver *getResolver()=0;
}; };
class IWritableNodeDefManager : public INodeDefManager class IWritableNodeDefManager : public INodeDefManager
@ -338,9 +374,11 @@ public:
virtual void serialize(std::ostream &os, u16 protocol_version)=0; virtual void serialize(std::ostream &os, u16 protocol_version)=0;
virtual void deSerialize(std::istream &is)=0; virtual void deSerialize(std::istream &is)=0;
virtual NodeResolver *getResolver()=0;
}; };
IWritableNodeDefManager* createNodeDefManager(); IWritableNodeDefManager *createNodeDefManager();
#endif #endif

@ -227,6 +227,25 @@ std::vector<aabb3f> read_aabb3f_vector(lua_State *L, int index, f32 scale)
return boxes; 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 Table field getters
*/ */
@ -287,6 +306,17 @@ bool getboolfield(lua_State *L, int table,
return got; 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, std::string checkstringfield(lua_State *L, int table,
const char *fieldname) const char *fieldname)
{ {

@ -37,7 +37,7 @@ extern "C" {
#include <lua.h> #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_); const char *fieldname, const std::string &default_);
bool getboolfield_default(lua_State *L, int table, bool getboolfield_default(lua_State *L, int table,
const char *fieldname, bool default_); const char *fieldname, bool default_);
@ -48,9 +48,12 @@ int getintfield_default (lua_State *L, int table,
bool getstringfield(lua_State *L, int table, bool getstringfield(lua_State *L, int table,
const char *fieldname, std::string &result); 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, bool getintfield(lua_State *L, int table,
const char *fieldname, int &result); 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); std::map<std::string, int> &result);
bool getboolfield(lua_State *L, int table, bool getboolfield(lua_State *L, int table,
const char *fieldname, bool &result); const char *fieldname, bool &result);
@ -79,8 +82,9 @@ v2s32 read_v2s32 (lua_State *L, int index);
video::SColor readARGB8 (lua_State *L, int index); video::SColor readARGB8 (lua_State *L, int index);
aabb3f read_aabb3f (lua_State *L, int index, f32 scale); aabb3f read_aabb3f (lua_State *L, int index, f32 scale);
v3s16 read_v3s16 (lua_State *L, int index); v3s16 read_v3s16 (lua_State *L, int index);
std::vector<aabb3f> std::vector<aabb3f> read_aabb3f_vector (lua_State *L, int index, f32 scale);
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 push_v3s16 (lua_State *L, v3s16 p);
void pushFloatPos (lua_State *L, v3f p); void pushFloatPos (lua_State *L, v3f p);

@ -80,17 +80,19 @@ 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); lua_pushnil(L);
while (lua_next(L, index)) { while (lua_next(L, index)) {
// key at index -2 and value at index -1
std::string replace_from; std::string replace_from;
std::string replace_to; 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); lua_rawgeti(L, -1, 1);
replace_from = lua_tostring(L, -1); replace_from = lua_tostring(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
lua_rawgeti(L, -1, 2); lua_rawgeti(L, -1, 2);
replace_to = lua_tostring(L, -1); replace_to = lua_tostring(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
@ -98,8 +100,8 @@ static void read_schematic_replacements(lua_State *L, DecoSchematic *dschem, int
replace_from = lua_tostring(L, -2); replace_from = lua_tostring(L, -2);
replace_to = lua_tostring(L, -1); 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); lua_pop(L, 1);
} }
} }
@ -298,6 +300,7 @@ int ModApiMapgen::l_register_biome(lua_State *L)
int index = 1; int index = 1;
luaL_checktype(L, index, LUA_TTABLE); luaL_checktype(L, index, LUA_TTABLE);
NodeResolver *resolver = getServer(L)->getNodeDefManager()->getResolver();
BiomeDefManager *bmgr = getServer(L)->getEmergeManager()->biomedef; BiomeDefManager *bmgr = getServer(L)->getEmergeManager()->biomedef;
if (!bmgr) { if (!bmgr) {
verbosestream << "register_biome: BiomeDefManager not active" << std::endl; verbosestream << "register_biome: BiomeDefManager not active" << std::endl;
@ -308,32 +311,25 @@ int ModApiMapgen::l_register_biome(lua_State *L)
"terrain_type", es_BiomeTerrainType, BIOME_TERRAIN_NORMAL); "terrain_type", es_BiomeTerrainType, BIOME_TERRAIN_NORMAL);
Biome *b = bmgr->createBiome(terrain); Biome *b = bmgr->createBiome(terrain);
b->name = getstringfield_default(L, index, "name", resolver->addNode(getstringfield_default(L, index, "node_top", ""),
"<no name>"); "mapgen_dirt_with_grass", CONTENT_AIR, &b->c_top);
b->nname_top = getstringfield_default(L, index, "node_top", resolver->addNode(getstringfield_default(L, index, "node_filler", ""),
"mapgen_dirt_with_grass"); "mapgen_dirt", CONTENT_AIR, &b->c_filler);
b->nname_filler = getstringfield_default(L, index, "node_filler", resolver->addNode(getstringfield_default(L, index, "node_water", ""),
"mapgen_dirt"); "mapgen_water_source", CONTENT_AIR, &b->c_water);
b->nname_water = getstringfield_default(L, index, "node_water", resolver->addNode(getstringfield_default(L, index, "node_dust", ""),
"mapgen_water_source"); "air", CONTENT_IGNORE, &b->c_dust);
b->nname_dust = getstringfield_default(L, index, "node_dust", resolver->addNode(getstringfield_default(L, index, "node_dust_water", ""),
"air"); "mapgen_water_source", CONTENT_IGNORE, &b->c_dust_water);
b->nname_dust_water = getstringfield_default(L, index, "node_dust_water",
"mapgen_water_source");
b->name = getstringfield_default(L, index, "name", "<no name>");
b->depth_top = getintfield_default(L, index, "depth_top", 1); b->depth_top = getintfield_default(L, index, "depth_top", 1);
b->depth_filler = getintfield_default(L, index, "depth_filler", 3); b->depth_filler = getintfield_default(L, index, "depth_filler", 3);
b->height_min = getintfield_default(L, index, "height_min", 0); b->height_min = getintfield_default(L, index, "height_min", 0);
b->height_max = getintfield_default(L, index, "height_max", 0); b->height_max = getintfield_default(L, index, "height_max", 0);
b->heat_point = getfloatfield_default(L, index, "heat_point", 0.); b->heat_point = getfloatfield_default(L, index, "heat_point", 0.);
b->humidity_point = getfloatfield_default(L, index, "humidity_point", 0.); b->humidity_point = getfloatfield_default(L, index, "humidity_point", 0.);
b->flags = 0; //reserved 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;
verbosestream << "register_biome: " << b->name << std::endl; verbosestream << "register_biome: " << b->name << std::endl;
bmgr->addBiome(b); bmgr->addBiome(b);
@ -349,6 +345,7 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
EmergeManager *emerge = getServer(L)->getEmergeManager(); EmergeManager *emerge = getServer(L)->getEmergeManager();
BiomeDefManager *bdef = emerge->biomedef; BiomeDefManager *bdef = emerge->biomedef;
NodeResolver *resolver = getServer(L)->getNodeDefManager()->getResolver();
enum DecorationType decotype = (DecorationType)getenumfield(L, index, enum DecorationType decotype = (DecorationType)getenumfield(L, index,
"deco_type", es_DecorationType, 0); "deco_type", es_DecorationType, 0);
@ -365,8 +362,6 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
return 0; 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->fill_ratio = getfloatfield_default(L, index, "fill_ratio", 0.02);
deco->sidelen = getintfield_default(L, index, "sidelen", 8); deco->sidelen = getintfield_default(L, index, "sidelen", 8);
if (deco->sidelen <= 0) { if (deco->sidelen <= 0) {
@ -376,51 +371,35 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
return 0; 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"); lua_getfield(L, index, "noise_params");
deco->np = read_noiseparams(L, -1); deco->np = read_noiseparams(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
lua_getfield(L, index, "biomes"); //// Get biomes associated with this decoration (if any)
if (lua_istable(L, -1)) { std::vector<const char *> biome_list;
lua_pushnil(L); getstringlistfield(L, index, "biomes", biome_list);
while (lua_next(L, -2)) { for (size_t i = 0; i != biome_list.size(); i++) {
const char *s = lua_tostring(L, -1); u8 biomeid = bdef->getBiomeIdByName(biome_list[i]);
u8 biomeid = bdef->getBiomeIdByName(s);
if (biomeid) if (biomeid)
deco->biomes.insert(biomeid); deco->biomes.insert(biomeid);
lua_pop(L, 1);
}
lua_pop(L, 1);
} }
//// Handle decoration type-specific parameters
switch (decotype) { switch (decotype) {
case DECO_SIMPLE: { case DECO_SIMPLE: {
DecoSimple *dsimple = (DecoSimple *)deco; 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 = getintfield_default(L, index, "height", 1);
dsimple->deco_height_max = getintfield_default(L, index, "height_max", 0); dsimple->deco_height_max = getintfield_default(L, index, "height_max", 0);
dsimple->nspawnby = getintfield_default(L, index, "num_spawn_by", -1); 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) { if (dsimple->deco_height <= 0) {
errorstream << "register_decoration: simple decoration height" errorstream << "register_decoration: simple decoration height"
" must be greater than 0" << std::endl; " must be greater than 0" << std::endl;
@ -428,7 +407,31 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
return 0; 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: { case DECO_SCHEMATIC: {
DecoSchematic *dschem = (DecoSchematic *)deco; DecoSchematic *dschem = (DecoSchematic *)deco;
@ -439,10 +442,10 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
dschem->rotation = (Rotation)getenumfield(L, index, dschem->rotation = (Rotation)getenumfield(L, index,
"rotation", es_Rotation, ROTATE_0); "rotation", es_Rotation, ROTATE_0);
std::map<std::string, std::string> replace_names;
lua_getfield(L, index, "replacements"); lua_getfield(L, index, "replacements");
if (lua_istable(L, -1)) { if (lua_istable(L, -1))
read_schematic_replacements(L, dschem, lua_gettop(L)); read_schematic_replacements(L, replace_names, lua_gettop(L));
}
lua_pop(L, 1); lua_pop(L, 1);
lua_getfield(L, index, "schematic"); lua_getfield(L, index, "schematic");
@ -452,17 +455,20 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
} }
lua_pop(L, -1); lua_pop(L, -1);
if (!dschem->filename.empty() && !dschem->loadSchematicFile()) { if (!dschem->filename.empty() &&
errorstream << "register_decoration: failed to load schematic file '" !dschem->loadSchematicFile(resolver, replace_names)) {
<< dschem->filename << "'" << std::endl; errorstream << "register_decoration: failed to load schematic"
" file '" << dschem->filename << "'" << std::endl;
delete dschem; delete dschem;
return 0; return 0;
} }
break; }
break;
}
case DECO_LSYSTEM: { case DECO_LSYSTEM: {
//DecoLSystem *decolsystem = (DecoLSystem *)deco; //DecoLSystem *decolsystem = (DecoLSystem *)deco;
break;
break; } }
} }
emerge->decorations.push_back(deco); emerge->decorations.push_back(deco);
@ -479,6 +485,7 @@ int ModApiMapgen::l_register_ore(lua_State *L)
luaL_checktype(L, index, LUA_TTABLE); 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, enum OreType oretype = (OreType)getenumfield(L, index,
"ore_type", es_OreType, ORE_SCATTER); "ore_type", es_OreType, ORE_SCATTER);
@ -489,7 +496,9 @@ int ModApiMapgen::l_register_ore(lua_State *L)
return 0; 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->ore_param2 = (u8)getintfield_default(L, index, "ore_param2", 0);
ore->clust_scarcity = getintfield_default(L, index, "clust_scarcity", 1); ore->clust_scarcity = getintfield_default(L, index, "clust_scarcity", 1);
ore->clust_num_ores = getintfield_default(L, index, "clust_num_ores", 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; ore->flags = 0;
getflagsfield(L, index, "flags", flagdesc_ore, &ore->flags, NULL); getflagsfield(L, index, "flags", flagdesc_ore, &ore->flags, NULL);
lua_getfield(L, index, "wherein"); std::vector<const char *> wherein_names;
if (lua_istable(L, -1)) { getstringlistfield(L, index, "wherein", wherein_names);
int i = lua_gettop(L); for (size_t i = 0; i != wherein_names.size(); i++)
lua_pushnil(L); resolver->addNodeList(wherein_names[i], &ore->c_wherein);
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);
lua_getfield(L, index, "noise_params"); lua_getfield(L, index, "noise_params");
ore->np = read_noiseparams(L, -1); ore->np = read_noiseparams(L, -1);
@ -530,8 +529,8 @@ int ModApiMapgen::l_register_ore(lua_State *L)
emerge->ores.push_back(ore); emerge->ores.push_back(ore);
verbosestream << "register_ore: ore '" << ore->ore_name //verbosestream << "register_ore: ore '" << ore->ore_name
<< "' registered" << std::endl; // << "' registered" << std::endl;
return 0; return 0;
} }
@ -603,7 +602,7 @@ int ModApiMapgen::l_place_schematic(lua_State *L)
DecoSchematic dschem; DecoSchematic dschem;
Map *map = &(getEnv(L)->getMap()); Map *map = &(getEnv(L)->getMap());
INodeDefManager *ndef = getServer(L)->getNodeDefManager(); NodeResolver *resolver = getServer(L)->getNodeDefManager()->getResolver();
v3s16 p = read_v3s16(L, 1); v3s16 p = read_v3s16(L, 1);
if (!read_schematic(L, 2, &dschem, getServer(L))) if (!read_schematic(L, 2, &dschem, getServer(L)))
@ -615,21 +614,20 @@ int ModApiMapgen::l_place_schematic(lua_State *L)
dschem.rotation = (Rotation)rot; dschem.rotation = (Rotation)rot;
if (lua_istable(L, 4)) { std::map<std::string, std::string> replace_names;
read_schematic_replacements(L, &dschem, 4); if (lua_istable(L, 4))
} read_schematic_replacements(L, replace_names, 4);
bool force_placement = true; bool force_placement = true;
if (lua_isboolean(L, 5)) if (lua_isboolean(L, 5))
force_placement = lua_toboolean(L, 5); force_placement = lua_toboolean(L, 5);
if (!dschem.filename.empty()) { if (!dschem.filename.empty()) {
if (!dschem.loadSchematicFile()) { if (!dschem.loadSchematicFile(resolver, replace_names)) {
errorstream << "place_schematic: failed to load schematic file '" errorstream << "place_schematic: failed to load schematic file '"
<< dschem.filename << "'" << std::endl; << dschem.filename << "'" << std::endl;
return 0; return 0;
} }
dschem.resolveNodeNames(ndef);
} }
dschem.placeStructure(map, p, force_placement); dschem.placeStructure(map, p, force_placement);

@ -338,6 +338,9 @@ Server::Server(
// Apply item aliases in the node definition manager // Apply item aliases in the node definition manager
m_nodedef->updateAliases(m_itemdef); m_nodedef->updateAliases(m_itemdef);
// Perform pending node name resolutions
m_nodedef->getResolver()->resolveNodes();
// Load the mapgen params from global settings now after any // Load the mapgen params from global settings now after any
// initial overrides have been set by the mods // initial overrides have been set by the mods
m_emerge->loadMapgenParams(); m_emerge->loadMapgenParams();