1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Merge remote-tracking branch 'upstream/develop' into cpp-map-editor

This commit is contained in:
nordsoft 2022-10-17 01:39:11 +04:00
commit d5403d3eb9
22 changed files with 311 additions and 133 deletions

View File

@ -17,6 +17,7 @@
#include "../../lib/mapObjects/CGTownInstance.h"
#include "../../lib/spells/CSpellHandler.h"
#include "../../lib/spells/ISpellMechanics.h"
#include "../../lib/battle/BattleStateInfoForRetreat.h"
#include "../../lib/CStack.h" // TODO: remove
// Eventually only IBattleInfoCallback and battle::Unit should be used,
// CUnitState should be private and CStack should be removed completely
@ -728,13 +729,34 @@ void CBattleAI::print(const std::string &text) const
boost::optional<BattleAction> CBattleAI::considerFleeingOrSurrendering()
{
if(cb->battleCanSurrender(playerID))
BattleStateInfoForRetreat bs;
bs.canFlee = cb->battleCanFlee();
bs.canSurrender = cb->battleCanSurrender(playerID);
bs.ourSide = cb->battleGetMySide();
bs.ourHero = cb->battleGetMyHero();
bs.enemyHero = nullptr;
for(auto stack : cb->battleGetAllStacks(false))
{
if(stack->alive())
{
if(stack->side == bs.ourSide)
bs.ourStacks.push_back(stack);
else
{
bs.enemyStacks.push_back(stack);
bs.enemyHero = cb->battleGetOwnerHero(stack);
}
}
}
if(cb->battleCanFlee())
if(!bs.canFlee || !bs.canSurrender)
{
return boost::none;
}
return boost::none;
return cb->makeSurrenderRetreatDecision(bs);
}

View File

@ -19,6 +19,7 @@
#include "../../lib/serializer/CTypeList.h"
#include "../../lib/serializer/BinarySerializer.h"
#include "../../lib/serializer/BinaryDeserializer.h"
#include "../../lib/battle/BattleStateInfoForRetreat.h"
#include "AIGateway.h"
#include "Goals/Goals.h"
@ -488,6 +489,24 @@ void AIGateway::showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositio
NET_EVENT_HANDLER;
}
boost::optional<BattleAction> AIGateway::makeSurrenderRetreatDecision(
const BattleStateInfoForRetreat & battleState)
{
LOG_TRACE(logAi);
NET_EVENT_HANDLER;
double fightRatio = battleState.getOurStrength() / (double)battleState.getEnemyStrength();
// if we have no towns - things are already bad, so retreat is not an option.
if(cb->getTownsInfo().size() && fightRatio < 0.3 && battleState.canFlee)
{
return BattleAction::makeRetreat(battleState.ourSide);
}
return boost::none;
}
void AIGateway::init(std::shared_ptr<Environment> env, std::shared_ptr<CCallback> CB)
{
LOG_TRACE(logAi);
@ -1017,8 +1036,10 @@ bool AIGateway::canRecruitAnyHero(const CGTownInstance * t) const
//TODO: make gathering gold, building tavern or conquering town (?) possible subgoals
if(!t)
t = findTownWithTavern();
if(!t)
if(!t || !townHasFreeTavern(t))
return false;
if(cb->getResourceAmount(Res::GOLD) < GameConstants::HERO_GOLD_COST) //TODO: use ResourceManager
return false;
if(cb->getHeroesInfo().size() >= ALLOWED_ROAMING_HEROES)
@ -1383,7 +1404,7 @@ void AIGateway::tryRealize(Goals::Trade & g) //trade
const CGTownInstance * AIGateway::findTownWithTavern() const
{
for(const CGTownInstance * t : cb->getTownsInfo())
if(t->hasBuilt(BuildingID::TAVERN) && !t->visitingHero)
if(townHasFreeTavern(t))
return t;
return nullptr;
@ -1414,34 +1435,6 @@ void AIGateway::buildArmyIn(const CGTownInstance * t)
moveCreaturesToHero(t);
}
void AIGateway::recruitHero(const CGTownInstance * t, bool throwing)
{
logAi->debug("Trying to recruit a hero in %s at %s", t->name, t->visitablePos().toString());
auto heroes = cb->getAvailableHeroes(t);
if(heroes.size())
{
auto hero = heroes[0];
if(heroes.size() >= 2) //makes sense to recruit two heroes with starting amries in first week
{
if(heroes[1]->getTotalStrength() > hero->getTotalStrength())
hero = heroes[1];
}
cb->recruitHero(t, hero);
nullkiller->heroManager->update();
if(t->visitingHero)
moveHeroToTile(t->visitablePos(), t->visitingHero.get());
throw goalFulfilledException(sptr(Goals::RecruitHero(t)));
}
else if(throwing)
{
throw cannotFulfillGoalException("No available heroes in tavern in " + t->nodeName());
}
}
void AIGateway::finish()
{
//we want to lock to avoid multiple threads from calling makingTurn->join() at same time

View File

@ -166,6 +166,7 @@ public:
void heroBonusChanged(const CGHeroInstance * hero, const Bonus & bonus, bool gain) override;
void showMarketWindow(const IMarket * market, const CGHeroInstance * visitor) override;
void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions) override;
boost::optional<BattleAction> makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) override;
void battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side) override;
void battleEnd(const BattleResult * br) override;
@ -176,7 +177,6 @@ public:
void endTurn();
// TODO: all the routines like recruiting hero or building army should be removed from here and extracted to elementar goals or whatever
void recruitHero(const CGTownInstance * t, bool throwing = false);
void recruitCreatures(const CGDwelling * d, const CArmedInstance * recruiter);
void pickBestCreatures(const CArmedInstance * army, const CArmedInstance * source); //called when we can't find a slot for new stack
void pickBestArtifacts(const CGHeroInstance * h, const CGHeroInstance * other = nullptr);

