1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-02-11 13:15:38 +02:00

Switch ObjectTemplate to shared_ptr<const> (#870)

This commit is contained in:
DjWarmonger 2022-09-11 15:12:35 +02:00 committed by Andrii Danylchenko
parent cedc9a92ed
commit 3d2dc2335b
34 changed files with 384 additions and 222 deletions

View File

@ -173,8 +173,8 @@ void Graphics::loadHeroAnimations()
{
for (auto & templ : VLC->objtypeh->getHandlerFor(Obj::HERO, elem->getIndex())->getTemplates())
{
if (!heroAnimations.count(templ.animationFile))
heroAnimations[templ.animationFile] = loadHeroAnimation(templ.animationFile);
if (!heroAnimations.count(templ->animationFile))
heroAnimations[templ->animationFile] = loadHeroAnimation(templ->animationFile);
}
}
@ -381,21 +381,21 @@ std::shared_ptr<CAnimation> Graphics::getAnimation(const CGObjectInstance* obj)
return getAnimation(obj->appearance);
}
std::shared_ptr<CAnimation> Graphics::getAnimation(const ObjectTemplate & info)
std::shared_ptr<CAnimation> Graphics::getAnimation(std::shared_ptr<const ObjectTemplate> info)
{
//the only(?) invisible object
if(info.id == Obj::EVENT)
if(info->id == Obj::EVENT)
{
return std::shared_ptr<CAnimation>();
}
if(info.animationFile.empty())
if(info->animationFile.empty())
{
logGlobal->warn("Def name for obj (%d,%d) is empty!", info.id, info.subid);
logGlobal->warn("Def name for obj (%d,%d) is empty!", info->id, info->subid);
return std::shared_ptr<CAnimation>();
}
std::shared_ptr<CAnimation> ret = mapObjectAnimations[info.animationFile];
std::shared_ptr<CAnimation> ret = mapObjectAnimations[info->animationFile];
//already loaded
if(ret)
@ -404,8 +404,8 @@ std::shared_ptr<CAnimation> Graphics::getAnimation(const ObjectTemplate & info)
return ret;
}
ret = std::make_shared<CAnimation>(info.animationFile);
mapObjectAnimations[info.animationFile] = ret;
ret = std::make_shared<CAnimation>(info->animationFile);
mapObjectAnimations[info->animationFile] = ret;
ret->preload();
return ret;

View File

@ -98,7 +98,7 @@ public:
void blueToPlayersAdv(SDL_Surface * sur, PlayerColor player); //replaces blue interface colour with a color of player
std::shared_ptr<CAnimation> getAnimation(const CGObjectInstance * obj);
std::shared_ptr<CAnimation> getAnimation(const ObjectTemplate & info);
std::shared_ptr<CAnimation> getAnimation(std::shared_ptr<const ObjectTemplate> info);
};
extern Graphics * graphics;

View File

