Redefine NodeResolver interface and replace with callback mechanism

This commit is contained in:
kwolekr 2014-12-17 03:20:17 -05:00
parent 3ea5ed4ffe
commit b67f37f27e
16 changed files with 278 additions and 364 deletions

@ -384,7 +384,7 @@ void GenerateNotifier::getEvents(
GenElementManager::GenElementManager(IGameDef *gamedef) GenElementManager::GenElementManager(IGameDef *gamedef)
{ {
m_resolver = gamedef->getNodeDefManager()->getResolver(); m_ndef = gamedef->getNodeDefManager();
} }

@ -192,7 +192,7 @@ public:
virtual GenElement *getByName(const std::string &name); virtual GenElement *getByName(const std::string &name);
protected: protected:
NodeResolver *m_resolver; INodeDefManager *m_ndef;
std::vector<GenElement *> m_elements; std::vector<GenElement *> m_elements;
}; };

@ -48,12 +48,14 @@ BiomeManager::BiomeManager(IGameDef *gamedef) :
b->heat_point = 0.0; b->heat_point = 0.0;
b->humidity_point = 0.0; b->humidity_point = 0.0;
m_resolver->addNode("air", "", CONTENT_AIR, &b->c_top); NodeResolveInfo *nri = new NodeResolveInfo(b);
m_resolver->addNode("air", "", CONTENT_AIR, &b->c_filler); nri->nodenames.push_back("air");
m_resolver->addNode("mapgen_stone", "", CONTENT_AIR, &b->c_stone); nri->nodenames.push_back("air");
m_resolver->addNode("mapgen_water_source", "", CONTENT_AIR, &b->c_water); nri->nodenames.push_back("mapgen_stone");
m_resolver->addNode("air", "", CONTENT_AIR, &b->c_dust); nri->nodenames.push_back("mapgen_water_source");
m_resolver->addNode("mapgen_water_source", "", CONTENT_AIR, &b->c_dust_water); nri->nodenames.push_back("air");
nri->nodenames.push_back("mapgen_water_source");
m_ndef->pendNodeResolve(nri);
add(b); add(b);
} }
@ -102,18 +104,26 @@ Biome *BiomeManager::getBiome(float heat, float humidity, s16 y)
void BiomeManager::clear() void BiomeManager::clear()
{ {
for (size_t i = 1; i < m_elements.size(); i++) { for (size_t i = 1; i < m_elements.size(); i++) {
Biome *b = (Biome *)m_elements[i]; Biome *b = (Biome *)m_elements[i];
if (!b) delete b;
continue;
m_resolver->cancelNode(&b->c_top);
m_resolver->cancelNode(&b->c_filler);
m_resolver->cancelNode(&b->c_stone);
m_resolver->cancelNode(&b->c_water);
m_resolver->cancelNode(&b->c_dust);
m_resolver->cancelNode(&b->c_dust_water);
} }
m_elements.resize(1); m_elements.resize(1);
} }
///////////////////////////////////////////////////////////////////////////////
void Biome::resolveNodeNames(NodeResolveInfo *nri)
{
m_ndef->getIdFromResolveInfo(nri, "mapgen_dirt_with_grass", CONTENT_AIR, c_top);
m_ndef->getIdFromResolveInfo(nri, "mapgen_dirt", CONTENT_AIR, c_filler);
m_ndef->getIdFromResolveInfo(nri, "mapgen_stone", CONTENT_AIR, c_stone);
m_ndef->getIdFromResolveInfo(nri, "mapgen_water_source", CONTENT_AIR, c_water);
m_ndef->getIdFromResolveInfo(nri, "air", CONTENT_IGNORE, c_dust);
m_ndef->getIdFromResolveInfo(nri, "mapgen_water_source", CONTENT_IGNORE, c_dust_water);
}