View File

@ -450,4 +450,14 @@ bool shouldVisit(const Nullkiller * ai, const CGHeroInstance * h, const CGObject
return true;
}
bool townHasFreeTavern(const CGTownInstance * town)
{
if(!town->hasBuilt(BuildingID::TAVERN)) return false;
if(!town->visitingHero) return true;
bool canMoveVisitingHeroToGarnison = !town->getUpperArmy()->stacksCount();
return canMoveVisitingHeroToGarnison;
}
}

View File

@ -238,6 +238,7 @@ bool isSafeToVisit(HeroPtr h, const CCreatureSet *, uint64_t dangerStrength);
bool compareHeroStrength(HeroPtr h1, HeroPtr h2);
bool compareArmyStrength(const CArmedInstance * a1, const CArmedInstance * a2);
bool compareArtifacts(const CArtifactInstance * a1, const CArtifactInstance * a2);
bool townHasFreeTavern(const CGTownInstance * town);
uint64_t timeElapsed(std::chrono::time_point<std::chrono::high_resolution_clock> start);

View File

@ -34,10 +34,40 @@ Goals::TGoalVec RecruitHeroBehavior::decompose() const
Goals::TGoalVec tasks;
auto towns = cb->getTownsInfo();
auto ourHeroes = ai->nullkiller->heroManager->getHeroRoles();
auto minScoreToHireMain = std::numeric_limits<float>::max();
for(auto hero : ourHeroes)
{
if(hero.second != HeroRole::MAIN)
continue;
auto newScore = ai->nullkiller->heroManager->evaluateHero(hero.first.get());
if(minScoreToHireMain > newScore)
{
// weakest main hero score
minScoreToHireMain = newScore;
}
}
for(auto town : towns)
{
if(!town->garrisonHero && !town->visitingHero && ai->canRecruitAnyHero(town))
if(ai->canRecruitAnyHero(town))
{
auto availableHeroes = cb->getAvailableHeroes(town);
for(auto hero : availableHeroes)
{
auto score = ai->nullkiller->heroManager->evaluateHero(hero);
if(score > minScoreToHireMain)
{
tasks.push_back(Goals::sptr(Goals::RecruitHero(town, hero).setpriority(200)));
break;
}
}
if(cb->getHeroesInfo().size() < cb->getTownsInfo().size() + 1
|| (ai->nullkiller->getFreeResources()[Res::GOLD] > 10000
&& ai->nullkiller->buildAnalyzer->getGoldPreasure() < MAX_GOLD_PEASURE))

View File

@ -35,16 +35,47 @@ void RecruitHero::accept(AIGateway * ai)
if(!t) t = ai->findTownWithTavern();
if(t)
{
ai->recruitHero(t, true);
//TODO try to free way to blocked town
//TODO: adventure map tavern or prison?
}
else
if(!t)
{
throw cannotFulfillGoalException("No town to recruit hero!");
}
logAi->debug("Trying to recruit a hero in %s at %s", t->name, t->visitablePos().toString());
auto heroes = cb->getAvailableHeroes(t);
if(!heroes.size())
{
throw cannotFulfillGoalException("No available heroes in tavern in " + t->nodeName());
}
auto heroToHire = heroes[0];
for(auto hero : heroes)
{
if(objid == hero->id.getNum())
{
heroToHire = hero;
break;
}
if(hero->getTotalStrength() > heroToHire->getTotalStrength())
heroToHire = hero;
}
if(t->visitingHero)
{
cb->swapGarrisonHero(t);
}
if(t->visitingHero)
throw cannotFulfillGoalException("Town " + t->nodeName() + " is occupied. Cannot recruit hero!");
cb->recruitHero(t, heroToHire);
ai->nullkiller->heroManager->update();
if(t->visitingHero)
ai->moveHeroToTile(t->visitablePos(), t->visitingHero.get());
}
}
}