@ -979,7 +979,7 @@ CMapHandler::AnimBitmapHolder CMapHandler::CMapBlitter::findHeroBitmap(const CGH
if (hero->boat)
animation = graphics->boatAnimations[hero->boat->subID];
else
animation = graphics->heroAnimations[hero->appearance.animationFile];
animation = graphics->heroAnimations[hero->appearance->animationFile];
bool moving = !hero->isStanding;
int group = getHeroFrameGroup(hero->moveDir, moving);
@ -1486,8 +1486,8 @@ bool CMapHandler::compareObjectBlitOrder(const CGObjectInstance * a, const CGObj
return true;
if (!b)
return false;
if (a->appearance.printPriority != b->appearance.printPriority)
return a->appearance.printPriority > b->appearance.printPriority;
if (a->appearance->printPriority != b->appearance->printPriority)
return a->appearance->printPriority > b->appearance->printPriority;
if(a->pos.y != b->pos.y)
return a->pos.y < b->pos.y;

View File

@ -533,7 +533,7 @@ void CGHeroInstance::initObj(CRandomGenerator & rand)
{
auto customApp = VLC->objtypeh->getHandlerFor(ID, type->heroClass->getIndex())->getOverride(cb->gameState()->getTile(visitablePos())->terType, this);
if (customApp)
appearance = customApp.get();
appearance = customApp;
}
//copy active (probably growing) bonuses from hero prototype to hero object

View File

@ -1133,7 +1133,7 @@ void CGTownInstance::updateAppearance()
//FIXME: not the best way to do this
auto app = VLC->objtypeh->getHandlerFor(ID, subID)->getOverride(cb->gameState()->getTile(visitablePos())->terType, this);
if (app)
appearance = app.get();
appearance = app;
}
std::string CGTownInstance::nodeName() const

View File

@ -117,11 +117,11 @@ std::vector<JsonNode> CObjectClassesHandler::loadLegacyData(size_t dataSize)
for (size_t i=0; i<totalNumber; i++)
{
ObjectTemplate templ;
templ.readTxt(parser);
auto templ = new ObjectTemplate;
templ->readTxt(parser);
parser.endLine();
std::pair<si32, si32> key(templ.id.num, templ.subid);
legacyTemplates.insert(std::make_pair(key, templ));
std::pair<si32, si32> key(templ->id.num, templ->subid);
legacyTemplates.insert(std::make_pair(key, std::shared_ptr<const ObjectTemplate>(templ)));
}
std::vector<JsonNode> ret(dataSize);// create storage for 256 objects
@ -448,7 +448,6 @@ AObjectTypeHandler::AObjectTypeHandler():
AObjectTypeHandler::~AObjectTypeHandler()
{
}
void AObjectTypeHandler::setType(si32 type, si32 subtype)
@ -488,12 +487,12 @@ void AObjectTypeHandler::init(const JsonNode & input, boost::optional<std::strin
entry.second.setType(JsonNode::JsonType::DATA_STRUCT);
JsonUtils::inherit(entry.second, base);
ObjectTemplate tmpl;
tmpl.id = Obj(type);
tmpl.subid = subtype;
tmpl.stringID = entry.first; // FIXME: create "fullID" - type.object.template?
tmpl.readJson(entry.second);
templates.push_back(tmpl);
auto tmpl = new ObjectTemplate;
tmpl->id = Obj(type);
tmpl->subid = subtype;
tmpl->stringID = entry.first; // FIXME: create "fullID" - type.object.template?
tmpl->readJson(entry.second);
templates.push_back(std::shared_ptr<const ObjectTemplate>(tmpl));
}
if (input["name"].isNull())
@ -523,7 +522,7 @@ void AObjectTypeHandler::init(const JsonNode & input, boost::optional<std::strin
initTypeData(input);
}
bool AObjectTypeHandler::objectFilter(const CGObjectInstance *, const ObjectTemplate &) const
bool AObjectTypeHandler::objectFilter(const CGObjectInstance *, std::shared_ptr<const ObjectTemplate>) const
{
return false; // by default there are no overrides
}
@ -551,26 +550,28 @@ SObjectSounds AObjectTypeHandler::getSounds() const
return sounds;
}
void AObjectTypeHandler::addTemplate(const ObjectTemplate & templ)
void AObjectTypeHandler::addTemplate(std::shared_ptr<const ObjectTemplate> templ)
{
//Otherwise the template remains constant
auto ptr = const_cast<ObjectTemplate*>(templ.get());
ptr->id = Obj(type);
ptr->subid = subtype;
templates.push_back(templ);
templates.back().id = Obj(type);
templates.back().subid = subtype;
}
void AObjectTypeHandler::addTemplate(JsonNode config)
{
config.setType(JsonNode::JsonType::DATA_STRUCT); // ensure that input is not null
JsonUtils::inherit(config, base);
ObjectTemplate tmpl;
tmpl.id = Obj(type);
tmpl.subid = subtype;
tmpl.stringID = ""; // TODO?
tmpl.readJson(config);
templates.push_back(tmpl);
auto tmpl = new ObjectTemplate;
tmpl->id = Obj(type);
tmpl->subid = subtype;
tmpl->stringID = ""; // TODO?
tmpl->readJson(config);
templates.emplace_back(tmpl);
}
std::vector<ObjectTemplate> AObjectTypeHandler::getTemplates() const
std::vector<std::shared_ptr<const ObjectTemplate>> AObjectTypeHandler::getTemplates() const
{
return templates;
}
@ -580,14 +581,14 @@ BattleField AObjectTypeHandler::getBattlefield() const
return battlefield ? BattleField::fromString(battlefield.get()) : BattleField::NONE;
}
std::vector<ObjectTemplate> AObjectTypeHandler::getTemplates(const Terrain & terrainType) const
std::vector<std::shared_ptr<const ObjectTemplate>>AObjectTypeHandler::getTemplates(const Terrain & terrainType) const
{
std::vector<ObjectTemplate> templates = getTemplates();
std::vector<ObjectTemplate> filtered;
std::vector<std::shared_ptr<const ObjectTemplate>> templates = getTemplates();
std::vector<std::shared_ptr<const ObjectTemplate>> filtered;
std::copy_if(templates.begin(), templates.end(), std::back_inserter(filtered), [&](const ObjectTemplate & obj)
std::copy_if(templates.begin(), templates.end(), std::back_inserter(filtered), [&](std::shared_ptr<const ObjectTemplate> obj)
{
return obj.canBePlacedAt(terrainType);
return obj->canBePlacedAt(terrainType);
});
// H3 defines allowed terrains in a weird way - artifacts, monsters and resources have faulty masks here
// Perhaps we should re-define faulty templates and remove this workaround (already done for resources)
@ -597,15 +598,15 @@ std::vector<ObjectTemplate> AObjectTypeHandler::getTemplates(const Terrain & ter
return filtered;
}
boost::optional<ObjectTemplate> AObjectTypeHandler::getOverride(const Terrain & terrainType, const CGObjectInstance * object) const
std::shared_ptr<const ObjectTemplate> AObjectTypeHandler::getOverride(const Terrain & terrainType, const CGObjectInstance * object) const
{
std::vector<ObjectTemplate> ret = getTemplates(terrainType);
for (auto & tmpl : ret)
std::vector<std::shared_ptr<const ObjectTemplate>> ret = getTemplates(terrainType);
for (const auto & tmpl: ret)
{
if (objectFilter(object, tmpl))
return tmpl;
}
return boost::optional<ObjectTemplate>();
return std::shared_ptr<const ObjectTemplate>(); //empty
}
const RandomMapInfo & AObjectTypeHandler::getRMGInfo()

View File

@ -144,7 +144,7 @@ class DLL_LINKAGE AObjectTypeHandler : public boost::noncopyable
JsonNode base; /// describes base template
std::vector<ObjectTemplate> templates;
std::vector<std::shared_ptr<const ObjectTemplate>> templates;
SObjectSounds sounds;
@ -154,7 +154,7 @@ class DLL_LINKAGE AObjectTypeHandler : public boost::noncopyable
protected:
void preInitObject(CGObjectInstance * obj) const;
virtual bool objectFilter(const CGObjectInstance *, const ObjectTemplate &) const;
virtual bool objectFilter(const CGObjectInstance *, std::shared_ptr<const ObjectTemplate>) const;
/// initialization for classes that inherit this one
virtual void initTypeData(const JsonNode & input);
@ -177,17 +177,21 @@ public:
boost::optional<std::string> getCustomName() const;
SObjectSounds getSounds() const;
void addTemplate(const ObjectTemplate & templ);
void addTemplate(std::shared_ptr<const ObjectTemplate> templ);
void addTemplate(JsonNode config);
/// returns all templates matching parameters
std::vector<ObjectTemplate> getTemplates() const;
std::vector<ObjectTemplate> getTemplates(const Terrain & terrainType) const;
std::vector<std::shared_ptr<const ObjectTemplate>> getTemplates() const;
std::vector<std::shared_ptr<const ObjectTemplate>> getTemplates(const Terrain & terrainType) const;
/// returns preferred template for this object, if present (e.g. one of 3 possible templates for town - village, fort and castle)
/// note that appearance will not be changed - this must be done separately (either by assignment or via pack from server)
std::shared_ptr<const ObjectTemplate> getOverride(const Terrain & terrainType, const CGObjectInstance * object) const;
BattleField getBattlefield() const;
/// returns preferred template for this object, if present (e.g. one of 3 possible templates for town - village, fort and castle)
/// note that appearance will not be changed - this must be done separately (either by assignment or via pack from server)
boost::optional<ObjectTemplate> getOverride(const Terrain & terrainType, const CGObjectInstance * object) const;
const RandomMapInfo & getRMGInfo();
@ -199,14 +203,14 @@ public:
/// Creates object and set up core properties (like ID/subID). Object is NOT initialized
/// to allow creating objects before game start (e.g. map loading)
virtual CGObjectInstance * create(const ObjectTemplate & tmpl) const = 0;
virtual CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const = 0;
/// Configures object properties. Should be re-entrable, resetting state of the object if necessarily
/// This should set remaining properties, including randomized or depending on map
virtual void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const = 0;
/// Returns object configuration, if available. Otherwise returns NULL
virtual std::unique_ptr<IObjectInfo> getObjectInfo(const ObjectTemplate & tmpl) const = 0;
virtual std::unique_ptr<IObjectInfo> getObjectInfo(std::shared_ptr<const ObjectTemplate> tmpl) const = 0;
template <typename Handler> void serialize(Handler &h, const int version)
{
@ -264,7 +268,7 @@ class DLL_LINKAGE CObjectClassesHandler : public IHandlerBase
std::map<std::string, std::function<TObjectTypeHandler()> > handlerConstructors;
/// container with H3 templates, used only during loading, no need to serialize it
typedef std::multimap<std::pair<si32, si32>, ObjectTemplate> TTemplatesContainer;
typedef std::multimap<std::pair<si32, si32>, std::shared_ptr<const ObjectTemplate>> TTemplatesContainer;
TTemplatesContainer legacyTemplates;
/// contains list of custom names for H3 objects (e.g. Dwellings), used to load H3 data

View File

@ -152,24 +152,24 @@ void CGObjectInstance::setOwner(PlayerColor ow)
}
int CGObjectInstance::getWidth() const//returns width of object graphic in tiles
{
return appearance.getWidth();
return appearance->getWidth();
}
int CGObjectInstance::getHeight() const //returns height of object graphic in tiles
{
return appearance.getHeight();
return appearance->getHeight();
}
bool CGObjectInstance::visitableAt(int x, int y) const //returns true if object is visitable at location (x, y) form left top tile of image (x, y in tiles)
{
return appearance.isVisitableAt(pos.x - x, pos.y - y);
return appearance->isVisitableAt(pos.x - x, pos.y - y);
}
bool CGObjectInstance::blockingAt(int x, int y) const
{
return appearance.isBlockedAt(pos.x - x, pos.y - y);
return appearance->isBlockedAt(pos.x - x, pos.y - y);
}
bool CGObjectInstance::coveringAt(int x, int y) const
{
return appearance.isVisibleAt(pos.x - x, pos.y - y);
return appearance->isVisibleAt(pos.x - x, pos.y - y);
}
std::set<int3> CGObjectInstance::getBlockedPos() const
@ -179,7 +179,7 @@ std::set<int3> CGObjectInstance::getBlockedPos() const
{
for(int h=0; h<getHeight(); ++h)
{
if(appearance.isBlockedAt(w, h))
if(appearance->isBlockedAt(w, h))
ret.insert(int3(pos.x - w, pos.y - h, pos.z));
}
}
@ -188,7 +188,7 @@ std::set<int3> CGObjectInstance::getBlockedPos() const
std::set<int3> CGObjectInstance::getBlockedOffsets() const
{
return appearance.getBlockedOffsets();
return appearance->getBlockedOffsets();
}
void CGObjectInstance::setType(si32 ID, si32 subID)
@ -264,7 +264,7 @@ int CGObjectInstance::getSightRadius() const
int3 CGObjectInstance::getVisitableOffset() const
{
return appearance.getVisitableOffset();
return appearance->getVisitableOffset();
}
void CGObjectInstance::giveDummyBonus(ObjectInstanceID heroID, ui8 duration) const
@ -350,7 +350,7 @@ int3 CGObjectInstance::visitablePos() const
bool CGObjectInstance::isVisitable() const
{
return appearance.isVisitable();
return appearance->isVisitable();
}
bool CGObjectInstance::passableFor(PlayerColor color) const
@ -375,7 +375,7 @@ void CGObjectInstance::serializeJson(JsonSerializeFormat & handler)
handler.serializeInt("y", pos.y);
handler.serializeInt("l", pos.z);
JsonNode app;
appearance.writeJson(app, false);
appearance->writeJson(app, false);
handler.serializeRaw("template",app, boost::none);
}

View File

@ -123,7 +123,7 @@ public:
/// Index of object in map's list of objects
ObjectInstanceID id;
/// Defines appearance of object on map (animation, blocked tiles, blit order, etc)
ObjectTemplate appearance;
std::shared_ptr<const ObjectTemplate> appearance;
/// If true hero can visit this object only from neighbouring tiles and can't stand on this object
bool blockVisit;

View File

@ -183,7 +183,7 @@ void CRewardableConstructor::initTypeData(const JsonNode & config)
objectInfo.init(config);
}
CGObjectInstance * CRewardableConstructor::create(const ObjectTemplate & tmpl) const
CGObjectInstance * CRewardableConstructor::create(std::shared_ptr<const ObjectTemplate> tmpl) const
{
auto ret = new CRewardableObject();
preInitObject(ret);
@ -196,7 +196,7 @@ void CRewardableConstructor::configureObject(CGObjectInstance * object, CRandomG
objectInfo.configureObject(dynamic_cast<CRewardableObject*>(object), rng);
}
std::unique_ptr<IObjectInfo> CRewardableConstructor::getObjectInfo(const ObjectTemplate & tmpl) const
std::unique_ptr<IObjectInfo> CRewardableConstructor::getObjectInfo(std::shared_ptr<const ObjectTemplate> tmpl) const
{
return std::unique_ptr<IObjectInfo>(new CRandomRewardObjectInfo(objectInfo));
}

View File

@ -49,9 +49,9 @@ class DLL_LINKAGE CRewardableConstructor : public AObjectTypeHandler
public:
CRewardableConstructor();
CGObjectInstance * create(const ObjectTemplate & tmpl) const override;
CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const override;
void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override;
std::unique_ptr<IObjectInfo> getObjectInfo(const ObjectTemplate & tmpl) const override;
std::unique_ptr<IObjectInfo> getObjectInfo(std::shared_ptr<const ObjectTemplate> tmpl) const override;
};