@ -33,7 +33,7 @@ enum BiomeType
BIOME_TYPE_FLAT BIOME_TYPE_FLAT
}; };
class Biome : public GenElement { class Biome : public GenElement, public NodeResolver {
public: public:
u32 flags; u32 flags;
@ -51,6 +51,8 @@ public:
s16 height_max; s16 height_max;
float heat_point; float heat_point;
float humidity_point; float humidity_point;
virtual void resolveNodeNames(NodeResolveInfo *nri);
}; };
class BiomeManager : public GenElementManager { class BiomeManager : public GenElementManager {

@ -65,10 +65,7 @@ void DecorationManager::clear()
{ {
for (size_t i = 0; i < m_elements.size(); i++) { for (size_t i = 0; i < m_elements.size(); i++) {
Decoration *deco = (Decoration *)m_elements[i]; Decoration *deco = (Decoration *)m_elements[i];
if (!deco) delete deco;
continue;
deco->dropResolverEntries(m_resolver);
} }
m_elements.clear(); m_elements.clear();
} }
@ -91,6 +88,12 @@ Decoration::~Decoration()
} }
void Decoration::resolveNodeNames(NodeResolveInfo *nri)
{
m_ndef->getIdsFromResolveInfo(nri, c_place_on);
}
size_t Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) size_t Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
{ {
PseudoRandom ps(blockseed + 53); PseudoRandom ps(blockseed + 53);
@ -229,6 +232,14 @@ void Decoration::placeCutoffs(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
void DecoSimple::resolveNodeNames(NodeResolveInfo *nri)
{
Decoration::resolveNodeNames(nri);
m_ndef->getIdsFromResolveInfo(nri, c_decos);
m_ndef->getIdsFromResolveInfo(nri, c_spawnby);
}
bool DecoSimple::canPlaceDecoration(ManualMapVoxelManipulator *vm, v3s16 p) bool DecoSimple::canPlaceDecoration(ManualMapVoxelManipulator *vm, v3s16 p)
{ {
// Don't bother if there aren't any decorations to place // Don't bother if there aren't any decorations to place
@ -310,13 +321,6 @@ int DecoSimple::getHeight()
} }
void DecoSimple::dropResolverEntries(NodeResolver *resolver)
{
resolver->cancelNodeList(&c_decos);
resolver->cancelNodeList(&c_spawnby);
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

@ -58,7 +58,7 @@ struct CutoffData {
}; };
#endif #endif
class Decoration : public GenElement { class Decoration : public GenElement, public NodeResolver {
public: public:
INodeDefManager *ndef; INodeDefManager *ndef;
@ -76,12 +76,13 @@ public:
Decoration(); Decoration();
virtual ~Decoration(); virtual ~Decoration();
virtual void resolveNodeNames(NodeResolveInfo *nri);
size_t placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax); size_t placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);
size_t placeCutoffs(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax); size_t placeCutoffs(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);
virtual size_t generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p) = 0; virtual size_t generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p) = 0;
virtual int getHeight() = 0; virtual int getHeight() = 0;
virtual void dropResolverEntries(NodeResolver *resolver) {}
}; };
class DecoSimple : public Decoration { class DecoSimple : public Decoration {
@ -92,12 +93,11 @@ public:
s16 deco_height_max; s16 deco_height_max;
s16 nspawnby; s16 nspawnby;
~DecoSimple() {} virtual void resolveNodeNames(NodeResolveInfo *nri);
bool canPlaceDecoration(ManualMapVoxelManipulator *vm, v3s16 p); bool canPlaceDecoration(ManualMapVoxelManipulator *vm, v3s16 p);
virtual size_t generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p); virtual size_t generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p);
virtual int getHeight(); virtual int getHeight();
virtual void dropResolverEntries(NodeResolver *resolver);
}; };
class DecoSchematic : public Decoration { class DecoSchematic : public Decoration {
@ -106,8 +106,6 @@ public:
Schematic *schematic; Schematic *schematic;
std::string filename; std::string filename;
~DecoSchematic() {}
virtual size_t generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p); virtual size_t generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p);
virtual int getHeight(); virtual int getHeight();
}; };