View File

@ -387,3 +387,9 @@ bool CBattleCallback::battleMakeTacticAction( BattleAction * action )
sendRequest(&ma);
return true;
}
boost::optional<BattleAction> CBattleCallback::makeSurrenderRetreatDecision(
const BattleStateInfoForRetreat & battleState)
{
return cl->playerint[getPlayerID().get()]->makeSurrenderRetreatDecision(battleState);
}

View File

@ -32,6 +32,7 @@ struct CPackForServer;
class IBattleEventsReceiver;
class IGameEventsReceiver;
struct ArtifactLocation;
class BattleStateInfoForRetreat;
VCMI_LIB_NAMESPACE_END
@ -48,6 +49,7 @@ public:
//battle
virtual int battleMakeAction(const BattleAction * action) = 0;//for casting spells by hero - DO NOT use it for moving active stack
virtual bool battleMakeTacticAction(BattleAction * action) = 0; // performs tactic phase actions
virtual boost::optional<BattleAction> makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) = 0;
};
class IGameActionCallback
@ -104,6 +106,7 @@ public:
CBattleCallback(boost::optional<PlayerColor> Player, CClient *C);
int battleMakeAction(const BattleAction * action) override;//for casting spells by hero - DO NOT use it for moving active stack
bool battleMakeTacticAction(BattleAction * action) override; // performs tactic phase actions
boost::optional<BattleAction> makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) override;
#if SCRIPTING_ENABLED
scripting::Pool * getContextPool() const override;

View File

@ -12,6 +12,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
${MAIN_LIB_DIR}/battle/BattleHex.cpp
${MAIN_LIB_DIR}/battle/BattleInfo.cpp
${MAIN_LIB_DIR}/battle/BattleProxy.cpp
${MAIN_LIB_DIR}/battle/BattleStateInfoForRetreat.cpp
${MAIN_LIB_DIR}/battle/CBattleInfoCallback.cpp
${MAIN_LIB_DIR}/battle/CBattleInfoEssentials.cpp
${MAIN_LIB_DIR}/battle/CCallbackBase.cpp
@ -241,6 +242,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
${MAIN_LIB_DIR}/battle/BattleAttackInfo.h
${MAIN_LIB_DIR}/battle/BattleHex.h
${MAIN_LIB_DIR}/battle/BattleInfo.h
${MAIN_LIB_DIR}/battle/BattleStateInfoForRetreat.h
${MAIN_LIB_DIR}/battle/BattleProxy.h
${MAIN_LIB_DIR}/battle/CBattleInfoCallback.h
${MAIN_LIB_DIR}/battle/CBattleInfoEssentials.h