View File

@ -1122,7 +1122,7 @@ std::vector<int3> CGMagicSpring::getVisitableOffsets() const
for(int y = 0; y < 6; y++)
for (int x = 0; x < 8; x++) //starting from left
if (appearance.isVisitableAt(x, y))
if (appearance->isVisitableAt(x, y))
visitableTiles.push_back (int3(x, y , 0));
return visitableTiles;

View File

@ -56,7 +56,7 @@ void CTownInstanceConstructor::afterLoadFinalization()
}
}
bool CTownInstanceConstructor::objectFilter(const CGObjectInstance * object, const ObjectTemplate & templ) const
bool CTownInstanceConstructor::objectFilter(const CGObjectInstance * object, std::shared_ptr<const ObjectTemplate> templ) const
{
auto town = dynamic_cast<const CGTownInstance *>(object);
@ -65,10 +65,10 @@ bool CTownInstanceConstructor::objectFilter(const CGObjectInstance * object, con
return town->hasBuilt(id);
};
return filters.count(templ.stringID) != 0 && filters.at(templ.stringID).test(buildTest);
return filters.count(templ->stringID) != 0 && filters.at(templ->stringID).test(buildTest);
}
CGObjectInstance * CTownInstanceConstructor::create(const ObjectTemplate & tmpl) const
CGObjectInstance * CTownInstanceConstructor::create(std::shared_ptr<const ObjectTemplate> tmpl) const
{
CGTownInstance * obj = createTyped(tmpl);
obj->town = faction->town;
@ -80,7 +80,7 @@ void CTownInstanceConstructor::configureObject(CGObjectInstance * object, CRando
{
auto templ = getOverride(object->cb->getTile(object->pos)->terType, object);
if(templ)
object->appearance = templ.get();
object->appearance = templ;
}
CHeroInstanceConstructor::CHeroInstanceConstructor()
@ -110,7 +110,7 @@ void CHeroInstanceConstructor::afterLoadFinalization()
}
}
bool CHeroInstanceConstructor::objectFilter(const CGObjectInstance * object, const ObjectTemplate & templ) const
bool CHeroInstanceConstructor::objectFilter(const CGObjectInstance * object, std::shared_ptr<const ObjectTemplate> templ) const
{
auto hero = dynamic_cast<const CGHeroInstance *>(object);
@ -119,14 +119,14 @@ bool CHeroInstanceConstructor::objectFilter(const CGObjectInstance * object, con
return hero->type->ID == id;
};
if(filters.count(templ.stringID))
if(filters.count(templ->stringID))
{
return filters.at(templ.stringID).test(heroTest);
return filters.at(templ->stringID).test(heroTest);
}
return false;
}
CGObjectInstance * CHeroInstanceConstructor::create(const ObjectTemplate & tmpl) const
CGObjectInstance * CHeroInstanceConstructor::create(std::shared_ptr<const ObjectTemplate> tmpl) const
{
CGHeroInstance * obj = createTyped(tmpl);
obj->type = nullptr; //FIXME: set to valid value. somehow.
@ -167,12 +167,12 @@ void CDwellingInstanceConstructor::initTypeData(const JsonNode & input)
guards = input["guards"];
}
bool CDwellingInstanceConstructor::objectFilter(const CGObjectInstance *, const ObjectTemplate &) const
bool CDwellingInstanceConstructor::objectFilter(const CGObjectInstance *, std::shared_ptr<const ObjectTemplate>) const
{
return false;
}
CGObjectInstance * CDwellingInstanceConstructor::create(const ObjectTemplate & tmpl) const
CGObjectInstance * CDwellingInstanceConstructor::create(std::shared_ptr<const ObjectTemplate> tmpl) const
{
CGDwelling * obj = createTyped(tmpl);
@ -272,7 +272,7 @@ void CBankInstanceConstructor::initTypeData(const JsonNode & input)
bankResetDuration = static_cast<si32>(input["resetDuration"].Float());
}
CGObjectInstance *CBankInstanceConstructor::create(const ObjectTemplate & tmpl) const
CGObjectInstance *CBankInstanceConstructor::create(std::shared_ptr<const ObjectTemplate> tmpl) const
{
return createTyped(tmpl);
}
@ -494,7 +494,7 @@ bool CBankInfo::givesSpells() const
}
std::unique_ptr<IObjectInfo> CBankInstanceConstructor::getObjectInfo(const ObjectTemplate & tmpl) const
std::unique_ptr<IObjectInfo> CBankInstanceConstructor::getObjectInfo(std::shared_ptr<const ObjectTemplate> tmpl) const
{
return std::unique_ptr<IObjectInfo>(new CBankInfo(levels));
}

View File