@ -64,11 +64,7 @@ void OreManager::clear()
{ {
for (size_t i = 0; i < m_elements.size(); i++) { for (size_t i = 0; i < m_elements.size(); i++) {
Ore *ore = (Ore *)m_elements[i]; Ore *ore = (Ore *)m_elements[i];
if (!ore) delete ore;
continue;
m_resolver->cancelNodeList(&ore->c_wherein);
m_resolver->cancelNode(&ore->c_ore);
} }
m_elements.clear(); m_elements.clear();
} }
@ -84,6 +80,19 @@ Ore::Ore()
} }
Ore::~Ore()
{
delete noise;
}
void Ore::resolveNodeNames(NodeResolveInfo *nri)
{
m_ndef->getIdFromResolveInfo(nri, "", CONTENT_AIR, c_ore);
m_ndef->getIdsFromResolveInfo(nri, c_wherein);
}
size_t Ore::placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) size_t Ore::placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
{ {
int in_range = 0; int in_range = 0;
@ -113,6 +122,9 @@ size_t 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)
{ {
@ -151,6 +163,9 @@ 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)
{ {

@ -54,7 +54,7 @@ enum OreType {
extern FlagDesc flagdesc_ore[]; extern FlagDesc flagdesc_ore[];
class Ore : public GenElement { class Ore : public GenElement, public NodeResolver {
public: public:
static const bool NEEDS_NOISE = false; static const bool NEEDS_NOISE = false;
@ -72,6 +72,9 @@ public:
Noise *noise; Noise *noise;
Ore(); Ore();
virtual ~Ore();
virtual void resolveNodeNames(NodeResolveInfo *nri);
size_t placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax); size_t placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);
virtual void generate(ManualMapVoxelManipulator *vm, int seed, virtual void generate(ManualMapVoxelManipulator *vm, int seed,

@ -58,6 +58,12 @@ Schematic::~Schematic()
} }
void Schematic::resolveNodeNames(NodeResolveInfo *nri)
{
m_ndef->getIdsFromResolveInfo(nri, c_nodes);
}
void Schematic::updateContentIds() void Schematic::updateContentIds()
{ {
if (flags & SCHEM_CIDS_UPDATED) if (flags & SCHEM_CIDS_UPDATED)
@ -195,8 +201,7 @@ void Schematic::placeStructure(Map *map, v3s16 p, u32 flags,
bool Schematic::loadSchematicFromFile(const char *filename, bool Schematic::loadSchematicFromFile(const char *filename,
NodeResolver *resolver, INodeDefManager *ndef, std::map<std::string, std::string> &replace_names)
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;
@ -224,10 +229,9 @@ bool Schematic::loadSchematicFromFile(const char *filename,
for (int y = 0; y != size.Y; y++) for (int y = 0; y != size.Y; y++)
slice_probs[y] = (version >= 3) ? readU8(is) : MTSCHEM_PROB_ALWAYS; slice_probs[y] = (version >= 3) ? readU8(is) : MTSCHEM_PROB_ALWAYS;
int nodecount = size.X * size.Y * size.Z; NodeResolveInfo *nri = new NodeResolveInfo(this);
u16 nidmapcount = readU16(is); u16 nidmapcount = readU16(is);
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") {
@ -241,16 +245,22 @@ bool Schematic::loadSchematicFromFile(const char *filename,
if (it != replace_names.end()) if (it != replace_names.end())
name = it->second; name = it->second;
resolver->addNodeList(name.c_str(), &c_nodes); nri->nodenames.push_back(name);
} }
nri->nodename_sizes.push_back(nidmapcount);
ndef->pendNodeResolve(nri);
size_t nodecount = size.X * size.Y * size.Z;
delete []schemdata; delete []schemdata;
schemdata = new MapNode[nodecount]; schemdata = new MapNode[nodecount];
MapNode::deSerializeBulk(is, SER_FMT_VER_HIGHEST_READ, schemdata, MapNode::deSerializeBulk(is, SER_FMT_VER_HIGHEST_READ, schemdata,
nodecount, 2, 2, true); nodecount, 2, 2, true);
if (version == 1) { // fix up the probability values if (version == 1) { // fix up the probability values
for (int i = 0; i != nodecount; i++) { for (size_t i = 0; i != nodecount; i++) {
if (schemdata[i].param1 == 0) if (schemdata[i].param1 == 0)
schemdata[i].param1 = MTSCHEM_PROB_ALWAYS; schemdata[i].param1 = MTSCHEM_PROB_ALWAYS;
if (have_cignore && schemdata[i].getContent() == cignore) if (have_cignore && schemdata[i].getContent() == cignore)

@ -42,7 +42,7 @@ class NodeResolver;
#define MTSCHEM_PROB_ALWAYS 0xFF #define MTSCHEM_PROB_ALWAYS 0xFF
class Schematic : public GenElement { class Schematic : public GenElement, public NodeResolver {
public: public:
std::vector<content_t> c_nodes; std::vector<content_t> c_nodes;
@ -52,14 +52,16 @@ public:
u8 *slice_probs; u8 *slice_probs;
Schematic(); Schematic();
~Schematic(); virtual ~Schematic();
virtual void resolveNodeNames(NodeResolveInfo *nri);
void updateContentIds(); void updateContentIds();
void blitToVManip(v3s16 p, ManualMapVoxelManipulator *vm, void blitToVManip(v3s16 p, ManualMapVoxelManipulator *vm,
Rotation rot, bool force_placement, INodeDefManager *ndef); Rotation rot, bool force_placement, INodeDefManager *ndef);
bool loadSchematicFromFile(const char *filename, NodeResolver *resolver, bool loadSchematicFromFile(const char *filename, INodeDefManager *ndef,
std::map<std::string, std::string> &replace_names); std::map<std::string, std::string> &replace_names);
void saveSchematicToFile(const char *filename, INodeDefManager *ndef); void saveSchematicToFile(const char *filename, INodeDefManager *ndef);
bool getSchematicFromMap(Map *map, v3s16 p1, v3s16 p2); bool getSchematicFromMap(Map *map, v3s16 p1, v3s16 p2);
@ -86,7 +88,7 @@ public:
}; };
void build_nnlist_and_update_ids(MapNode *nodes, u32 nodecount, void build_nnlist_and_update_ids(MapNode *nodes, u32 nodecount,
std::vector<content_t> *usednodes); std::vector<content_t> *usednodes);
#endif #endif

@ -402,7 +402,15 @@ 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();
virtual void pendNodeResolve(NodeResolveInfo *nri);
virtual void cancelNodeResolve(NodeResolver *resolver);
virtual void runNodeResolverCallbacks();
virtual bool getIdFromResolveInfo(NodeResolveInfo *nri,
const std::string &node_alt, content_t c_fallback, content_t &result);
virtual bool getIdsFromResolveInfo(NodeResolveInfo *nri,
std::vector<content_t> &result);
private: private:
void addNameIdMapping(content_t i, std::string name); void addNameIdMapping(content_t i, std::string name);
@ -432,13 +440,12 @@ 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 // List of node strings and node resolver callbacks to perform
NodeResolver m_resolver; std::list<NodeResolveInfo *> m_pending_node_lookups;
}; };
CNodeDefManager::CNodeDefManager() : CNodeDefManager::CNodeDefManager()
m_resolver(this)
{ {
clear(); clear();
} }
@ -1035,12 +1042,6 @@ 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();
@ -1267,166 +1268,100 @@ void ContentFeatures::deSerializeOld(std::istream &is, int version)
} }
} }
/*
NodeResolver
*/
NodeResolver::NodeResolver(INodeDefManager *ndef) void CNodeDefManager::pendNodeResolve(NodeResolveInfo *nri)
{ {
m_ndef = ndef; nri->resolver->m_ndef = this;
m_is_node_registration_complete = false; m_pending_node_lookups.push_back(nri);
} }
NodeResolver::~NodeResolver() void CNodeDefManager::cancelNodeResolve(NodeResolver *resolver)
{ {
while (!m_pending_contents.empty()) {
NodeResolveInfo *nri = m_pending_contents.front();
m_pending_contents.pop_front();
delete nri;
}
}
int NodeResolver::addNode(const std::string &n_wanted, const 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 == "" || !m_ndef->getId(n_alt, *content)) {
*content = c_fallback;
return NR_STATUS_FAILURE;
}
return NR_STATUS_SUCCESS;
} 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 std::string &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(nodename, content_vec));
return NR_STATUS_PENDING;
}
}
bool NodeResolver::cancelNode(content_t *content)
{
bool found = false;
for (std::list<NodeResolveInfo *>::iterator for (std::list<NodeResolveInfo *>::iterator
it = m_pending_contents.begin(); it = m_pending_node_lookups.begin();
it != m_pending_contents.end(); it != m_pending_node_lookups.end();
++it) { ++it) {
NodeResolveInfo *nfi = *it; NodeResolveInfo *nri = *it;
if (nfi->output == content) { if (resolver == nri->resolver) {
it = m_pending_contents.erase(it); it = m_pending_node_lookups.erase(it);
delete nfi; delete nri;
found = true;
} }
} }
return found;
} }
int NodeResolver::cancelNodeList(std::vector<content_t> *content_vec) void CNodeDefManager::runNodeResolverCallbacks()
{ {
int num_canceled = 0; while (!m_pending_node_lookups.empty()) {
NodeResolveInfo *nri = m_pending_node_lookups.front();
for (ContentVectorResolveList::iterator m_pending_node_lookups.pop_front();
it = m_pending_content_vecs.begin(); nri->resolver->resolveNodeNames(nri);
it != m_pending_content_vecs.end(); nri->resolver->m_lookup_done = true;
++it) {
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 << "'" << std::endl;
}
delete nri; 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; bool CNodeDefManager::getIdFromResolveInfo(NodeResolveInfo *nri,
std::vector<content_t> *output = item.second; const std::string &node_alt, content_t c_fallback, content_t &result)
{
std::set<content_t> idset; if (nri->nodenames.empty()) {
std::set<content_t>::iterator it; result = c_fallback;
errorstream << "CNodeDefManager::getIdFromResolveInfo: empty "
m_ndef->getIds(name, idset); "nodenames list" << std::endl;
for (it = idset.begin(); it != idset.end(); ++it) return false;
output->push_back(*it);
if (idset.empty()) {
num_failed++;
errorstream << "NodeResolver::resolveNodes(): Failed to "
"resolve '" << name << "'" << std::endl;
}
} }
//// Mark node registration as complete so future resolve content_t c;
//// requests are satisfied immediately std::string name = nri->nodenames.front();
m_is_node_registration_complete = true; nri->nodenames.pop_front();
return num_failed; bool success = getId(name, c);
if (!success && node_alt != "") {
name = node_alt;
success = getId(name, c);
}
if (!success) {
errorstream << "CNodeDefManager::getIdFromResolveInfo: Failed to "
"resolve node name '" << name << "'." << std::endl;
c = c_fallback;
}
result = c;
return success;
}
bool CNodeDefManager::getIdsFromResolveInfo(NodeResolveInfo *nri,
std::vector<content_t> &result)
{
if (nri->nodename_sizes.empty()) {
errorstream << "CNodeDefManager::getIdsFromResolveInfo: empty "
"nodename_sizes list" << std::endl;
return false;
}
size_t nitems = nri->nodename_sizes.front();
nri->nodename_sizes.pop_front();
while (nitems--) {
if (nri->nodenames.empty()) {
errorstream << "" << std::endl;
return false;
}
content_t c;
if (getId(nri->nodenames.front(), c)) {
result.push_back(c);
} else {
errorstream << "CNodeDefManager::getIdsFromResolveInfo: empty "
"nodenames list" << std::endl;
}
nri->nodenames.pop_front();
}
return true;
} }

@ -40,8 +40,6 @@ class IShaderSource;
class IGameDef; class IGameDef;
typedef std::list<std::pair<content_t, int> > GroupItems; typedef std::list<std::pair<content_t, int> > GroupItems;
typedef std::list<std::pair<std::string, std::vector<content_t> *> >
ContentVectorResolveList;
enum ContentParamType enum ContentParamType
{ {
@ -284,125 +282,18 @@ struct ContentFeatures
} }
}; };
class NodeResolver;
class INodeDefManager;
struct NodeResolveInfo { struct NodeResolveInfo {
std::string n_wanted; NodeResolveInfo(NodeResolver *nr)
std::string n_alt; {
content_t c_fallback; resolver = nr;
content_t *output; }
};
#define NR_STATUS_FAILURE 0 std::list<std::string> nodenames;
#define NR_STATUS_PENDING 1 std::list<size_t> nodename_sizes;
#define NR_STATUS_SUCCESS 2 NodeResolver *resolver;
/**
NodeResolver
NodeResolver attempts to resolve node names to content ID integers. If the
node registration phase has not yet finished at the time the resolution
request is placed, the request is marked as pending and added to an internal
queue. The name resolution request is later satisfied by writing directly
to the output location when the node registration phase has been completed.
This is primarily intended to be used for objects registered during script
initialization (i.e. while nodes are being registered) that reference
particular nodes.
*/
class NodeResolver {
public:
NodeResolver(INodeDefManager *ndef);
~NodeResolver();
/**
Add a request to resolve the node n_wanted and set *content to the
result, or alternatively, n_alt if n_wanted is not found. If n_alt
cannot be found either, or has not been specified, *content is set
to c_fallback.
If node registration is complete, the request is finished immediately
and NR_STATUS_SUCCESS is returned (or NR_STATUS_FAILURE if no node can
be found). Otherwise, NR_STATUS_PENDING is returned and the resolution
request is queued.
N.B. If the memory in which content is located has been deallocated
before the pending request had been satisfied, cancelNode() must be
called.
@param n_wanted Name of node that is wanted.
@param n_alt Name of node in case n_wanted could not be found. Blank
if no alternative node is desired.
@param c_fallback Content ID that content is set to in case of node
resolution failure (should be CONTENT_AIR, CONTENT_IGNORE, etc.)
@param content Pointer to content_t that receives the result of the
node name resolution.
@return Status of node resolution request.
*/
int addNode(const std::string &n_wanted, const std::string &n_alt,
content_t c_fallback, content_t *content);
/**
Add a request to resolve the node(s) specified by nodename.
If node registration is complete, the request is finished immediately
and NR_STATUS_SUCCESS is returned if at least one node is resolved; if
zero were resolved, NR_STATUS_FAILURE. Otherwise, NR_STATUS_PENDING is
returned and the resolution request is queued.
N.B. If the memory in which content_vec is located has been deallocated
before the pending request had been satisfied, cancelNodeList() must be
called.
@param nodename Name of node (or node group) to be resolved.
@param content_vec Pointer to content_t vector onto which the results
are added.
@return Status of node resolution request.
*/
int addNodeList(const std::string &nodename,
std::vector<content_t> *content_vec);
/**
Removes all pending requests from the resolution queue with the output
address of 'content'.
@param content Location of the content ID for the request being
cancelled.
@return Number of pending requests cancelled.
*/
bool cancelNode(content_t *content);
/**
Removes all pending requests from the resolution queue with the output
address of 'content_vec'.
@param content_vec Location of the content ID vector for requests being
cancelled.
@return Number of pending requests cancelled.
*/
int cancelNodeList(std::vector<content_t> *content_vec);
/**
Carries out all pending node resolution requests. Call this when the
node registration phase has completed.
Internally marks node registration as complete.
@return Number of failed pending requests.
*/
int resolveNodes();
/**
Returns the status of the node registration phase.
@return Boolean of whether the registration phase is complete.
*/
bool isNodeRegFinished() { return m_is_node_registration_complete; }
private:
INodeDefManager *m_ndef;
bool m_is_node_registration_complete;
std::list<NodeResolveInfo *> m_pending_contents;
ContentVectorResolveList m_pending_content_vecs;
}; };
class INodeDefManager class INodeDefManager
@ -422,7 +313,14 @@ public:
virtual void serialize(std::ostream &os, u16 protocol_version)=0; virtual void serialize(std::ostream &os, u16 protocol_version)=0;
virtual NodeResolver *getResolver()=0; virtual void pendNodeResolve(NodeResolveInfo *nri)=0;
virtual void cancelNodeResolve(NodeResolver *resolver)=0;
virtual void runNodeResolverCallbacks()=0;
virtual bool getIdFromResolveInfo(NodeResolveInfo *nri,
const std::string &node_alt, content_t c_fallback, content_t &result)=0;
virtual bool getIdsFromResolveInfo(NodeResolveInfo *nri,
std::vector<content_t> &result)=0;
}; };
class IWritableNodeDefManager : public INodeDefManager class IWritableNodeDefManager : public INodeDefManager
@ -464,10 +362,38 @@ 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; virtual void pendNodeResolve(NodeResolveInfo *nri)=0;
virtual void cancelNodeResolve(NodeResolver *resolver)=0;
virtual void runNodeResolverCallbacks()=0;
virtual bool getIdFromResolveInfo(NodeResolveInfo *nri,
const std::string &node_alt, content_t c_fallback, content_t &result)=0;
virtual bool getIdsFromResolveInfo(NodeResolveInfo *nri,
std::vector<content_t> &result)=0;
}; };
IWritableNodeDefManager *createNodeDefManager(); IWritableNodeDefManager *createNodeDefManager();
class NodeResolver {
public:
NodeResolver()
{
m_lookup_done = false;
m_ndef = NULL;
}
~NodeResolver()
{
if (!m_lookup_done)
m_ndef->cancelNodeResolve(this);
}
virtual void resolveNodeNames(NodeResolveInfo *nri) = 0;
bool m_lookup_done;
INodeDefManager *m_ndef;
};
#endif #endif