View File

@ -58,7 +58,9 @@ class CLoadFile;
class CSaveFile;
class BinaryDeserializer;
class BinarySerializer;
class BattleStateInfo;
struct ArtifactLocation;
class BattleStateInfoForRetreat;
#if SCRIPTING_ENABLED
namespace scripting
@ -93,7 +95,7 @@ public:
//pskill is gained primary skill, interface has to choose one of given skills and call callback with selection id
virtual void heroGotLevel(const CGHeroInstance *hero, PrimarySkill::PrimarySkill pskill, std::vector<SecondarySkill> &skills, QueryID queryID)=0;
virtual void commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, QueryID queryID)=0;
virtual void commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, QueryID queryID)=0;
// Show a dialog, player must take decision. If selection then he has to choose between one of given components,
// if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called
@ -108,6 +110,11 @@ public:
virtual void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions){};
virtual boost::optional<BattleAction> makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState)
{
return boost::none;
}
virtual void saveGame(BinarySerializer & h, const int version) = 0;
virtual void loadGame(BinaryDeserializer & h, const int version) = 0;
};

View File

@ -105,6 +105,22 @@ BattleAction BattleAction::makeEndOFTacticPhase(ui8 side)
return ba;
}
BattleAction BattleAction::makeSurrender(ui8 side)
{
BattleAction ba;
ba.side = side;
ba.actionType = EActionType::SURRENDER;
return ba;
}
BattleAction BattleAction::makeRetreat(ui8 side)
{
BattleAction ba;
ba.side = side;
ba.actionType = EActionType::RETREAT;
return ba;
}
std::string BattleAction::toString() const
{
std::stringstream actionTypeStream;

View File

@ -40,6 +40,8 @@ public:
static BattleAction makeCreatureSpellcast(const battle::Unit * stack, const battle::Target & target, SpellID spellID);
static BattleAction makeMove(const battle::Unit * stack, BattleHex dest);
static BattleAction makeEndOFTacticPhase(ui8 side);
static BattleAction makeRetreat(ui8 side);
static BattleAction makeSurrender(ui8 side);
std::string toString() const;

View File

@ -0,0 +1,52 @@
/*
* BattleStateInfoForRetreat.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "BattleStateInfoForRetreat.h"
#include "Unit.h"
#include "CBattleInfoCallback.h"
#include "../CCreatureSet.h"
#include "../mapObjects/CGHeroInstance.h"
VCMI_LIB_NAMESPACE_BEGIN
BattleStateInfoForRetreat::BattleStateInfoForRetreat()
: canFlee(false), canSurrender(false), isLastTurnBeforeDie(false), ourStacks(), enemyStacks(), ourHero(nullptr), enemyHero(nullptr), ourSide(-1)
{
}
uint64_t getFightingStrength(std::vector<const battle::Unit *> stacks, const CGHeroInstance * hero = nullptr)
{
uint64_t result = 0;
for(const battle::Unit * stack : stacks)
{
result += stack->creatureId().toCreature()->AIValue * stack->getCount();
}
if(hero)
{
result = (uint64_t)(result * hero->getFightingStrength());
}
return result;
}
uint64_t BattleStateInfoForRetreat::getOurStrength() const
{
return getFightingStrength(ourStacks, ourHero);
}
uint64_t BattleStateInfoForRetreat::getEnemyStrength() const
{
return getFightingStrength(enemyStacks, enemyHero);
}
VCMI_LIB_NAMESPACE_END

View File

@ -0,0 +1,38 @@
/*
* BattleStateInfoForRetreat.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
VCMI_LIB_NAMESPACE_BEGIN
namespace battle
{
class Unit;
}
class CGHeroInstance;
class DLL_LINKAGE BattleStateInfoForRetreat
{
public:
bool canFlee;
bool canSurrender;
bool isLastTurnBeforeDie;
ui8 ourSide;
std::vector<const battle::Unit *> ourStacks;
std::vector<const battle::Unit *> enemyStacks;
const CGHeroInstance * ourHero;
const CGHeroInstance * enemyHero;
BattleStateInfoForRetreat();
uint64_t getOurStrength() const;
uint64_t getEnemyStrength() const;
};
VCMI_LIB_NAMESPACE_END

View File

@ -116,13 +116,15 @@ std::vector<JsonNode> CObjectClassesHandler::loadLegacyData(size_t dataSize)
size_t totalNumber = static_cast<size_t>(parser.readNumber()); // first line contains number of objects to read and nothing else
parser.endLine();
for (size_t i=0; i<totalNumber; i++)
for (size_t i = 0; i < totalNumber; i++)
{
auto templ = new ObjectTemplate;
templ->readTxt(parser);
auto tmpl = new ObjectTemplate;
tmpl->readTxt(parser);
parser.endLine();
std::pair<si32, si32> key(templ->id.num, templ->subid);
legacyTemplates.insert(std::make_pair(key, std::shared_ptr<const ObjectTemplate>(templ)));
std::pair<si32, si32> key(tmpl->id.num, tmpl->subid);
legacyTemplates.insert(std::make_pair(key, std::shared_ptr<const ObjectTemplate>(tmpl)));
}
std::vector<JsonNode> ret(dataSize);// create storage for 256 objects
@ -560,10 +562,6 @@ SObjectSounds AObjectTypeHandler::getSounds() const
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);
}

View File

@ -197,9 +197,6 @@ void CGObjectInstance::setType(si32 ID, si32 subID)
{
const TerrainTile &tile = cb->gameState()->map->getTile(visitablePos());
this->ID = Obj(ID);
this->subID = subID;
//recalculate blockvis tiles - new appearance might have different blockmap than before
cb->gameState()->map->removeBlockVisTiles(this, true);
auto handler = VLC->objtypeh->getHandlerFor(ID, subID);
@ -212,11 +209,16 @@ void CGObjectInstance::setType(si32 ID, si32 subID)
appearance = handler->getTemplates(tile.terType->id)[0];
else
appearance = handler->getTemplates()[0]; // get at least some appearance since alternative is crash
if (ID == Obj::HERO)
if(this->ID == Obj::PRISON && ID == Obj::HERO)
{
//adjust for the prison offset
pos = visitablePos();
}
this->ID = Obj(ID);
this->subID = subID;
cb->gameState()->map->addBlockVisTiles(this);
}

View File

@ -33,19 +33,11 @@ protected:
auto obj = new ObjectType();
preInitObject(obj);
//Set custom template or leave null
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;
}

View File

@ -490,6 +490,7 @@ bool ObjectManager::addGuard(rmg::Object & object, si32 strength, bool zoneGuard
auto & instance = object.addInstance(*guard);
instance.setPosition(guardPos - object.getPosition());
instance.setAnyTemplate(); //terrain is irrelevant for monsters, but monsters need some template now
return true;
}

View File

@ -105,20 +105,26 @@ void Object::Instance::setPositionRaw(const int3 & position)
dObject.pos = dPosition + dParent.getPosition();
}
void Object::Instance::setTemplate(const TerrainId & terrain)
void Object::Instance::setAnyTemplate()
{
if(dObject.appearance->id == Obj::NO_OBJ)
auto templates = VLC->objtypeh->getHandlerFor(dObject.ID, dObject.subID)->getTemplates();
if(templates.empty())
throw rmgException(boost::to_string(boost::format("Did not find any graphics for object (%d,%d)") % dObject.ID % dObject.subID));
dObject.appearance = templates.front();
dAccessibleAreaCache.clear();
setPosition(getPosition(false));
}
void Object::Instance::setTemplate(TerrainId terrain)
{
auto templates = VLC->objtypeh->getHandlerFor(dObject.ID, dObject.subID)->getTemplates(terrain);
if (templates.empty())
{
auto templates = VLC->objtypeh->getHandlerFor(dObject.ID, dObject.subID)->getTemplates(terrain);
auto terrainName = VLC->terrainTypeHandler->terrains()[terrain].name;
if (templates.empty())
{
throw rmgException(boost::to_string(boost::format("Did not find graphics for object (%d,%d) at %s") %
dObject.ID % dObject.subID % terrainName));
}
dObject.appearance = templates.front();
throw rmgException(boost::to_string(boost::format("Did not find graphics for object (%d,%d) at %s") % dObject.ID % dObject.subID % terrainName));
}
dObject.appearance = templates.front();
dAccessibleAreaCache.clear();
setPosition(getPosition(false));
}
@ -283,6 +289,21 @@ void Object::Instance::finalize(RmgMap & map)
if(!map.isOnMap(getPosition(true)))
throw rmgException(boost::to_string(boost::format("Position of object %d at %s is outside the map") % dObject.id % getPosition(true).toString()));
//If no specific template was defined for this object, select any matching
if (!dObject.appearance)
{
auto terrainType = map.map().getTile(getPosition(true)).terType;
auto templates = VLC->objtypeh->getHandlerFor(dObject.ID, dObject.subID)->getTemplates(terrainType->id);
if (templates.empty())
{
throw rmgException(boost::to_string(boost::format("Did not find graphics for object (%d,%d) at %s (terrain %d)") % dObject.ID % dObject.subID % getPosition(true).toString() % terrainType));
}
else
{
setTemplate(terrainType->id);
}
}
if (dObject.isVisitable() && !map.isOnMap(dObject.visitablePos()))
throw rmgException(boost::to_string(boost::format("Visitable tile %s of object %d at %s is outside the map") % dObject.visitablePos().toString() % dObject.id % dObject.pos.toString()));
@ -292,17 +313,6 @@ 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)
{
auto terrainType = map.map().getTile(getPosition(true)).terType;
auto templates = VLC->objtypeh->getHandlerFor(dObject.ID, dObject.subID)->getTemplates(terrainType->id);
if (templates.empty())
throw rmgException(boost::to_string(boost::format("Did not find graphics for object (%d,%d) at %s (terrain %d)") %
dObject.ID % dObject.subID % getPosition(true).toString() % terrainType->name));
setTemplate(terrainType->id);
}
for(auto & tile : getBlockedArea().getTilesVector())
{
map.setOccupied(tile, ETileType::ETileType::USED);

View File

@ -35,7 +35,8 @@ public:
int3 getVisitablePosition() const;
bool isVisitableFrom(const int3 & tile) const;
const Area & getAccessibleArea() const;
void setTemplate(const TerrainId & terrain); //cache invalidation
void setTemplate(TerrainId terrain); //cache invalidation
void setAnyTemplate(); //cache invalidation
int3 getPosition(bool isAbsolute = false) const;
void setPosition(const int3 & position); //cache invalidation

View File

@ -391,56 +391,17 @@ public:
else
data.reset();
}
template <typename T>
void load(std::shared_ptr<const T> &data) //version of the above for const ptr
void load(std::shared_ptr<const T> & data)
{
typedef typename std::remove_const<T>::type NonConstT;
NonConstT *internalPtr;
load(internalPtr);
std::shared_ptr<T> nonConstData;
void *internalPtrDerived = typeList.castToMostDerived(internalPtr);
load(nonConstData);
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);
}
}
else
data.reset();
data = nonConstData;
}
template <typename T>
void load(std::unique_ptr<T> &data)
{