@ -26,17 +26,31 @@ template<class ObjectType>
class CDefaultObjectTypeHandler : public AObjectTypeHandler
{
protected:
ObjectType * createTyped(const ObjectTemplate & tmpl) const
ObjectType * createTyped(std::shared_ptr<const ObjectTemplate> tmpl /* = nullptr */) const
{
auto obj = new ObjectType();
preInitObject(obj);
obj->appearance = tmpl;
if (tmpl)
{
obj->appearance = tmpl;
}
else
{
auto templates = getTemplates();
if (templates.empty())
{
throw std::runtime_error("No handler for created object");
}
obj->appearance = templates.front(); //just any template for now, will be initialized later
}
return obj;
}
public:
CDefaultObjectTypeHandler() {}
CGObjectInstance * create(const ObjectTemplate & tmpl) const override
CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const override
{
return createTyped(tmpl);
}
@ -45,7 +59,7 @@ public:
{
}
virtual std::unique_ptr<IObjectInfo> getObjectInfo(const ObjectTemplate & tmpl) const override
virtual std::unique_ptr<IObjectInfo> getObjectInfo(std::shared_ptr<const ObjectTemplate> tmpl) const override
{
return nullptr;
}
@ -62,7 +76,7 @@ class CTownInstanceConstructor : public CDefaultObjectTypeHandler<CGTownInstance
{
JsonNode filtersJson;
protected:
bool objectFilter(const CGObjectInstance *, const ObjectTemplate &) const override;
bool objectFilter(const CGObjectInstance *, std::shared_ptr<const ObjectTemplate>) const override;
void initTypeData(const JsonNode & input) override;
public:
@ -70,7 +84,7 @@ public:
std::map<std::string, LogicalExpression<BuildingID>> filters;
CTownInstanceConstructor();
CGObjectInstance * create(const ObjectTemplate & tmpl) const override;
CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const override;
void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override;
void afterLoadFinalization() override;
@ -87,7 +101,7 @@ class CHeroInstanceConstructor : public CDefaultObjectTypeHandler<CGHeroInstance
{
JsonNode filtersJson;
protected:
bool objectFilter(const CGObjectInstance *, const ObjectTemplate &) const override;
bool objectFilter(const CGObjectInstance *, std::shared_ptr<const ObjectTemplate>) const override;
void initTypeData(const JsonNode & input) override;
public:
@ -95,7 +109,7 @@ public:
std::map<std::string, LogicalExpression<HeroTypeID>> filters;
CHeroInstanceConstructor();
CGObjectInstance * create(const ObjectTemplate & tmpl) const override;
CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const override;
void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override;
void afterLoadFinalization() override;
@ -115,13 +129,13 @@ class CDwellingInstanceConstructor : public CDefaultObjectTypeHandler<CGDwelling
JsonNode guards;
protected:
bool objectFilter(const CGObjectInstance *, const ObjectTemplate &) const override;
bool objectFilter(const CGObjectInstance *, std::shared_ptr<const ObjectTemplate> tmpl) const override;
void initTypeData(const JsonNode & input) override;
public:
CDwellingInstanceConstructor();
CGObjectInstance * create(const ObjectTemplate & tmpl) const override;
CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const override;
void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override;
bool producesCreature(const CCreature * crea) const;
@ -207,10 +221,10 @@ public:
CBankInstanceConstructor();
CGObjectInstance * create(const ObjectTemplate & tmpl) const override;
CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const override;
void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override;
std::unique_ptr<IObjectInfo> getObjectInfo(const ObjectTemplate & tmpl) const override;
std::unique_ptr<IObjectInfo> getObjectInfo(std::shared_ptr<const ObjectTemplate> tmpl) const override;
template <typename Handler> void serialize(Handler &h, const int version)
{

View File

@ -53,7 +53,9 @@ ObjectTemplate::ObjectTemplate():
id(Obj::NO_OBJ),
subid(0),
printPriority(0),
stringID("")
width(0),
height(0),
visitable(false)
{
}
@ -65,7 +67,13 @@ ObjectTemplate::ObjectTemplate(const ObjectTemplate& other):
printPriority(other.printPriority),
animationFile(other.animationFile),
editorAnimationFile(other.editorAnimationFile),
stringID(other.stringID)
stringID(other.stringID),
width(other.width),
height(other.height),
visitable(other.visitable),
blockedOffsets(other.blockedOffsets),
blockMapOffset(other.blockMapOffset),
visitableOffset(other.visitableOffset)
{
//default copy constructor is failing with usedTiles this for unknown reason
@ -84,11 +92,18 @@ ObjectTemplate & ObjectTemplate::operator=(const ObjectTemplate & rhs)
animationFile = rhs.animationFile;
editorAnimationFile = rhs.editorAnimationFile;
stringID = rhs.stringID;
width = rhs.width;
height = rhs.height;
visitable = rhs.visitable;
blockedOffsets = rhs.blockedOffsets;
blockMapOffset = rhs.blockMapOffset;
visitableOffset = rhs.visitableOffset;
usedTiles.clear();
usedTiles.resize(rhs.usedTiles.size());
for(size_t i = 0; i < usedTiles.size(); i++)
std::copy(rhs.usedTiles[i].begin(), rhs.usedTiles[i].end(), std::back_inserter(usedTiles[i]));
return *this;
}
@ -121,9 +136,9 @@ void ObjectTemplate::readTxt(CLegacyConfigParser & parser)
assert(visitStr.size() == 6*8);
setSize(8, 6);
for (size_t i=0; i<6; i++) // 6 rows
for(size_t i = 0; i < 6; i++) // 6 rows
{
for (size_t j=0; j<8; j++) // 8 columns
for(size_t j = 0; j < 8; j++) // 8 columns
{
auto & tile = usedTiles[i][j];
tile |= VISIBLE; // assume that all tiles are visible
@ -141,7 +156,7 @@ void ObjectTemplate::readTxt(CLegacyConfigParser & parser)
std::string & terrStr = strings[4]; // allowed terrains, 1 = object can be placed on this terrain
assert(terrStr.size() == 9); // all terrains but rock
for (size_t i=0; i<9; i++)
for(size_t i = 0; i < 9; i++)
{
if (terrStr[8-i] == '1')
allowedTerrains.insert(Terrain::createTerrainTypeH3M(i));
@ -168,6 +183,7 @@ void ObjectTemplate::readTxt(CLegacyConfigParser & parser)
visitDir = (8|16|32|64|128);
readMsk();
recalculate();
}
void ObjectTemplate::readMsk()
@ -197,9 +213,9 @@ void ObjectTemplate::readMap(CBinaryReader & reader)
for(auto & byte : visitMask)
byte = reader.readUInt8();
for (size_t i=0; i<6; i++) // 6 rows
for(size_t i = 0; i < 6; i++) // 6 rows
{
for (size_t j=0; j<8; j++) // 8 columns
for(size_t j = 0; j < 8; j++) // 8 columns
{
auto & tile = usedTiles[5 - i][7 - j];
tile |= VISIBLE; // assume that all tiles are visible
@ -213,7 +229,7 @@ void ObjectTemplate::readMap(CBinaryReader & reader)
reader.readUInt16();
ui16 terrMask = reader.readUInt16();
for (size_t i=0; i<9; i++)
for(size_t i = 0; i < 9; i++)
{
if (((terrMask >> i) & 1 ) != 0)
allowedTerrains.insert(Terrain::createTerrainTypeH3M(i));
@ -243,6 +259,7 @@ void ObjectTemplate::readMap(CBinaryReader & reader)
readMsk();
afterLoadFixup();
recalculate();
}
void ObjectTemplate::readJson(const JsonNode &node, const bool withTerrain)
@ -288,16 +305,16 @@ void ObjectTemplate::readJson(const JsonNode &node, const bool withTerrain)
{
switch (ch)
{
case ' ' : return 0;
case '0' : return 0;
case 'V' : return VISIBLE;
case 'B' : return VISIBLE | BLOCKED;
case 'H' : return BLOCKED;
case 'A' : return VISIBLE | BLOCKED | VISITABLE;
case 'T' : return BLOCKED | VISITABLE;
default:
logGlobal->error("Unrecognized char %s in template mask", ch);
return 0;
case ' ' : return 0;
case '0' : return 0;
case 'V' : return VISIBLE;
case 'B' : return VISIBLE | BLOCKED;
case 'H' : return BLOCKED;
case 'A' : return VISIBLE | BLOCKED | VISITABLE;
case 'T' : return BLOCKED | VISITABLE;
default:
logGlobal->error("Unrecognized char %s in template mask", ch);
return 0;
}
};
@ -320,6 +337,7 @@ void ObjectTemplate::readJson(const JsonNode &node, const bool withTerrain)
printPriority = static_cast<si32>(node["zIndex"].Float());
afterLoadFixup();
recalculate();
}
void ObjectTemplate::writeJson(JsonNode & node, const bool withTerrain) const
@ -413,38 +431,42 @@ void ObjectTemplate::writeJson(JsonNode & node, const bool withTerrain) const
node["zIndex"].Float() = printPriority;
}
ui32 ObjectTemplate::getWidth() const
void ObjectTemplate::calculateWidth()
{
//TODO: Use 2D array
//TODO: better precalculate and store constant value
ui32 ret = 0;
for (const auto &row : usedTiles) //copy is expensive
for(const auto& row : usedTiles) //copy is expensive
{
ret = std::max<ui32>(ret, (ui32)row.size());
width = std::max<ui32>(width, (ui32)row.size());
}
return ret;
}
ui32 ObjectTemplate::getHeight() const
void ObjectTemplate::calculateHeight()
{
//TODO: Use 2D array
return static_cast<ui32>(usedTiles.size());
height = static_cast<ui32>(usedTiles.size());
}
void ObjectTemplate::setSize(ui32 width, ui32 height)
{
usedTiles.resize(height);
for (auto & line : usedTiles)
for(auto & line : usedTiles)
line.resize(width, 0);
}
bool ObjectTemplate::isVisitable() const
void ObjectTemplate::calculateVsitable()
{
for (auto & line : usedTiles)
for (auto & tile : line)
for(auto& line : usedTiles)
{
for(auto& tile : line)
{
if (tile & VISITABLE)
return true;
return false;
{
visitable = true;
return;
}
}
}
visitable = false;
}
bool ObjectTemplate::isWithin(si32 X, si32 Y) const
@ -469,31 +491,33 @@ bool ObjectTemplate::isBlockedAt(si32 X, si32 Y) const
return isWithin(X, Y) && usedTiles[Y][X] & BLOCKED;
}
std::set<int3> ObjectTemplate::getBlockedOffsets() const
void ObjectTemplate::calculateBlockedOffsets()
{
std::set<int3> ret;
blockedOffsets.clear();
for(int w = 0; w < (int)getWidth(); ++w)
{
for(int h = 0; h < (int)getHeight(); ++h)
{
if (isBlockedAt(w, h))
ret.insert(int3(-w, -h, 0));
blockedOffsets.insert(int3(-w, -h, 0));
}
}
return ret;
}
int3 ObjectTemplate::getBlockMapOffset() const
void ObjectTemplate::calculateBlockMapOffset()
{
for(int w = 0; w < (int)getWidth(); ++w)
{
for(int h = 0; h < (int)getHeight(); ++h)
{
if (isBlockedAt(w, h))
return int3(w, h, 0);
{
blockMapOffset = int3(w, h, 0);
return;
}
}
}
return int3(0,0,0);
blockMapOffset = int3(0, 0, 0);
}
bool ObjectTemplate::isVisitableFrom(si8 X, si8 Y) const
@ -502,6 +526,7 @@ bool ObjectTemplate::isVisitableFrom(si8 X, si8 Y) const
// 1 2 3
// 8 4
// 7 6 5
//TODO: static? cached?
int dirMap[3][3] =
{
{ visitDir & 1, visitDir & 2, visitDir & 4 },
@ -515,22 +540,20 @@ bool ObjectTemplate::isVisitableFrom(si8 X, si8 Y) const
return dirMap[dy][dx] != 0;
}
int3 ObjectTemplate::getVisitableOffset() const
void ObjectTemplate::calculateVisitableOffset()
{
for(int y = 0; y < (int)getHeight(); y++)
for (int x = 0; x < (int)getWidth(); x++)
{
for(int x = 0; x < (int)getWidth(); x++)
{
if (isVisitableAt(x, y))
return int3(x,y,0);
//logGlobal->warn("Warning: getVisitableOffset called on non-visitable obj!");
return int3(0,0,0);
}
bool ObjectTemplate::isVisitableFromTop() const
{
return visitDir & 2;
//for some reason the line below is never called :?
//return isVisitableFrom (0, 1);
{
visitableOffset = int3(x, y, 0);
return;
}
}
}
visitableOffset = int3(0, 0, 0);
}
bool ObjectTemplate::canBePlacedAt(Terrain terrain) const
@ -538,3 +561,14 @@ bool ObjectTemplate::canBePlacedAt(Terrain terrain) const
return allowedTerrains.count(terrain) != 0;
}
void ObjectTemplate::recalculate()
{
calculateWidth();
calculateHeight();
calculateVsitable();
//The lines below use width and height
calculateBlockedOffsets();
calculateBlockMapOffset();
calculateVisitableOffset();
}

View File

@ -10,6 +10,7 @@
#pragma once
#include "../GameConstants.h"
#include "../int3.h"
class CBinaryReader;
class CLegacyConfigParser;
@ -50,11 +51,22 @@ public:
/// string ID, equals to def base name for h3m files (lower case, no extension) or specified in mod data
std::string stringID;
ui32 getWidth() const;
ui32 getHeight() const;
inline ui32 getWidth() const
{
return width;
};
inline ui32 getHeight() const
{
return height;
};
void setSize(ui32 width, ui32 height);
bool isVisitable() const;
inline bool isVisitable() const
{
return visitable;
};
// Checks object used tiles
// Position is relative to bottom-right corner of the object, can not be negative
@ -62,13 +74,29 @@ public:
bool isVisitableAt(si32 X, si32 Y) const;
bool isVisibleAt(si32 X, si32 Y) const;
bool isBlockedAt(si32 X, si32 Y) const;
std::set<int3> getBlockedOffsets() const;
int3 getBlockMapOffset() const; //bottom-right corner when firts blocked tile is
inline std::set<int3> getBlockedOffsets() const
{
return blockedOffsets;
};
inline int3 getBlockMapOffset() const
{
return blockMapOffset;
};
// Checks if object is visitable from certain direction. X and Y must be between -1..+1
bool isVisitableFrom(si8 X, si8 Y) const;
int3 getVisitableOffset() const;
bool isVisitableFromTop() const;
inline int3 getVisitableOffset() const
{
//logGlobal->warn("Warning: getVisitableOffset called on non-visitable obj!");
return visitableOffset;
};
inline bool isVisitableFromTop() const
{
return visitDir & 2;
};
// Checks if object can be placed on specific terrain
bool canBePlacedAt(Terrain terrain) const;
@ -87,6 +115,25 @@ public:
bool operator==(const ObjectTemplate& ot) const { return (id == ot.id && subid == ot.subid); }
private:
ui32 width;
ui32 height;
bool visitable;
std::set<int3> blockedOffsets;
int3 blockMapOffset;
int3 visitableOffset;
void recalculate();
void calculateWidth();
void calculateHeight();
void calculateVsitable();
void calculateBlockedOffsets();
void calculateBlockMapOffset();
void calculateVisitableOffset();
public:
template <typename Handler> void serialize(Handler &h, const int version)
{
h & usedTiles;
@ -98,6 +145,11 @@ public:
h & printPriority;
h & visitDir;
h & editorAnimationFile;
if (!h.saving)
{
recalculate();
}
}
};

View File

@ -146,7 +146,7 @@ public:
// FIXME: due to usage of JsonNode I can't make these methods const
const CGHeroInstance * strongestHero(PlayerColor owner);
std::vector<CGHeroInstance *> getLostCrossoverHeroes(); /// returns a list of crossover heroes which started the scenario, but didn't complete it
CCampaignScenario();
template <typename Handler> void serialize(Handler &h, const int formatVersion)

View File

@ -417,7 +417,7 @@ bool CMap::checkForVisitableDir(const int3 & src, const TerrainTile *pom, const
if(!vstd::contains(pom->blockingObjects, obj)) //this visitable object is not blocking, ignore
continue;
if (!obj->appearance.isVisitableFrom(src.x - dst.x, src.y - dst.y))
if (!obj->appearance->isVisitableFrom(src.x - dst.x, src.y - dst.y))
return false;
}
return true;

View File

@ -958,9 +958,9 @@ void CMapLoaderH3M::readDefInfo()
// Read custom defs
for(int idd = 0; idd < defAmount; ++idd)
{
ObjectTemplate tmpl;
tmpl.readMap(reader);
templates.push_back(tmpl);
auto tmpl = new ObjectTemplate;
tmpl->readMap(reader);
templates.push_back(std::shared_ptr<const ObjectTemplate>(tmpl));
}
}
@ -977,10 +977,10 @@ void CMapLoaderH3M::readObjects()
int defnum = reader.readUInt32();
ObjectInstanceID idToBeGiven = ObjectInstanceID((si32)map->objects.size());
ObjectTemplate & objTempl = templates.at(defnum);
std::shared_ptr<const ObjectTemplate> objTempl = templates.at(defnum);
reader.skip(5);
switch(objTempl.id)
switch(objTempl->id)
{
case Obj::EVENT:
{
@ -1212,15 +1212,15 @@ void CMapLoaderH3M::readObjects()
readMessageAndGuards(art->message, art);
if(objTempl.id == Obj::SPELL_SCROLL)
if(objTempl->id == Obj::SPELL_SCROLL)
{
spellID = reader.readUInt32();
artID = ArtifactID::SPELL_SCROLL;
}
else if(objTempl.id == Obj::ARTIFACT)
else if(objTempl->id == Obj::ARTIFACT)
{
//specific artifact
artID = objTempl.subid;
artID = objTempl->subid;
}
art->storedArtifact = CArtifactInstance::createArtifact(map, artID, spellID);
@ -1235,7 +1235,7 @@ void CMapLoaderH3M::readObjects()
readMessageAndGuards(res->message, res);
res->amount = reader.readUInt32();
if(objTempl.subid == Res::GOLD)
if(objTempl->subid == Res::GOLD)
{
// Gold is multiplied by 100.
res->amount *= 100;
@ -1246,7 +1246,7 @@ void CMapLoaderH3M::readObjects()
case Obj::RANDOM_TOWN:
case Obj::TOWN:
{
nobj = readTown(objTempl.subid);
nobj = readTown(objTempl->subid);
break;
}
case Obj::MINE:
@ -1347,7 +1347,7 @@ void CMapLoaderH3M::readObjects()
auto dwelling = new CGDwelling();
nobj = dwelling;
CSpecObjInfo * spec = nullptr;
switch(objTempl.id)
switch(objTempl->id)
{
case Obj::RANDOM_DWELLING:
spec = new CCreGenLeveledCastleInfo();
@ -1450,7 +1450,7 @@ void CMapLoaderH3M::readObjects()
}
case Obj::PYRAMID: //Pyramid of WoG object
{
if(objTempl.subid == 0)
if(objTempl->subid == 0)
{
nobj = new CBank();
}
@ -1470,13 +1470,13 @@ void CMapLoaderH3M::readObjects()
}
default: //any other object
{
if (VLC->objtypeh->knownSubObjects(objTempl.id).count(objTempl.subid))
if (VLC->objtypeh->knownSubObjects(objTempl->id).count(objTempl->subid))
{
nobj = VLC->objtypeh->getHandlerFor(objTempl.id, objTempl.subid)->create(objTempl);
nobj = VLC->objtypeh->getHandlerFor(objTempl->id, objTempl->subid)->create(objTempl);
}
else
{
logGlobal->warn("Unrecognized object: %d:%d at %s on map %s", objTempl.id.toEnum(), objTempl.subid, objPos.toString(), map->name);
logGlobal->warn("Unrecognized object: %d:%d at %s on map %s", objTempl->id.toEnum(), objTempl->subid, objPos.toString(), map->name);
nobj = new CGObjectInstance();
}
break;
@ -1484,11 +1484,11 @@ void CMapLoaderH3M::readObjects()
}
nobj->pos = objPos;
nobj->ID = objTempl.id;
nobj->ID = objTempl->id;
nobj->id = idToBeGiven;
if(nobj->ID != Obj::HERO && nobj->ID != Obj::HERO_PLACEHOLDER && nobj->ID != Obj::PRISON)
{
nobj->subID = objTempl.subid;
nobj->subID = objTempl->subid;
}
nobj->appearance = objTempl;
assert(idToBeGiven == ObjectInstanceID((si32)map->objects.size()));

View File

@ -245,7 +245,7 @@ private:
/** List of templates loaded from the map, used on later stage to create
* objects but not needed for fully functional CMap */
std::vector<ObjectTemplate> templates;
std::vector<std::shared_ptr<const ObjectTemplate>> templates;
/** ptr to the map object which gets filled by data from the buffer */
CMap * map;

View File

@ -1110,13 +1110,14 @@ void CMapLoaderJson::MapObjectLoader::construct()
auto handler = VLC->objtypeh->getHandlerFor(typeName, subtypeName);
ObjectTemplate appearance;
auto appearance = new ObjectTemplate;
appearance.id = Obj(handler->type);
appearance.subid = handler->subtype;
appearance.readJson(configuration["template"], false);
appearance->id = Obj(handler->type);
appearance->subid = handler->subtype;
appearance->readJson(configuration["template"], false);
instance = handler->create(appearance);
// Will be destroyed soon and replaced with shared template
instance = handler->create(std::shared_ptr<const ObjectTemplate>(appearance));
instance->id = ObjectInstanceID((si32)owner->map->objects.size());
instance->instanceName = jsonKey;

View File

@ -204,8 +204,8 @@ void ConnectionsPlacer::selfSideIndirectConnection(const rmg::ZoneConnection & c
auto & managerOther = *otherZone->getModificator<ObjectManager>();
auto factory = VLC->objtypeh->getHandlerFor(Obj::SUBTERRANEAN_GATE, 0);
auto gate1 = factory->create(ObjectTemplate());
auto gate2 = factory->create(ObjectTemplate());
auto gate1 = factory->create();
auto gate2 = factory->create();
rmg::Object rmgGate1(*gate1), rmgGate2(*gate2);
rmgGate1.setTemplate(zone.getTerrainType());
rmgGate2.setTemplate(otherZone->getTerrainType());
@ -249,8 +249,8 @@ void ConnectionsPlacer::selfSideIndirectConnection(const rmg::ZoneConnection & c
if(!success)
{
auto factory = VLC->objtypeh->getHandlerFor(Obj::MONOLITH_TWO_WAY, generator.getNextMonlithIndex());
auto teleport1 = factory->create(ObjectTemplate());
auto teleport2 = factory->create(ObjectTemplate());
auto teleport1 = factory->create();
auto teleport2 = factory->create();
zone.getModificator<ObjectManager>()->addRequiredObject(teleport1, connection.getGuardStrength());
otherZone->getModificator<ObjectManager>()->addRequiredObject(teleport2, connection.getGuardStrength());

View File

@ -367,7 +367,7 @@ void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateD
objects.push_back(&instance->object());
if(auto * m = zone.getModificator<RoadPlacer>())
{
if(instance->object().appearance.isVisitableFromTop())
if(instance->object().appearance->isVisitableFromTop())
m->areaForRoads().add(instance->getVisitablePosition());
else
{
@ -449,7 +449,7 @@ CGCreature * ObjectManager::chooseGuard(si32 strength, bool zoneGuard)
auto guardFactory = VLC->objtypeh->getHandlerFor(Obj::MONSTER, creId);
auto guard = (CGCreature *) guardFactory->create(ObjectTemplate());
auto guard = (CGCreature *) guardFactory->create();
guard->character = CGCreature::HOSTILE;
auto hlp = new CStackInstance(creId, amount);
//will be set during initialization

View File

@ -31,7 +31,7 @@ void ObstaclePlacer::process()
auto * riverManager = zone.getModificator<RiverPlacer>();
typedef std::vector<ObjectTemplate> ObstacleVector;
typedef std::vector<std::shared_ptr<const ObjectTemplate>> ObstacleVector;
//obstacleVector possibleObstacles;
std::map<int, ObstacleVector> obstaclesBySize;
@ -48,8 +48,8 @@ void ObstaclePlacer::process()
{
for(auto temp : handler->getTemplates())
{
if(temp.canBePlacedAt(zone.getTerrainType()) && temp.getBlockMapOffset().valid())
obstaclesBySize[temp.getBlockedOffsets().size()].push_back(temp);
if(temp->canBePlacedAt(zone.getTerrainType()) && temp->getBlockMapOffset().valid())
obstaclesBySize[temp->getBlockedOffsets().size()].push_back(temp);
}
}
}
@ -93,7 +93,7 @@ void ObstaclePlacer::process()
for(auto & temp : shuffledObstacles)
{
auto handler = VLC->objtypeh->getHandlerFor(temp.id, temp.subid);
auto handler = VLC->objtypeh->getHandlerFor(temp->id, temp->subid);
auto obj = handler->create(temp);
allObjects.emplace_back(*obj);
rmg::Object * rmgObject = &allObjects.back();

View File

@ -374,10 +374,10 @@ void RiverPlacer::connectRiver(const int3 & tile)
auto handler = VLC->objtypeh->getHandlerFor(RIVER_DELTA_ID, RIVER_DELTA_SUBTYPE);
assert(handler->isStaticObject());
std::vector<ObjectTemplate> tmplates;
std::vector<std::shared_ptr<const ObjectTemplate>> tmplates;
for(auto & temp : handler->getTemplates())
{
if(temp.canBePlacedAt(zone.getTerrainType()))
if(temp->canBePlacedAt(zone.getTerrainType()))
tmplates.push_back(temp);
}
@ -389,7 +389,7 @@ void RiverPlacer::connectRiver(const int3 & tile)
std::string targetTemplateName = RIVER_DELTA_TEMPLATE_NAME.at(river) + std::to_string(deltaOrientations[pos]) + ".def";
for(auto & templ : tmplates)
{
if(templ.animationFile == targetTemplateName)
if(templ->animationFile == targetTemplateName)
{
auto obj = handler->create(templ);
rmg::Object deltaObj(*obj, deltaPositions[pos]);

View File

@ -105,7 +105,7 @@ void Object::Instance::setPositionRaw(const int3 & position)
void Object::Instance::setTemplate(const Terrain & terrain)
{
if(dObject.appearance.id == Obj::NO_OBJ)
if(dObject.appearance->id == Obj::NO_OBJ)
{
auto templates = VLC->objtypeh->getHandlerFor(dObject.ID, dObject.subID)->getTemplates(terrain);
if(templates.empty())
@ -130,7 +130,7 @@ void Object::Instance::clear()
bool Object::Instance::isVisitableFrom(const int3 & position) const
{
auto relPosition = position - getPosition(true);
return dObject.appearance.isVisitableFrom(relPosition.x, relPosition.y);
return dObject.appearance->isVisitableFrom(relPosition.x, relPosition.y);
}
CGObjectInstance & Object::Instance::object()
@ -286,7 +286,7 @@ void Object::Instance::finalize(RmgMap & map)
throw rmgException(boost::to_string(boost::format("Tile %s of object %d at %s is outside the map") % tile.toString() % dObject.id % dObject.pos.toString()));
}
if (dObject.appearance.id == Obj::NO_OBJ)
if (dObject.appearance->id == Obj::NO_OBJ)
{
auto terrainType = map.map().getTile(getPosition(true)).terType;
auto templates = VLC->objtypeh->getHandlerFor(dObject.ID, dObject.subID)->getTemplates(terrainType);

View File

@ -69,7 +69,7 @@ void TownPlacer::placeTowns(ObjectManager & manager)
auto townFactory = VLC->objtypeh->getHandlerFor(Obj::TOWN, zone.getTownType());
CGTownInstance * town = (CGTownInstance *) townFactory->create(ObjectTemplate());
CGTownInstance * town = (CGTownInstance *) townFactory->create();
town->tempOwner = player;
town->builtBuildings.insert(BuildingID::FORT);
town->builtBuildings.insert(BuildingID::DEFAULT);
@ -163,7 +163,7 @@ bool TownPlacer::placeMines(ObjectManager & manager)
{
auto mineHandler = VLC->objtypeh->getHandlerFor(Obj::MINE, res);
auto & rmginfo = mineHandler->getRMGInfo();
auto mine = (CGMine*)mineHandler->create(ObjectTemplate());
auto mine = (CGMine*)mineHandler->create();
mine->producedResource = res;
mine->tempOwner = PlayerColor::NEUTRAL;
mine->producedQuantity = mine->defaultResProduction();
@ -184,7 +184,7 @@ bool TownPlacer::placeMines(ObjectManager & manager)
{
for(int rc = generator.rand.nextInt(1, extraRes); rc > 0; --rc)
{
auto resourse = (CGResource*) VLC->objtypeh->getHandlerFor(Obj::RESOURCE, mine->producedResource)->create(ObjectTemplate());
auto resourse = (CGResource*) VLC->objtypeh->getHandlerFor(Obj::RESOURCE, mine->producedResource)->create();
resourse->amount = CGResource::RANDOM_AMOUNT;
manager.addNearbyObject(resourse, mine);
}
@ -225,7 +225,7 @@ void TownPlacer::addNewTowns(int count, bool hasFort, PlayerColor player, Object
}
auto townFactory = VLC->objtypeh->getHandlerFor(Obj::TOWN, subType);
auto town = (CGTownInstance *) townFactory->create(ObjectTemplate());
auto town = (CGTownInstance *) townFactory->create();
town->ID = Obj::TOWN;
town->tempOwner = player;

View File

@ -59,11 +59,11 @@ void TreasurePlacer::addAllPossibleObjects()
{
for(auto temp : handler->getTemplates())
{
if(temp.canBePlacedAt(zone.getTerrainType()))
if(temp->canBePlacedAt(zone.getTerrainType()))
{
oi.generateObject = [temp]() -> CGObjectInstance *
{
return VLC->objtypeh->getHandlerFor(temp.id, temp.subid)->create(temp);
return VLC->objtypeh->getHandlerFor(temp->id, temp->subid)->create(temp);
};
auto rmgInfo = handler->getRMGInfo();
oi.value = rmgInfo.value;
@ -97,7 +97,7 @@ void TreasurePlacer::addAllPossibleObjects()
auto hid = *RandomGeneratorUtil::nextItem(possibleHeroes, generator.rand);
auto factory = VLC->objtypeh->getHandlerFor(Obj::PRISON, 0);
auto obj = (CGHeroInstance *) factory->create(ObjectTemplate());
auto obj = (CGHeroInstance *) factory->create();
obj->subID = hid; //will be initialized later
@ -159,7 +159,7 @@ void TreasurePlacer::addAllPossibleObjects()
for(auto tmplate : dwellingHandler->getTemplates())
{
if(tmplate.canBePlacedAt(zone.getTerrainType()))
if(tmplate->canBePlacedAt(zone.getTerrainType()))
{
oi.generateObject = [tmplate, secondaryID, dwellingType]() -> CGObjectInstance *
{
@ -181,7 +181,7 @@ void TreasurePlacer::addAllPossibleObjects()
oi.generateObject = [i, this]() -> CGObjectInstance *
{
auto factory = VLC->objtypeh->getHandlerFor(Obj::SPELL_SCROLL, 0);
auto obj = (CGArtifact *) factory->create(ObjectTemplate());
auto obj = (CGArtifact *) factory->create();
std::vector<SpellID> out;
for(auto spell : VLC->spellh->objects) //spellh size appears to be greater (?)
@ -207,7 +207,7 @@ void TreasurePlacer::addAllPossibleObjects()
oi.generateObject = [i]() -> CGObjectInstance *
{
auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0);
auto obj = (CGPandoraBox *) factory->create(ObjectTemplate());
auto obj = (CGPandoraBox *) factory->create();
obj->resources[Res::GOLD] = i * 5000;
return obj;
};
@ -223,7 +223,7 @@ void TreasurePlacer::addAllPossibleObjects()
oi.generateObject = [i]() -> CGObjectInstance *
{
auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0);
auto obj = (CGPandoraBox *) factory->create(ObjectTemplate());
auto obj = (CGPandoraBox *) factory->create();
obj->gainedExp = i * 5000;
return obj;
};
@ -275,7 +275,7 @@ void TreasurePlacer::addAllPossibleObjects()
oi.generateObject = [creature, creaturesAmount]() -> CGObjectInstance *
{
auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0);
auto obj = (CGPandoraBox *) factory->create(ObjectTemplate());
auto obj = (CGPandoraBox *) factory->create();
auto stack = new CStackInstance(creature, creaturesAmount);
obj->creatures.putStack(SlotID(0), stack);
return obj;
@ -292,7 +292,7 @@ void TreasurePlacer::addAllPossibleObjects()
oi.generateObject = [i, this]() -> CGObjectInstance *
{
auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0);
auto obj = (CGPandoraBox *) factory->create(ObjectTemplate());
auto obj = (CGPandoraBox *) factory->create();
std::vector <CSpell *> spells;
for(auto spell : VLC->spellh->objects)
@ -321,7 +321,7 @@ void TreasurePlacer::addAllPossibleObjects()
oi.generateObject = [i, this]() -> CGObjectInstance *
{
auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0);
auto obj = (CGPandoraBox *) factory->create(ObjectTemplate());
auto obj = (CGPandoraBox *) factory->create();
std::vector <CSpell *> spells;
for(auto spell : VLC->spellh->objects)
@ -349,7 +349,7 @@ void TreasurePlacer::addAllPossibleObjects()
oi.generateObject = [this]() -> CGObjectInstance *
{
auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0);
auto obj = (CGPandoraBox *) factory->create(ObjectTemplate());
auto obj = (CGPandoraBox *) factory->create();
std::vector <CSpell *> spells;
for(auto spell : VLC->spellh->objects)
@ -421,7 +421,7 @@ void TreasurePlacer::addAllPossibleObjects()
oi.generateObject = [creature, creaturesAmount, randomAppearance, this, generateArtInfo]() -> CGObjectInstance *
{
auto factory = VLC->objtypeh->getHandlerFor(Obj::SEER_HUT, randomAppearance);
auto obj = (CGSeerHut *) factory->create(ObjectTemplate());
auto obj = (CGSeerHut *) factory->create();
obj->rewardType = CGSeerHut::CREATURE;
obj->rID = creature->idNumber;
obj->rVal = creaturesAmount;
@ -457,7 +457,7 @@ void TreasurePlacer::addAllPossibleObjects()
oi.generateObject = [i, randomAppearance, this, generateArtInfo]() -> CGObjectInstance *
{
auto factory = VLC->objtypeh->getHandlerFor(Obj::SEER_HUT, randomAppearance);
auto obj = (CGSeerHut *) factory->create(ObjectTemplate());
auto obj = (CGSeerHut *) factory->create();
obj->rewardType = CGSeerHut::EXPERIENCE;
obj->rID = 0; //unitialized?
@ -481,7 +481,7 @@ void TreasurePlacer::addAllPossibleObjects()
oi.generateObject = [i, randomAppearance, this, generateArtInfo]() -> CGObjectInstance *
{
auto factory = VLC->objtypeh->getHandlerFor(Obj::SEER_HUT, randomAppearance);
auto obj = (CGSeerHut *) factory->create(ObjectTemplate());
auto obj = (CGSeerHut *) factory->create();
obj->rewardType = CGSeerHut::RESOURCES;
obj->rID = Res::GOLD;
obj->rVal = generator.getConfig().questRewardValues[i];
@ -525,7 +525,7 @@ std::vector<ObjectInfo*> TreasurePlacer::prepareTreasurePile(const CTreasureInfo
if(!oi) //fail
break;
if(oi->templ.isVisitableFromTop())
if(oi->templ->isVisitableFromTop())
{
objectInfos.push_back(oi);
}
@ -599,7 +599,7 @@ rmg::Object TreasurePlacer::constructTreasurePile(const std::vector<ObjectInfo*>
auto instanceAccessibleArea = instance.getAccessibleArea();
if(instance.getBlockedArea().getTilesVector().size() == 1)
{
if(instance.object().appearance.isVisitableFromTop() && instance.object().ID != Obj::CORPSE)
if(instance.object().appearance->isVisitableFromTop() && instance.object().ID != Obj::CORPSE)
instanceAccessibleArea.add(instance.getVisitablePosition());
}
@ -632,7 +632,7 @@ ObjectInfo * TreasurePlacer::getRandomObject(ui32 desiredValue, ui32 currentValu
if(oi.value > maxVal)
break; //this assumes values are sorted in ascending order
if(!oi.templ.isVisitableFromTop() && !allowLargeObjects)
if(!oi.templ->isVisitableFromTop() && !allowLargeObjects)
continue;
if(oi.value >= minValue && oi.maxPerZone > 0)

View File

@ -19,7 +19,7 @@ class CMapGenerator;
struct ObjectInfo
{
ObjectTemplate templ;
std::shared_ptr<const ObjectTemplate> templ;
ui32 value = 0;
ui16 probability = 0;
ui32 maxPerZone = -1;

View File

@ -200,7 +200,7 @@ bool WaterProxy::placeBoat(Zone & land, const Lake & lake, RouteInfo & info)
return false;
auto subObjects = VLC->objtypeh->knownSubObjects(Obj::BOAT);
auto* boat = (CGBoat*)VLC->objtypeh->getHandlerFor(Obj::BOAT, *RandomGeneratorUtil::nextItem(subObjects, generator.rand))->create(ObjectTemplate());
auto* boat = (CGBoat*)VLC->objtypeh->getHandlerFor(Obj::BOAT, *RandomGeneratorUtil::nextItem(subObjects, generator.rand))->create();
rmg::Object rmgObject(*boat);
rmgObject.setTemplate(zone.getTerrainType());
@ -259,7 +259,7 @@ bool WaterProxy::placeShipyard(Zone & land, const Lake & lake, si32 guard, Route
return false;
int subtype = chooseRandomAppearance(generator.rand, Obj::SHIPYARD, land.getTerrainType());
auto shipyard = (CGShipyard*) VLC->objtypeh->getHandlerFor(Obj::SHIPYARD, subtype)->create(ObjectTemplate());
auto shipyard = (CGShipyard*) VLC->objtypeh->getHandlerFor(Obj::SHIPYARD, subtype)->create();
shipyard->tempOwner = PlayerColor::NEUTRAL;
rmg::Object rmgObject(*shipyard);

View File

@ -382,6 +382,56 @@ public:
else
{
auto hlp = std::shared_ptr<NonConstT>(internalPtr);
data = hlp;
loadedSharedPointers[internalPtrDerived] = typeList.castSharedToMostDerived(hlp);
}
}
else
data.reset();
}
template <typename T>
void load(std::shared_ptr<const T> &data) //version of the above for const ptr
{
typedef typename std::remove_const<T>::type NonConstT;
NonConstT *internalPtr;
load(internalPtr);
void *internalPtrDerived = typeList.castToMostDerived(internalPtr);
if(internalPtr)
{
auto itr = loadedSharedPointers.find(internalPtrDerived);
if(itr != loadedSharedPointers.end())
{
// This pointer is already loaded. The "data" needs to be pointed to it,
// so their shared state is actually shared.
try
{
auto actualType = typeList.getTypeInfo(internalPtr);
auto typeWeNeedToReturn = typeList.getTypeInfo<T>();
if(*actualType == *typeWeNeedToReturn)
{
// No casting needed, just unpack already stored shared_ptr and return it
data = boost::any_cast<std::shared_ptr<const T>>(itr->second);
}
else
{
// We need to perform series of casts
auto ret = typeList.castShared(itr->second, actualType, typeWeNeedToReturn);
data = boost::any_cast<std::shared_ptr<const T>>(ret);
}
}
catch(std::exception &e)
{
logGlobal->error(e.what());
logGlobal->error("Failed to cast stored shared ptr. Real type: %s. Needed type %s. FIXME FIXME FIXME", itr->second.type().name(), typeid(std::shared_ptr<T>).name());
//TODO scenario with inheritance -> we can have stored ptr to base and load ptr to derived (or vice versa)
throw;
}
}
else
{
auto hlp = std::shared_ptr<const T>(internalPtr);
data = hlp; //possibly adds const
loadedSharedPointers[internalPtrDerived] = typeList.castSharedToMostDerived(hlp);
}

View File

@ -245,6 +245,12 @@ public:
save(internalPtr);
}
template <typename T>
void save(const std::shared_ptr<const T> &data)
{
const T *internalPtr = data.get();
save(internalPtr);
}
template <typename T>
void save(const std::unique_ptr<T> &data)
{
T *internalPtr = data.get();

View File

@ -12,8 +12,8 @@
#include "../ConstTransitivePtr.h"
#include "../GameConstants.h"
const ui32 SERIALIZATION_VERSION = 803;
const ui32 MINIMAL_SERIALIZATION_VERSION = 803;
const ui32 SERIALIZATION_VERSION = 804;
const ui32 MINIMAL_SERIALIZATION_VERSION = 804;
const std::string SAVEGAME_MAGIC = "VCMISVG";
class CHero;

View File

@ -1017,4 +1017,4 @@ std::vector<bool> CSpellHandler::getDefaultAllowed() const
}
return allowedSpells;
}
}