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 <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::iterator iter = mglist.begin(); - iter != mglist.end(); iter ++) { - delete iter->second; + for (std::map::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()) +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::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 &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; 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::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 wherein_names; - content_t ore; - std::vector wherein; // the node to be replaced + content_t c_ore; // the node to place + std::vector 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 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 c_decos; + std::vector c_spawnby; s16 deco_height; s16 deco_height_max; s16 nspawnby; - std::vector decolist_names; - std::vector 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 *node_names; std::vector c_nodes; - std::map 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 &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_vec) +{ + if (m_is_node_registration_complete) { + std::set idset; + std::set::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::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_vec) +{ + int num_canceled = 0; + + std::list *> >::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 *> item = + m_pending_content_vecs.front(); + m_pending_content_vecs.pop_front(); + + std::string &name = item.first; + std::vector *output = item.second; + + std::set idset; + std::set::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_vec); + + bool cancelNode(content_t *content); + int cancelNodeList(std::vector *content_vec); + + int resolveNodes(); + + bool isNodeRegFinished() { return m_is_node_registration_complete; } + +private: + INodeDefManager *m_ndef; + bool m_is_node_registration_complete; + std::list m_pending_contents; + std::list *> > 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 read_aabb3f_vector(lua_State *L, int index, f32 scale) return boxes; } +bool read_stringlist(lua_State *L, int index, std::vector &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 &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 } -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 &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 &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 - 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 read_aabb3f_vector (lua_State *L, int index, f32 scale); +bool read_stringlist (lua_State *L, int index, + std::vector &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 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", - ""); - 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", ""); 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 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 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 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 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 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 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 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();