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);
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;
}

@ -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);

@ -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) {

@ -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())
void DecoSchematic::updateContentIds() {
if (flags & DECO_SCHEM_CIDS_UPDATED)
return;
if (!node_names) {
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);
}
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;

@ -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);

@ -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;
}

@ -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

@ -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)
{

@ -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);

@ -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);

@ -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();