From 3d2dc2335bdc881e720caeb3afa8276dbd039ce2 Mon Sep 17 00:00:00 2001 From: DjWarmonger Date: Sun, 11 Sep 2022 15:12:35 +0200 Subject: [PATCH] Switch ObjectTemplate to shared_ptr (#870) --- client/Graphics.cpp | 18 +-- client/Graphics.h | 2 +- client/mapHandler.cpp | 6 +- lib/mapObjects/CGHeroInstance.cpp | 2 +- lib/mapObjects/CGTownInstance.cpp | 2 +- lib/mapObjects/CObjectClassesHandler.cpp | 63 +++++----- lib/mapObjects/CObjectClassesHandler.h | 22 ++-- lib/mapObjects/CObjectHandler.cpp | 20 ++-- lib/mapObjects/CObjectHandler.h | 2 +- lib/mapObjects/CRewardableConstructor.cpp | 4 +- lib/mapObjects/CRewardableConstructor.h | 4 +- lib/mapObjects/CRewardableObject.cpp | 2 +- lib/mapObjects/CommonConstructors.cpp | 24 ++-- lib/mapObjects/CommonConstructors.h | 38 ++++-- lib/mapObjects/ObjectTemplate.cpp | 138 ++++++++++++++-------- lib/mapObjects/ObjectTemplate.h | 66 +++++++++-- lib/mapping/CCampaignHandler.h | 2 +- lib/mapping/CMap.cpp | 2 +- lib/mapping/MapFormatH3M.cpp | 34 +++--- lib/mapping/MapFormatH3M.h | 2 +- lib/mapping/MapFormatJson.cpp | 11 +- lib/rmg/ConnectionsPlacer.cpp | 8 +- lib/rmg/ObjectManager.cpp | 4 +- lib/rmg/ObstaclePlacer.cpp | 8 +- lib/rmg/RiverPlacer.cpp | 6 +- lib/rmg/RmgObject.cpp | 6 +- lib/rmg/TownPlacer.cpp | 8 +- lib/rmg/TreasurePlacer.cpp | 34 +++--- lib/rmg/TreasurePlacer.h | 2 +- lib/rmg/WaterProxy.cpp | 4 +- lib/serializer/BinaryDeserializer.h | 50 ++++++++ lib/serializer/BinarySerializer.h | 6 + lib/serializer/CSerializer.h | 4 +- lib/spells/CSpellHandler.cpp | 2 +- 34 files changed, 384 insertions(+), 222 deletions(-) diff --git a/client/Graphics.cpp b/client/Graphics.cpp index 41b4a4507..e9d3ac2e5 100644 --- a/client/Graphics.cpp +++ b/client/Graphics.cpp @@ -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 Graphics::getAnimation(const CGObjectInstance* obj) return getAnimation(obj->appearance); } -std::shared_ptr Graphics::getAnimation(const ObjectTemplate & info) +std::shared_ptr Graphics::getAnimation(std::shared_ptr info) { //the only(?) invisible object - if(info.id == Obj::EVENT) + if(info->id == Obj::EVENT) { return std::shared_ptr(); } - 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(); } - std::shared_ptr ret = mapObjectAnimations[info.animationFile]; + std::shared_ptr ret = mapObjectAnimations[info->animationFile]; //already loaded if(ret) @@ -404,8 +404,8 @@ std::shared_ptr Graphics::getAnimation(const ObjectTemplate & info) return ret; } - ret = std::make_shared(info.animationFile); - mapObjectAnimations[info.animationFile] = ret; + ret = std::make_shared(info->animationFile); + mapObjectAnimations[info->animationFile] = ret; ret->preload(); return ret; diff --git a/client/Graphics.h b/client/Graphics.h index fbf41063a..c1461b064 100644 --- a/client/Graphics.h +++ b/client/Graphics.h @@ -98,7 +98,7 @@ public: void blueToPlayersAdv(SDL_Surface * sur, PlayerColor player); //replaces blue interface colour with a color of player std::shared_ptr getAnimation(const CGObjectInstance * obj); - std::shared_ptr getAnimation(const ObjectTemplate & info); + std::shared_ptr getAnimation(std::shared_ptr info); }; extern Graphics * graphics; diff --git a/client/mapHandler.cpp b/client/mapHandler.cpp index f33a8dad5..c9da73647 100644 --- a/client/mapHandler.cpp +++ b/client/mapHandler.cpp @@ -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; diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index dbe4e77c7..307f9df6c 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/lib/mapObjects/CGHeroInstance.cpp @@ -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 diff --git a/lib/mapObjects/CGTownInstance.cpp b/lib/mapObjects/CGTownInstance.cpp index 843f21326..e3b02e9cb 100644 --- a/lib/mapObjects/CGTownInstance.cpp +++ b/lib/mapObjects/CGTownInstance.cpp @@ -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 diff --git a/lib/mapObjects/CObjectClassesHandler.cpp b/lib/mapObjects/CObjectClassesHandler.cpp index b9525cb0a..4a3e8ad12 100644 --- a/lib/mapObjects/CObjectClassesHandler.cpp +++ b/lib/mapObjects/CObjectClassesHandler.cpp @@ -117,11 +117,11 @@ std::vector CObjectClassesHandler::loadLegacyData(size_t dataSize) for (size_t i=0; ireadTxt(parser); parser.endLine(); - std::pair key(templ.id.num, templ.subid); - legacyTemplates.insert(std::make_pair(key, templ)); + std::pair key(templ->id.num, templ->subid); + legacyTemplates.insert(std::make_pair(key, std::shared_ptr(templ))); } std::vector 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::optionalid = 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(tmpl)); } if (input["name"].isNull()) @@ -523,7 +522,7 @@ void AObjectTypeHandler::init(const JsonNode & input, boost::optional) 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 templ) { + //Otherwise the template remains constant + auto ptr = const_cast(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 AObjectTypeHandler::getTemplates() const +std::vector> AObjectTypeHandler::getTemplates() const { return templates; } @@ -580,14 +581,14 @@ BattleField AObjectTypeHandler::getBattlefield() const return battlefield ? BattleField::fromString(battlefield.get()) : BattleField::NONE; } -std::vector AObjectTypeHandler::getTemplates(const Terrain & terrainType) const +std::vector>AObjectTypeHandler::getTemplates(const Terrain & terrainType) const { - std::vector templates = getTemplates(); - std::vector filtered; + std::vector> templates = getTemplates(); + std::vector> 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 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 AObjectTypeHandler::getTemplates(const Terrain & ter return filtered; } -boost::optional AObjectTypeHandler::getOverride(const Terrain & terrainType, const CGObjectInstance * object) const +std::shared_ptr AObjectTypeHandler::getOverride(const Terrain & terrainType, const CGObjectInstance * object) const { - std::vector ret = getTemplates(terrainType); - for (auto & tmpl : ret) + std::vector> ret = getTemplates(terrainType); + for (const auto & tmpl: ret) { if (objectFilter(object, tmpl)) return tmpl; } - return boost::optional(); + return std::shared_ptr(); //empty } const RandomMapInfo & AObjectTypeHandler::getRMGInfo() diff --git a/lib/mapObjects/CObjectClassesHandler.h b/lib/mapObjects/CObjectClassesHandler.h index e578f585c..cff16a715 100644 --- a/lib/mapObjects/CObjectClassesHandler.h +++ b/lib/mapObjects/CObjectClassesHandler.h @@ -144,7 +144,7 @@ class DLL_LINKAGE AObjectTypeHandler : public boost::noncopyable JsonNode base; /// describes base template - std::vector templates; + std::vector> 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; /// initialization for classes that inherit this one virtual void initTypeData(const JsonNode & input); @@ -177,17 +177,21 @@ public: boost::optional getCustomName() const; SObjectSounds getSounds() const; - void addTemplate(const ObjectTemplate & templ); + void addTemplate(std::shared_ptr templ); void addTemplate(JsonNode config); /// returns all templates matching parameters - std::vector getTemplates() const; - std::vector getTemplates(const Terrain & terrainType) const; + std::vector> getTemplates() const; + std::vector> 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 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 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 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 getObjectInfo(const ObjectTemplate & tmpl) const = 0; + virtual std::unique_ptr getObjectInfo(std::shared_ptr tmpl) const = 0; template void serialize(Handler &h, const int version) { @@ -264,7 +268,7 @@ class DLL_LINKAGE CObjectClassesHandler : public IHandlerBase std::map > handlerConstructors; /// container with H3 templates, used only during loading, no need to serialize it - typedef std::multimap, ObjectTemplate> TTemplatesContainer; + typedef std::multimap, std::shared_ptr> TTemplatesContainer; TTemplatesContainer legacyTemplates; /// contains list of custom names for H3 objects (e.g. Dwellings), used to load H3 data diff --git a/lib/mapObjects/CObjectHandler.cpp b/lib/mapObjects/CObjectHandler.cpp index 4b1591d36..d78d79ede 100644 --- a/lib/mapObjects/CObjectHandler.cpp +++ b/lib/mapObjects/CObjectHandler.cpp @@ -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 CGObjectInstance::getBlockedPos() const @@ -179,7 +179,7 @@ std::set CGObjectInstance::getBlockedPos() const { for(int h=0; hisBlockedAt(w, h)) ret.insert(int3(pos.x - w, pos.y - h, pos.z)); } } @@ -188,7 +188,7 @@ std::set CGObjectInstance::getBlockedPos() const std::set 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); } diff --git a/lib/mapObjects/CObjectHandler.h b/lib/mapObjects/CObjectHandler.h index 851796db8..942d82d33 100644 --- a/lib/mapObjects/CObjectHandler.h +++ b/lib/mapObjects/CObjectHandler.h @@ -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 appearance; /// If true hero can visit this object only from neighbouring tiles and can't stand on this object bool blockVisit; diff --git a/lib/mapObjects/CRewardableConstructor.cpp b/lib/mapObjects/CRewardableConstructor.cpp index 971913571..21219f3f0 100644 --- a/lib/mapObjects/CRewardableConstructor.cpp +++ b/lib/mapObjects/CRewardableConstructor.cpp @@ -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 tmpl) const { auto ret = new CRewardableObject(); preInitObject(ret); @@ -196,7 +196,7 @@ void CRewardableConstructor::configureObject(CGObjectInstance * object, CRandomG objectInfo.configureObject(dynamic_cast(object), rng); } -std::unique_ptr CRewardableConstructor::getObjectInfo(const ObjectTemplate & tmpl) const +std::unique_ptr CRewardableConstructor::getObjectInfo(std::shared_ptr tmpl) const { return std::unique_ptr(new CRandomRewardObjectInfo(objectInfo)); } diff --git a/lib/mapObjects/CRewardableConstructor.h b/lib/mapObjects/CRewardableConstructor.h index 94c047bb6..4157ae7cb 100644 --- a/lib/mapObjects/CRewardableConstructor.h +++ b/lib/mapObjects/CRewardableConstructor.h @@ -49,9 +49,9 @@ class DLL_LINKAGE CRewardableConstructor : public AObjectTypeHandler public: CRewardableConstructor(); - CGObjectInstance * create(const ObjectTemplate & tmpl) const override; + CGObjectInstance * create(std::shared_ptr tmpl = nullptr) const override; void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override; - std::unique_ptr getObjectInfo(const ObjectTemplate & tmpl) const override; + std::unique_ptr getObjectInfo(std::shared_ptr tmpl) const override; }; diff --git a/lib/mapObjects/CRewardableObject.cpp b/lib/mapObjects/CRewardableObject.cpp index 638d61bc7..4caa94198 100644 --- a/lib/mapObjects/CRewardableObject.cpp +++ b/lib/mapObjects/CRewardableObject.cpp @@ -1122,7 +1122,7 @@ std::vector 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; diff --git a/lib/mapObjects/CommonConstructors.cpp b/lib/mapObjects/CommonConstructors.cpp index 6809175e5..3b870847a 100644 --- a/lib/mapObjects/CommonConstructors.cpp +++ b/lib/mapObjects/CommonConstructors.cpp @@ -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 templ) const { auto town = dynamic_cast(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 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 templ) const { auto hero = dynamic_cast(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 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 { return false; } -CGObjectInstance * CDwellingInstanceConstructor::create(const ObjectTemplate & tmpl) const +CGObjectInstance * CDwellingInstanceConstructor::create(std::shared_ptr tmpl) const { CGDwelling * obj = createTyped(tmpl); @@ -272,7 +272,7 @@ void CBankInstanceConstructor::initTypeData(const JsonNode & input) bankResetDuration = static_cast(input["resetDuration"].Float()); } -CGObjectInstance *CBankInstanceConstructor::create(const ObjectTemplate & tmpl) const +CGObjectInstance *CBankInstanceConstructor::create(std::shared_ptr tmpl) const { return createTyped(tmpl); } @@ -494,7 +494,7 @@ bool CBankInfo::givesSpells() const } -std::unique_ptr CBankInstanceConstructor::getObjectInfo(const ObjectTemplate & tmpl) const +std::unique_ptr CBankInstanceConstructor::getObjectInfo(std::shared_ptr tmpl) const { return std::unique_ptr(new CBankInfo(levels)); } diff --git a/lib/mapObjects/CommonConstructors.h b/lib/mapObjects/CommonConstructors.h index 1dc6ec5d1..605ad429c 100644 --- a/lib/mapObjects/CommonConstructors.h +++ b/lib/mapObjects/CommonConstructors.h @@ -26,17 +26,31 @@ template class CDefaultObjectTypeHandler : public AObjectTypeHandler { protected: - ObjectType * createTyped(const ObjectTemplate & tmpl) const + ObjectType * createTyped(std::shared_ptr 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 tmpl = nullptr) const override { return createTyped(tmpl); } @@ -45,7 +59,7 @@ public: { } - virtual std::unique_ptr getObjectInfo(const ObjectTemplate & tmpl) const override + virtual std::unique_ptr getObjectInfo(std::shared_ptr tmpl) const override { return nullptr; } @@ -62,7 +76,7 @@ class CTownInstanceConstructor : public CDefaultObjectTypeHandler) const override; void initTypeData(const JsonNode & input) override; public: @@ -70,7 +84,7 @@ public: std::map> filters; CTownInstanceConstructor(); - CGObjectInstance * create(const ObjectTemplate & tmpl) const override; + CGObjectInstance * create(std::shared_ptr tmpl = nullptr) const override; void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override; void afterLoadFinalization() override; @@ -87,7 +101,7 @@ class CHeroInstanceConstructor : public CDefaultObjectTypeHandler) const override; void initTypeData(const JsonNode & input) override; public: @@ -95,7 +109,7 @@ public: std::map> filters; CHeroInstanceConstructor(); - CGObjectInstance * create(const ObjectTemplate & tmpl) const override; + CGObjectInstance * create(std::shared_ptr tmpl = nullptr) const override; void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override; void afterLoadFinalization() override; @@ -115,13 +129,13 @@ class CDwellingInstanceConstructor : public CDefaultObjectTypeHandler tmpl) const override; void initTypeData(const JsonNode & input) override; public: CDwellingInstanceConstructor(); - CGObjectInstance * create(const ObjectTemplate & tmpl) const override; + CGObjectInstance * create(std::shared_ptr 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 tmpl = nullptr) const override; void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override; - std::unique_ptr getObjectInfo(const ObjectTemplate & tmpl) const override; + std::unique_ptr getObjectInfo(std::shared_ptr tmpl) const override; template void serialize(Handler &h, const int version) { diff --git a/lib/mapObjects/ObjectTemplate.cpp b/lib/mapObjects/ObjectTemplate.cpp index deaa1f63a..53b410de4 100644 --- a/lib/mapObjects/ObjectTemplate.cpp +++ b/lib/mapObjects/ObjectTemplate.cpp @@ -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(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(ret, (ui32)row.size()); + width = std::max(width, (ui32)row.size()); } - return ret; } -ui32 ObjectTemplate::getHeight() const +void ObjectTemplate::calculateHeight() { //TODO: Use 2D array - return static_cast(usedTiles.size()); + height = static_cast(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 ObjectTemplate::getBlockedOffsets() const +void ObjectTemplate::calculateBlockedOffsets() { - std::set 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(); +} + diff --git a/lib/mapObjects/ObjectTemplate.h b/lib/mapObjects/ObjectTemplate.h index 080561f2d..e10f1efad 100644 --- a/lib/mapObjects/ObjectTemplate.h +++ b/lib/mapObjects/ObjectTemplate.h @@ -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 getBlockedOffsets() const; - int3 getBlockMapOffset() const; //bottom-right corner when firts blocked tile is + + inline std::set 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 blockedOffsets; + int3 blockMapOffset; + int3 visitableOffset; + + void recalculate(); + + void calculateWidth(); + void calculateHeight(); + void calculateVsitable(); + void calculateBlockedOffsets(); + void calculateBlockMapOffset(); + void calculateVisitableOffset(); + +public: template void serialize(Handler &h, const int version) { h & usedTiles; @@ -98,6 +145,11 @@ public: h & printPriority; h & visitDir; h & editorAnimationFile; + + if (!h.saving) + { + recalculate(); + } } }; diff --git a/lib/mapping/CCampaignHandler.h b/lib/mapping/CCampaignHandler.h index ea1dd6f7f..1e3e923c1 100644 --- a/lib/mapping/CCampaignHandler.h +++ b/lib/mapping/CCampaignHandler.h @@ -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 getLostCrossoverHeroes(); /// returns a list of crossover heroes which started the scenario, but didn't complete it - + CCampaignScenario(); template void serialize(Handler &h, const int formatVersion) diff --git a/lib/mapping/CMap.cpp b/lib/mapping/CMap.cpp index 749a2e5b0..4130f5a94 100644 --- a/lib/mapping/CMap.cpp +++ b/lib/mapping/CMap.cpp @@ -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; diff --git a/lib/mapping/MapFormatH3M.cpp b/lib/mapping/MapFormatH3M.cpp index 9030e9737..d960975fc 100644 --- a/lib/mapping/MapFormatH3M.cpp +++ b/lib/mapping/MapFormatH3M.cpp @@ -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(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 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())); diff --git a/lib/mapping/MapFormatH3M.h b/lib/mapping/MapFormatH3M.h index 563932bd4..1a71f2d1d 100644 --- a/lib/mapping/MapFormatH3M.h +++ b/lib/mapping/MapFormatH3M.h @@ -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 templates; + std::vector> templates; /** ptr to the map object which gets filled by data from the buffer */ CMap * map; diff --git a/lib/mapping/MapFormatJson.cpp b/lib/mapping/MapFormatJson.cpp index ff08ba2c5..e14de101b 100644 --- a/lib/mapping/MapFormatJson.cpp +++ b/lib/mapping/MapFormatJson.cpp @@ -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(appearance)); instance->id = ObjectInstanceID((si32)owner->map->objects.size()); instance->instanceName = jsonKey; diff --git a/lib/rmg/ConnectionsPlacer.cpp b/lib/rmg/ConnectionsPlacer.cpp index 78aa17984..bd4633398 100644 --- a/lib/rmg/ConnectionsPlacer.cpp +++ b/lib/rmg/ConnectionsPlacer.cpp @@ -204,8 +204,8 @@ void ConnectionsPlacer::selfSideIndirectConnection(const rmg::ZoneConnection & c auto & managerOther = *otherZone->getModificator(); 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()->addRequiredObject(teleport1, connection.getGuardStrength()); otherZone->getModificator()->addRequiredObject(teleport2, connection.getGuardStrength()); diff --git a/lib/rmg/ObjectManager.cpp b/lib/rmg/ObjectManager.cpp index b995941d9..875b9974a 100644 --- a/lib/rmg/ObjectManager.cpp +++ b/lib/rmg/ObjectManager.cpp @@ -367,7 +367,7 @@ void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateD objects.push_back(&instance->object()); if(auto * m = zone.getModificator()) { - 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 diff --git a/lib/rmg/ObstaclePlacer.cpp b/lib/rmg/ObstaclePlacer.cpp index 9baa60917..a0c051fdb 100644 --- a/lib/rmg/ObstaclePlacer.cpp +++ b/lib/rmg/ObstaclePlacer.cpp @@ -31,7 +31,7 @@ void ObstaclePlacer::process() auto * riverManager = zone.getModificator(); - typedef std::vector ObstacleVector; + typedef std::vector> ObstacleVector; //obstacleVector possibleObstacles; std::map 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(); diff --git a/lib/rmg/RiverPlacer.cpp b/lib/rmg/RiverPlacer.cpp index a9086f056..599c1cded 100644 --- a/lib/rmg/RiverPlacer.cpp +++ b/lib/rmg/RiverPlacer.cpp @@ -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 tmplates; + std::vector> 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]); diff --git a/lib/rmg/RmgObject.cpp b/lib/rmg/RmgObject.cpp index 08d3bf7ac..9635daf53 100644 --- a/lib/rmg/RmgObject.cpp +++ b/lib/rmg/RmgObject.cpp @@ -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); diff --git a/lib/rmg/TownPlacer.cpp b/lib/rmg/TownPlacer.cpp index 2e10423b0..d33ae032b 100644 --- a/lib/rmg/TownPlacer.cpp +++ b/lib/rmg/TownPlacer.cpp @@ -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; diff --git a/lib/rmg/TreasurePlacer.cpp b/lib/rmg/TreasurePlacer.cpp index 7e24f2d28..cf1d58abb 100644 --- a/lib/rmg/TreasurePlacer.cpp +++ b/lib/rmg/TreasurePlacer.cpp @@ -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 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 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 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 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 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 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) diff --git a/lib/rmg/TreasurePlacer.h b/lib/rmg/TreasurePlacer.h index b3ecf39f7..457ef35a8 100644 --- a/lib/rmg/TreasurePlacer.h +++ b/lib/rmg/TreasurePlacer.h @@ -19,7 +19,7 @@ class CMapGenerator; struct ObjectInfo { - ObjectTemplate templ; + std::shared_ptr templ; ui32 value = 0; ui16 probability = 0; ui32 maxPerZone = -1; diff --git a/lib/rmg/WaterProxy.cpp b/lib/rmg/WaterProxy.cpp index 5b5354c45..777cf8c11 100644 --- a/lib/rmg/WaterProxy.cpp +++ b/lib/rmg/WaterProxy.cpp @@ -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); diff --git a/lib/serializer/BinaryDeserializer.h b/lib/serializer/BinaryDeserializer.h index b98025d05..f8065732a 100644 --- a/lib/serializer/BinaryDeserializer.h +++ b/lib/serializer/BinaryDeserializer.h @@ -382,6 +382,56 @@ public: else { auto hlp = std::shared_ptr(internalPtr); + data = hlp; + loadedSharedPointers[internalPtrDerived] = typeList.castSharedToMostDerived(hlp); + } + } + else + data.reset(); + } + template + void load(std::shared_ptr &data) //version of the above for const ptr + { + typedef typename std::remove_const::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(); + if(*actualType == *typeWeNeedToReturn) + { + // No casting needed, just unpack already stored shared_ptr and return it + data = boost::any_cast>(itr->second); + } + else + { + // We need to perform series of casts + auto ret = typeList.castShared(itr->second, actualType, typeWeNeedToReturn); + data = boost::any_cast>(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).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(internalPtr); data = hlp; //possibly adds const loadedSharedPointers[internalPtrDerived] = typeList.castSharedToMostDerived(hlp); } diff --git a/lib/serializer/BinarySerializer.h b/lib/serializer/BinarySerializer.h index f8272855a..7d3914205 100644 --- a/lib/serializer/BinarySerializer.h +++ b/lib/serializer/BinarySerializer.h @@ -245,6 +245,12 @@ public: save(internalPtr); } template + void save(const std::shared_ptr &data) + { + const T *internalPtr = data.get(); + save(internalPtr); + } + template void save(const std::unique_ptr &data) { T *internalPtr = data.get(); diff --git a/lib/serializer/CSerializer.h b/lib/serializer/CSerializer.h index e07e48d04..76b73331b 100644 --- a/lib/serializer/CSerializer.h +++ b/lib/serializer/CSerializer.h @@ -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; diff --git a/lib/spells/CSpellHandler.cpp b/lib/spells/CSpellHandler.cpp index 358a91bef..aca31549c 100644 --- a/lib/spells/CSpellHandler.cpp +++ b/lib/spells/CSpellHandler.cpp @@ -1017,4 +1017,4 @@ std::vector CSpellHandler::getDefaultAllowed() const } return allowedSpells; -} +} \ No newline at end of file