}
+BiomeManager *BiomeManager::clone() const
+{
+ auto mgr = new BiomeManager();
+ assert(mgr);
+ ObjDefManager::cloneTo(mgr);
+ mgr->m_server = m_server;
+ return mgr;
+}
+
+
// For BiomeGen type 'BiomeGenOriginal'
float BiomeManager::getHeatAtPosOriginal(v3s16 pos, NoiseParams &np_heat,
NoiseParams &np_heat_blend, u64 seed)
////////////////////////////////////////////////////////////////////////////////
+ObjDef *Biome::clone() const
+{
+ auto obj = new Biome();
+ ObjDef::cloneTo(obj);
+ NodeResolver::cloneTo(obj);
+
+ obj->flags = flags;
+
+ obj->c_top = c_top;
+ obj->c_filler = c_filler;
+ obj->c_stone = c_stone;
+ obj->c_water_top = c_water_top;
+ obj->c_water = c_water;
+ obj->c_river_water = c_river_water;
+ obj->c_riverbed = c_riverbed;
+ obj->c_dust = c_dust;
+ obj->c_cave_liquid = c_cave_liquid;
+ obj->c_dungeon = c_dungeon;
+ obj->c_dungeon_alt = c_dungeon_alt;
+ obj->c_dungeon_stair = c_dungeon_stair;
+
+ obj->depth_top = depth_top;
+ obj->depth_filler = depth_filler;
+ obj->depth_water_top = depth_water_top;
+ obj->depth_riverbed = depth_riverbed;
+
+ obj->min_pos = min_pos;
+ obj->max_pos = max_pos;
+ obj->heat_point = heat_point;
+ obj->humidity_point = humidity_point;
+ obj->vertical_blend = vertical_blend;
+
+ return obj;
+}
+
void Biome::resolveNodeNames()
{
getIdFromNrBacklog(&c_top, "mapgen_stone", CONTENT_AIR, false);
class Biome : public ObjDef, public NodeResolver {
public:
+ ObjDef *clone() const;
+
u32 flags;
content_t c_top;
BiomeManager(Server *server);
virtual ~BiomeManager() = default;
+ BiomeManager *clone() const;
+
const char *getObjectTitle() const
{
return "biome";
Biome *getBiomeFromNoiseOriginal(float heat, float humidity, v3s16 pos);
private:
+ BiomeManager() {};
+
Server *m_server;
};
return nplaced;
}
+DecorationManager *DecorationManager::clone() const
+{
+ auto mgr = new DecorationManager();
+ ObjDefManager::cloneTo(mgr);
+ return mgr;
+}
+
///////////////////////////////////////////////////////////////////////////////
}
+void Decoration::cloneTo(Decoration *def) const
+{
+ ObjDef::cloneTo(def);
+ def->flags = flags;
+ def->mapseed = mapseed;
+ def->c_place_on = c_place_on;
+ def->sidelen = sidelen;
+ def->y_min = y_min;
+ def->y_max = y_max;
+ def->fill_ratio = fill_ratio;
+ def->np = np;
+ def->c_spawnby = c_spawnby;
+ def->nspawnby = nspawnby;
+ def->place_offset_y = place_offset_y;
+ def->biomes = biomes;
+}
+
+
///////////////////////////////////////////////////////////////////////////////
+ObjDef *DecoSimple::clone() const
+{
+ auto def = new DecoSimple();
+ Decoration::cloneTo(def);
+
+ def->c_decos = c_decos;
+ def->deco_height = deco_height;
+ def->deco_height_max = deco_height_max;
+ def->deco_param2 = deco_param2;
+ def->deco_param2_max = deco_param2_max;
+
+ return def;
+}
+
+
void DecoSimple::resolveNodeNames()
{
Decoration::resolveNodeNames();
///////////////////////////////////////////////////////////////////////////////
+ObjDef *DecoSchematic::clone() const
+{
+ auto def = new DecoSchematic();
+ Decoration::cloneTo(def);
+ NodeResolver::cloneTo(def);
+
+ def->rotation = rotation;
+ /* FIXME: This is not ideal, we only have a pointer to the schematic despite
+ * not owning it. Optimally this would be a handle. */
+ def->schematic = schematic; // not cloned
+
+ return def;
+}
+
+
size_t DecoSchematic::generate(MMVManip *vm, PcgRandom *pr, v3s16 p, bool ceiling)
{
// Schematic could have been unloaded but not the decoration
s16 place_offset_y = 0;
std::unordered_set<u8> biomes;
+
+protected:
+ void cloneTo(Decoration *def) const;
};
class DecoSimple : public Decoration {
public:
+ ObjDef *clone() const;
+
virtual void resolveNodeNames();
virtual size_t generate(MMVManip *vm, PcgRandom *pr, v3s16 p, bool ceiling);
class DecoSchematic : public Decoration {
public:
+ ObjDef *clone() const;
+
DecoSchematic() = default;
virtual size_t generate(MMVManip *vm, PcgRandom *pr, v3s16 p, bool ceiling);
DecorationManager(IGameDef *gamedef);
virtual ~DecorationManager() = default;
+ DecorationManager *clone() const;
+
const char *getObjectTitle() const
{
return "decoration";
}
size_t placeAllDecos(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);
+
+private:
+ DecorationManager() {};
};
}
+OreManager *OreManager::clone() const
+{
+ auto mgr = new OreManager();
+ ObjDefManager::cloneTo(mgr);
+ return mgr;
+}
+
+
///////////////////////////////////////////////////////////////////////////////
}
+void Ore::cloneTo(Ore *def) const
+{
+ ObjDef::cloneTo(def);
+ NodeResolver::cloneTo(def);
+ def->c_ore = c_ore;
+ def->c_wherein = c_wherein;
+ def->clust_scarcity = clust_scarcity;
+ def->clust_num_ores = clust_num_ores;
+ def->clust_size = clust_size;
+ def->y_min = y_min;
+ def->y_max = y_max;
+ def->ore_param2 = ore_param2;
+ def->flags = flags;
+ def->nthresh = nthresh;
+ def->np = np;
+ def->noise = nullptr; // cannot be shared! so created on demand
+ def->biomes = biomes;
+}
+
+
///////////////////////////////////////////////////////////////////////////////
+ObjDef *OreScatter::clone() const
+{
+ auto def = new OreScatter();
+ Ore::cloneTo(def);
+ return def;
+}
+
+
void OreScatter::generate(MMVManip *vm, int mapseed, u32 blockseed,
v3s16 nmin, v3s16 nmax, u8 *biomemap)
{
///////////////////////////////////////////////////////////////////////////////
+ObjDef *OreSheet::clone() const
+{
+ auto def = new OreSheet();
+ Ore::cloneTo(def);
+
+ def->column_height_max = column_height_max;
+ def->column_height_min = column_height_min;
+ def->column_midpoint_factor = column_midpoint_factor;
+
+ return def;
+}
+
+
void OreSheet::generate(MMVManip *vm, int mapseed, u32 blockseed,
v3s16 nmin, v3s16 nmax, u8 *biomemap)
{
}
+ObjDef *OrePuff::clone() const
+{
+ auto def = new OrePuff();
+ Ore::cloneTo(def);
+
+ def->np_puff_top = np_puff_top;
+ def->np_puff_bottom = np_puff_bottom;
+ def->noise_puff_top = nullptr; // cannot be shared, on-demand
+ def->noise_puff_bottom = nullptr;
+
+ return def;
+}
+
+
void OrePuff::generate(MMVManip *vm, int mapseed, u32 blockseed,
v3s16 nmin, v3s16 nmax, u8 *biomemap)
{
///////////////////////////////////////////////////////////////////////////////
+ObjDef *OreBlob::clone() const
+{
+ auto def = new OreBlob();
+ Ore::cloneTo(def);
+ return def;
+}
+
+
void OreBlob::generate(MMVManip *vm, int mapseed, u32 blockseed,
v3s16 nmin, v3s16 nmax, u8 *biomemap)
{
}
+ObjDef *OreVein::clone() const
+{
+ auto def = new OreVein();
+ Ore::cloneTo(def);
+
+ def->random_factor = random_factor;
+ def->noise2 = nullptr; // cannot be shared, on-demand
+ def->sizey_prev = sizey_prev;
+
+ return def;
+}
+
+
void OreVein::generate(MMVManip *vm, int mapseed, u32 blockseed,
v3s16 nmin, v3s16 nmax, u8 *biomemap)
{
}
+ObjDef *OreStratum::clone() const
+{
+ auto def = new OreStratum();
+ Ore::cloneTo(def);
+
+ def->np_stratum_thickness = np_stratum_thickness;
+ def->noise_stratum_thickness = nullptr; // cannot be shared, on-demand
+ def->stratum_thickness = stratum_thickness;
+
+ return def;
+}
+
+
void OreStratum::generate(MMVManip *vm, int mapseed, u32 blockseed,
v3s16 nmin, v3s16 nmax, u8 *biomemap)
{
size_t placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);
virtual void generate(MMVManip *vm, int mapseed, u32 blockseed,
v3s16 nmin, v3s16 nmax, u8 *biomemap) = 0;
+
+protected:
+ void cloneTo(Ore *def) const;
};
class OreScatter : public Ore {
public:
static const bool NEEDS_NOISE = false;
+ ObjDef *clone() const;
+
virtual void generate(MMVManip *vm, int mapseed, u32 blockseed,
v3s16 nmin, v3s16 nmax, u8 *biomemap);
};
public:
static const bool NEEDS_NOISE = true;
+ ObjDef *clone() const;
+
u16 column_height_min;
u16 column_height_max;
float column_midpoint_factor;
public:
static const bool NEEDS_NOISE = true;
+ ObjDef *clone() const;
+
NoiseParams np_puff_top;
NoiseParams np_puff_bottom;
Noise *noise_puff_top = nullptr;
public:
static const bool NEEDS_NOISE = true;
+ ObjDef *clone() const;
+
virtual void generate(MMVManip *vm, int mapseed, u32 blockseed,
v3s16 nmin, v3s16 nmax, u8 *biomemap);
};
public:
static const bool NEEDS_NOISE = true;
+ ObjDef *clone() const;
+
float random_factor;
Noise *noise2 = nullptr;
int sizey_prev = 0;
public:
static const bool NEEDS_NOISE = false;
+ ObjDef *clone() const;
+
NoiseParams np_stratum_thickness;
Noise *noise_stratum_thickness = nullptr;
u16 stratum_thickness;
OreManager(IGameDef *gamedef);
virtual ~OreManager() = default;
+ OreManager *clone() const;
+
const char *getObjectTitle() const
{
return "ore";
void clear();
size_t placeAllOres(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);
+
+private:
+ OreManager() {};
};
delete []slice_probs;
}
+ObjDef *Schematic::clone() const
+{
+ FATAL_ERROR("not cloneable");
+}
+
void Schematic::resolveNodeNames()
{
void Schematic::blitToVManip(MMVManip *vm, v3s16 p, Rotation rot, bool force_place)
{
+ assert(schemdata && slice_probs);
sanity_check(m_ndef != NULL);
int xstride = 1;
Rotation rot, bool force_place)
{
assert(vm != NULL);
- assert(schemdata != NULL);
+ assert(schemdata && slice_probs);
sanity_check(m_ndef != NULL);
//// Determine effective rotation and effective schematic dimensions
Schematic();
virtual ~Schematic();
+ ObjDef *clone() const;
+
virtual void resolveNodeNames();
bool loadSchematicFromFile(const std::string &filename,
SchematicManager(Server *server);
virtual ~SchematicManager() = default;
+ // not cloneable
+
virtual void clear();
const char *getObjectTitle() const
}
+void NodeResolver::cloneTo(NodeResolver *res) const
+{
+ FATAL_ERROR_IF(!m_resolve_done, "NodeResolver can only be cloned"
+ " after resolving has completed");
+ /* We don't actually do anything significant. Since the node resolving has
+ * already completed, the class that called us will already have the
+ * resolved IDs in its data structures (which it copies on its own) */
+ res->m_ndef = m_ndef;
+ res->m_resolve_done = true;
+}
+
+
void NodeResolver::nodeResolveInternal()
{
m_nodenames_idx = 0;
virtual ~NodeResolver();
virtual void resolveNodeNames() = 0;
+ // required because this class is used as mixin for ObjDef
+ void cloneTo(NodeResolver *res) const;
+
bool getIdFromNrBacklog(content_t *result_out,
const std::string &node_alt, content_t c_fallback,
bool error_on_fallback = true);
*uid = get_bits(handle, 24, 7);
return true;
}
+
+// Cloning
+
+void ObjDef::cloneTo(ObjDef *def) const
+{
+ def->index = index;
+ def->uid = uid;
+ def->handle = handle;
+ def->name = name;
+}
+
+void ObjDefManager::cloneTo(ObjDefManager *mgr) const
+{
+ mgr->m_ndef = m_ndef;
+ mgr->m_objects.reserve(m_objects.size());
+ for (const auto &obj : m_objects)
+ mgr->m_objects.push_back(obj->clone());
+ mgr->m_objtype = m_objtype;
+}
public:
virtual ~ObjDef() = default;
+ // Only implemented by child classes (leafs in class hierarchy)
+ // Should create new object of its own type, call cloneTo() of parent class
+ // and copy its own instance variables over
+ virtual ObjDef *clone() const = 0;
+
u32 index;
u32 uid;
ObjDefHandle handle;
std::string name;
+
+protected:
+ // Only implemented by classes that have children themselves
+ // by copying the defintion and changing that argument type (!!!)
+ // Should defer to parent class cloneTo() if applicable and then copy
+ // over its own properties
+ void cloneTo(ObjDef *def) const;
};
// WARNING: Ownership of ObjDefs is transferred to the ObjDefManager it is
virtual ~ObjDefManager();
DISABLE_CLASS_COPY(ObjDefManager);
+ // T *clone() const; // implemented in child class with correct type
+
virtual const char *getObjectTitle() const { return "ObjDef"; }
virtual void clear();
ObjDefType *type, u32 *uid);
protected:
+ ObjDefManager() {};
+ // Helper for child classes to implement clone()
+ void cloneTo(ObjDefManager *mgr) const;
+
const NodeDefManager *m_ndef;
std::vector<ObjDef *> m_objects;
ObjDefType m_objtype;
void testHandles();
void testAddGetSetClear();
+ void testClone();
};
static TestObjDef g_test_instance;
{
TEST(testHandles);
TEST(testAddGetSetClear);
+ TEST(testClone);
}
////////////////////////////////////////////////////////////////////////////////
+/* Minimal implementation of ObjDef and ObjDefManager subclass */
+
+class MyObjDef : public ObjDef
+{
+public:
+ ObjDef *clone() const
+ {
+ auto def = new MyObjDef();
+ ObjDef::cloneTo(def);
+ def->testvalue = testvalue;
+ return def;
+ };
+
+ u32 testvalue;
+};
+
+class MyObjDefManager : public ObjDefManager
+{
+public:
+ MyObjDefManager(ObjDefType type) : ObjDefManager(NULL, type){};
+ MyObjDefManager *clone() const
+ {
+ auto mgr = new MyObjDefManager();
+ ObjDefManager::cloneTo(mgr);
+ return mgr;
+ };
+
+protected:
+ MyObjDefManager(){};
+};
+
void TestObjDef::testHandles()
{
u32 uid = 0;
UASSERTEQ(ObjDefType, testmgr.getType(), OBJDEF_GENERIC);
- obj0 = new ObjDef;
+ obj0 = new MyObjDef;
obj0->name = "foobar";
hObj0 = testmgr.add(obj0);
UASSERT(hObj0 != OBJDEF_INVALID_HANDLE);
UASSERTEQ(u32, obj0->index, 0);
- obj1 = new ObjDef;
+ obj1 = new MyObjDef;
obj1->name = "FooBaz";
hObj1 = testmgr.add(obj1);
UASSERT(hObj1 != OBJDEF_INVALID_HANDLE);
UASSERTEQ(u32, obj1->index, 1);
- obj2 = new ObjDef;
+ obj2 = new MyObjDef;
obj2->name = "asdf";
hObj2 = testmgr.add(obj2);
UASSERT(hObj2 != OBJDEF_INVALID_HANDLE);
UASSERTEQ(u32, obj2->index, 2);
- obj3 = new ObjDef;
+ obj3 = new MyObjDef;
obj3->name = "foobaz";
hObj3 = testmgr.add(obj3);
UASSERT(hObj3 == OBJDEF_INVALID_HANDLE);
testmgr.clear();
UASSERTEQ(size_t, testmgr.getNumObjects(), 0);
}
+
+void TestObjDef::testClone()
+{
+ MyObjDefManager testmgr(OBJDEF_GENERIC);
+ ObjDefManager *mgrcopy;
+ MyObjDef *obj, *temp2;
+ ObjDef *temp1;
+ ObjDefHandle hObj;
+
+ obj = new MyObjDef;
+ obj->testvalue = 0xee00ff11;
+ hObj = testmgr.add(obj);
+ UASSERT(hObj != OBJDEF_INVALID_HANDLE);
+
+ mgrcopy = testmgr.clone();
+ UASSERT(mgrcopy);
+ UASSERTEQ(ObjDefType, mgrcopy->getType(), testmgr.getType());
+ UASSERTEQ(size_t, mgrcopy->getNumObjects(), testmgr.getNumObjects());
+
+ // 1) check that the same handle is still valid on the copy
+ temp1 = mgrcopy->get(hObj);
+ UASSERT(temp1);
+ UASSERT(temp1 == mgrcopy->getRaw(0));
+ // 2) check that the copy has the correct C++ class
+ temp2 = dynamic_cast<MyObjDef *>(temp1);
+ UASSERT(temp2);
+ // 3) check that it was correctly copied
+ UASSERTEQ(u32, obj->testvalue, temp2->testvalue);
+ // 4) check that it was copied AT ALL (not the same)
+ UASSERT(obj != temp2);
+
+ testmgr.clear();
+ mgrcopy->clear();
+ delete mgrcopy;
+}