@ -235,7 +235,8 @@ bool read_stringlist(lua_State *L, int index, std::vector<const char *> &result)
if (lua_istable(L, index)) { if (lua_istable(L, index)) {
lua_pushnil(L); lua_pushnil(L);
while (lua_next(L, index)) { while (lua_next(L, index)) {
result.push_back(lua_tostring(L, -1)); if (lua_isstring(L, -1))
result.push_back(lua_tostring(L, -1));
lua_pop(L, 1); lua_pop(L, 1);
} }
} else if (lua_isstring(L, index)) { } else if (lua_isstring(L, index)) {

@ -183,9 +183,8 @@ bool get_schematic(lua_State *L, int index, Schematic *schem,
if (lua_istable(L, index)) { if (lua_istable(L, index)) {
return read_schematic(L, index, schem, ndef, replace_names); return read_schematic(L, index, schem, ndef, replace_names);
} else if (lua_isstring(L, index)) { } else if (lua_isstring(L, index)) {
NodeResolver *resolver = ndef->getResolver();
const char *filename = lua_tostring(L, index); const char *filename = lua_tostring(L, index);
return schem->loadSchematicFromFile(filename, resolver, replace_names); return schem->loadSchematicFromFile(filename, ndef, replace_names);
} else { } else {
return false; return false;
} }
@ -415,8 +414,8 @@ 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(); INodeDefManager *ndef = getServer(L)->getNodeDefManager();
BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr; BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr;
enum BiomeType biometype = (BiomeType)getenumfield(L, index, "type", enum BiomeType biometype = (BiomeType)getenumfield(L, index, "type",
es_BiomeTerrainType, BIOME_TYPE_NORMAL); es_BiomeTerrainType, BIOME_TYPE_NORMAL);
@ -437,19 +436,15 @@ int ModApiMapgen::l_register_biome(lua_State *L)
return 0; return 0;
} }
// Pend node resolutions only if insertion succeeded NodeResolveInfo *nri = new NodeResolveInfo(b);
resolver->addNode(getstringfield_default(L, index, "node_top", ""), std::list<std::string> &nnames = nri->nodenames;
"mapgen_dirt_with_grass", CONTENT_AIR, &b->c_top); nnames.push_back(getstringfield_default(L, index, "node_top", ""));
resolver->addNode(getstringfield_default(L, index, "node_filler", ""), nnames.push_back(getstringfield_default(L, index, "node_filler", ""));
"mapgen_dirt", CONTENT_AIR, &b->c_filler); nnames.push_back(getstringfield_default(L, index, "node_stone", ""));
resolver->addNode(getstringfield_default(L, index, "node_stone", ""), nnames.push_back(getstringfield_default(L, index, "node_water", ""));
"mapgen_stone", CONTENT_AIR, &b->c_stone); nnames.push_back(getstringfield_default(L, index, "node_dust", ""));
resolver->addNode(getstringfield_default(L, index, "node_water", ""), nnames.push_back(getstringfield_default(L, index, "node_dust_water", ""));
"mapgen_water_source", CONTENT_AIR, &b->c_water); ndef->pendNodeResolve(nri);
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);
verbosestream << "register_biome: " << b->name << std::endl; verbosestream << "register_biome: " << b->name << std::endl;
@ -485,7 +480,6 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
luaL_checktype(L, index, LUA_TTABLE); luaL_checktype(L, index, LUA_TTABLE);
INodeDefManager *ndef = getServer(L)->getNodeDefManager(); INodeDefManager *ndef = getServer(L)->getNodeDefManager();
NodeResolver *resolver = getServer(L)->getNodeDefManager()->getResolver();
DecorationManager *decomgr = getServer(L)->getEmergeManager()->decomgr; DecorationManager *decomgr = getServer(L)->getEmergeManager()->decomgr;
BiomeManager *biomemgr = getServer(L)->getEmergeManager()->biomemgr; BiomeManager *biomemgr = getServer(L)->getEmergeManager()->biomemgr;
@ -509,11 +503,14 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
return 0; return 0;
} }
NodeResolveInfo *nri = new NodeResolveInfo(deco);
//// Get node name(s) to place decoration on //// Get node name(s) to place decoration on
std::vector<const char *> place_on_names; std::vector<const char *> place_on_names;
getstringlistfield(L, index, "place_on", place_on_names); getstringlistfield(L, index, "place_on", place_on_names);
nri->nodename_sizes.push_back(place_on_names.size());
for (size_t i = 0; i != place_on_names.size(); i++) for (size_t i = 0; i != place_on_names.size(); i++)
resolver->addNodeList(place_on_names[i], &deco->c_place_on); nri->nodenames.push_back(place_on_names[i]);
getflagsfield(L, index, "flags", flagdesc_deco, &deco->flags, NULL); getflagsfield(L, index, "flags", flagdesc_deco, &deco->flags, NULL);
@ -538,7 +535,7 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
bool success = false; bool success = false;
switch (decotype) { switch (decotype) {
case DECO_SIMPLE: case DECO_SIMPLE:
success = regDecoSimple(L, resolver, (DecoSimple *)deco); success = regDecoSimple(L, nri, (DecoSimple *)deco);
break; break;
case DECO_SCHEMATIC: case DECO_SCHEMATIC:
success = regDecoSchematic(L, ndef, (DecoSchematic *)deco); success = regDecoSchematic(L, ndef, (DecoSchematic *)deco);
@ -547,6 +544,8 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
break; break;
} }
ndef->pendNodeResolve(nri);
if (!success) { if (!success) {
delete deco; delete deco;
return 0; return 0;
@ -558,12 +557,14 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
return 0; return 0;
} }
verbosestream << "register_decoration: " << deco->name << std::endl;
lua_pushinteger(L, id); lua_pushinteger(L, id);
return 1; return 1;
} }
bool ModApiMapgen::regDecoSimple(lua_State *L, bool ModApiMapgen::regDecoSimple(lua_State *L,
NodeResolver *resolver, DecoSimple *deco) NodeResolveInfo *nri, DecoSimple *deco)
{ {
int index = 1; int index = 1;
@ -584,6 +585,9 @@ bool ModApiMapgen::regDecoSimple(lua_State *L,
"defined" << std::endl; "defined" << std::endl;
return false; return false;
} }
nri->nodename_sizes.push_back(deco_names.size());
for (size_t i = 0; i != deco_names.size(); i++)
nri->nodenames.push_back(deco_names[i]);
std::vector<const char *> spawnby_names; std::vector<const char *> spawnby_names;
getstringlistfield(L, index, "spawn_by", spawnby_names); getstringlistfield(L, index, "spawn_by", spawnby_names);
@ -592,11 +596,9 @@ bool ModApiMapgen::regDecoSimple(lua_State *L,
" but num_spawn_by specified" << std::endl; " but num_spawn_by specified" << std::endl;
return false; return false;
} }
nri->nodename_sizes.push_back(spawnby_names.size());
for (size_t i = 0; i != deco_names.size(); i++)
resolver->addNodeList(deco_names[i], &deco->c_decos);
for (size_t i = 0; i != spawnby_names.size(); i++) for (size_t i = 0; i != spawnby_names.size(); i++)
resolver->addNodeList(spawnby_names[i], &deco->c_spawnby); nri->nodenames.push_back(spawnby_names[i]);
return true; return true;
} }
@ -615,6 +617,7 @@ bool ModApiMapgen::regDecoSchematic(lua_State *L, INodeDefManager *ndef,
read_schematic_replacements(L, replace_names, lua_gettop(L)); read_schematic_replacements(L, replace_names, lua_gettop(L));
lua_pop(L, 1); lua_pop(L, 1);
// TODO(hmmmm): get a ref from registered schematics
Schematic *schem = new Schematic; Schematic *schem = new Schematic;
lua_getfield(L, index, "schematic"); lua_getfield(L, index, "schematic");
if (!get_schematic(L, -1, schem, ndef, replace_names)) { if (!get_schematic(L, -1, schem, ndef, replace_names)) {
@ -635,8 +638,8 @@ int ModApiMapgen::l_register_ore(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(); INodeDefManager *ndef = getServer(L)->getNodeDefManager();
OreManager *oremgr = getServer(L)->getEmergeManager()->oremgr; OreManager *oremgr = getServer(L)->getEmergeManager()->oremgr;
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);
@ -683,13 +686,18 @@ int ModApiMapgen::l_register_ore(lua_State *L)
return 0; return 0;
} }
NodeResolveInfo *nri = new NodeResolveInfo(ore);
nri->nodenames.push_back(getstringfield_default(L, index, "ore", ""));
std::vector<const char *> wherein_names; std::vector<const char *> wherein_names;
getstringlistfield(L, index, "wherein", wherein_names); getstringlistfield(L, index, "wherein", wherein_names);
nri->nodename_sizes.push_back(wherein_names.size());
for (size_t i = 0; i != wherein_names.size(); i++) for (size_t i = 0; i != wherein_names.size(); i++)
resolver->addNodeList(wherein_names[i], &ore->c_wherein); nri->nodenames.push_back(wherein_names[i]);
resolver->addNode(getstringfield_default(L, index, "ore", ""), ndef->pendNodeResolve(nri);
"", CONTENT_AIR, &ore->c_ore);
verbosestream << "register_ore: " << ore->name << std::endl;
lua_pushinteger(L, id); lua_pushinteger(L, id);
return 1; return 1;

@ -23,7 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_base.h" #include "lua_api/l_base.h"
class INodeDefManager; class INodeDefManager;
class NodeResolver; class NodeResolveInfo;
class DecoSimple; class DecoSimple;
class DecoSchematic; class DecoSchematic;
@ -68,7 +68,7 @@ private:
static int l_place_schematic(lua_State *L); static int l_place_schematic(lua_State *L);
static bool regDecoSimple(lua_State *L, static bool regDecoSimple(lua_State *L,
NodeResolver *resolver, DecoSimple *deco); NodeResolveInfo *nri, DecoSimple *deco);
static bool regDecoSchematic(lua_State *L, static bool regDecoSchematic(lua_State *L,
INodeDefManager *ndef, DecoSchematic *deco); INodeDefManager *ndef, DecoSchematic *deco);

@ -337,7 +337,7 @@ Server::Server(
m_nodedef->updateAliases(m_itemdef); m_nodedef->updateAliases(m_itemdef);
// Perform pending node name resolutions // Perform pending node name resolutions
m_nodedef->getResolver()->resolveNodes(); m_nodedef->runNodeResolverCallbacks();
// 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
@ -2650,7 +2650,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
} }
} // action == 4 } // action == 4
/* /*
Catch invalid actions Catch invalid actions
@ -4570,7 +4570,7 @@ bool Server::showFormspec(const char *playername, const std::string &formspec, c
u32 Server::hudAdd(Player *player, HudElement *form) { u32 Server::hudAdd(Player *player, HudElement *form) {
if (!player) if (!player)
return -1; return -1;
u32 id = player->addHud(form); u32 id = player->addHud(form);
SendHUDAdd(player->peer_id, id, form); SendHUDAdd(player->peer_id, id, form);
@ -4586,7 +4586,7 @@ bool Server::hudRemove(Player *player, u32 id) {
if (!todel) if (!todel)
return false; return false;
delete todel; delete todel;
SendHUDRemove(player->peer_id, id); SendHUDRemove(player->peer_id, id);
@ -4607,9 +4607,9 @@ bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
SendHUDSetFlags(player->peer_id, flags, mask); SendHUDSetFlags(player->peer_id, flags, mask);
player->hud_flags = flags; player->hud_flags = flags;
PlayerSAO* playersao = player->getPlayerSAO(); PlayerSAO* playersao = player->getPlayerSAO();
if (playersao == NULL) if (playersao == NULL)
return false; return false;