1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-03-29 21:56:54 +02:00

Merge branch 'develop' into autosave

This commit is contained in:
Michael 2023-08-23 21:39:04 +02:00 committed by GitHub
commit b22a9ff2d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
126 changed files with 416 additions and 457 deletions

View File

@ -34,26 +34,26 @@ const float RETREAT_THRESHOLD = 0.3f;
const double RETREAT_ABSOLUTE_THRESHOLD = 10000.;
//one thread may be turn of AI and another will be handling a side effect for AI2
boost::thread_specific_ptr<CCallback> cb;
boost::thread_specific_ptr<AIGateway> ai;
thread_local CCallback * cb = nullptr;
thread_local AIGateway * ai = nullptr;
//helper RAII to manage global ai/cb ptrs
struct SetGlobalState
{
SetGlobalState(AIGateway * AI)
{
assert(!ai.get());
assert(!cb.get());
assert(!ai);
assert(!cb);
ai.reset(AI);
cb.reset(AI->myCb.get());
ai = AI;
cb = AI->myCb.get();
}
~SetGlobalState()
{
//TODO: how to handle rm? shouldn't be called after ai is destroyed, hopefully
//TODO: to ensure that, make rm unique_ptr
ai.release();
cb.release();
ai = nullptr;
cb = nullptr;
}
};
@ -1472,6 +1472,8 @@ void AIGateway::requestActionASAP(std::function<void()> whatToDo)
boost::shared_lock<boost::shared_mutex> gsLock(CGameState::mutex);
whatToDo();
});
newThread.detach();
}
void AIGateway::lostHero(HeroPtr h)
@ -1605,7 +1607,7 @@ void AIStatus::waitTillFree()
{
boost::unique_lock<boost::mutex> lock(mx);
while(battle != NO_BATTLE || !remainingQueries.empty() || !objectsBeingVisited.empty() || ongoingHeroMovement)
cv.timed_wait(lock, boost::posix_time::milliseconds(10));
cv.wait_for(lock, boost::chrono::milliseconds(10));
}
bool AIStatus::haveTurn()

View File

@ -25,10 +25,6 @@
namespace NKAI
{
extern boost::thread_specific_ptr<AIGateway> ai;
//extern static const int3 dirs[8];
const CGObjectInstance * ObjectIdRef::operator->() const
{
return cb->getObj(id, false);

View File

@ -57,6 +57,7 @@ using dwellingContent = std::pair<ui32, std::vector<CreatureID>>;
namespace NKAI
{
struct creInfo;
class AIGateway;
class Nullkiller;
const int GOLD_MINE_PRODUCTION = 1000, WOOD_ORE_MINE_PRODUCTION = 2, RESOURCE_MINE_PRODUCTION = 1;
@ -67,7 +68,8 @@ const int ALLOWED_ROAMING_HEROES = 8;
extern const float SAFE_ATTACK_CONSTANT;
extern const int GOLD_RESERVE;
extern boost::thread_specific_ptr<CCallback> cb;
extern thread_local CCallback * cb;
extern thread_local AIGateway * ai;
enum HeroRole
{
@ -201,7 +203,7 @@ void foreach_tile_pos(CCallback * cbp, const Func & foo) // avoid costly retriev
template<class Func>
void foreach_neighbour(const int3 & pos, const Func & foo)
{
CCallback * cbp = cb.get(); // avoid costly retrieval of thread-specific pointer
CCallback * cbp = cb; // avoid costly retrieval of thread-specific pointer
for(const int3 & dir : int3::getDirs())
{
const int3 n = pos + dir;

View File

@ -20,9 +20,6 @@
namespace NKAI
{
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<AIGateway> ai;
using namespace Goals;
std::string BuildingBehavior::toString() const

View File

@ -17,9 +17,6 @@
namespace NKAI
{
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<AIGateway> ai;
using namespace Goals;
std::string BuyArmyBehavior::toString() const

View File

@ -19,9 +19,6 @@
namespace NKAI
{
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<AIGateway> ai;
using namespace Goals;
template <typename T>

View File

@ -19,9 +19,6 @@
namespace NKAI
{
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<AIGateway> ai;
using namespace Goals;
std::string ClusterBehavior::toString() const

View File

@ -25,9 +25,6 @@
namespace NKAI
{
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<AIGateway> ai;
const float TREAT_IGNORE_RATIO = 2;
using namespace Goals;

View File

@ -23,9 +23,6 @@
namespace NKAI
{
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<AIGateway> ai;
using namespace Goals;
std::string GatherArmyBehavior::toString() const

View File

@ -17,9 +17,6 @@
namespace NKAI
{
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<AIGateway> ai;
using namespace Goals;
std::string RecruitHeroBehavior::toString() const

View File

@ -21,9 +21,6 @@
namespace NKAI
{
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<AIGateway> ai;
using namespace Goals;
std::string StartupBehavior::toString() const

View File

@ -24,9 +24,6 @@
namespace NKAI
{
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<AIGateway> ai;
using namespace Goals;
void DeepDecomposer::reset()

View File

@ -20,8 +20,6 @@ namespace NKAI
#define MIN_AI_STRENGTH (0.5f) //lower when combat AI gets smarter
#define UNGUARDED_OBJECT (100.0f) //we consider unguarded objects 100 times weaker than us
extern boost::thread_specific_ptr<AIGateway> ai;
engineBase::engineBase()
{
rules = new fl::RuleBlock();

View File

@ -24,9 +24,6 @@
namespace NKAI
{
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<AIGateway> ai;
using namespace Goals;
#if NKAI_TRACE_LEVEL >= 1
@ -341,7 +338,7 @@ void Nullkiller::executeTask(Goals::TTask task)
try
{
task->accept(ai.get());
task->accept(ai);
logAi->trace("Task %s completed in %lld", taskDescr, timeElapsed(start));
}
catch(goalFulfilledException &)

View File

@ -15,9 +15,6 @@
namespace NKAI
{
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<AIGateway> ai;
using namespace Goals;
TSubgoal Goals::sptr(const AbstractGoal & tmp)

View File

@ -14,9 +14,6 @@
namespace NKAI
{
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<AIGateway> ai;
using namespace Goals;
bool AdventureSpellCast::operator==(const AdventureSpellCast & other) const

View File

@ -15,9 +15,6 @@
namespace NKAI
{
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<AIGateway> ai;
using namespace Goals;
bool BuildBoat::operator==(const BuildBoat & other) const

View File

@ -17,12 +17,8 @@
namespace NKAI
{
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<AIGateway> ai;
using namespace Goals;
BuildThis::BuildThis(BuildingID Bid, const CGTownInstance * tid)
: ElementarGoal(Goals::BUILD_STRUCTURE)
{

View File

@ -17,9 +17,6 @@
namespace NKAI
{
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<AIGateway> ai;
using namespace Goals;
bool BuyArmy::operator==(const BuyArmy & other) const

View File

@ -18,8 +18,6 @@
namespace NKAI
{
extern boost::thread_specific_ptr<CCallback> cb;
using namespace Goals;
bool CaptureObject::operator==(const CaptureObject & other) const

View File

@ -17,9 +17,6 @@
namespace NKAI
{
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<AIGateway> ai;
using namespace Goals;
bool isKeyMaster(const QuestInfo & q)

View File

@ -17,9 +17,6 @@
namespace NKAI
{
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<AIGateway> ai;
using namespace Goals;
bool Composition::operator==(const Composition & other) const

View File

@ -16,9 +16,6 @@
namespace NKAI
{
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<AIGateway> ai;
using namespace Goals;
bool DigAtTile::operator==(const DigAtTile & other) const

View File

@ -14,9 +14,6 @@
namespace NKAI
{
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<AIGateway> ai;
using namespace Goals;
bool DismissHero::operator==(const DismissHero & other) const

View File

@ -16,9 +16,6 @@
namespace NKAI
{
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<AIGateway> ai;
using namespace Goals;
ExchangeSwapTownHeroes::ExchangeSwapTownHeroes(

View File

@ -15,9 +15,6 @@
namespace NKAI
{
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<AIGateway> ai;
using namespace Goals;
ExecuteHeroChain::ExecuteHeroChain(const AIPath & path, const CGObjectInstance * obj)

View File

@ -17,9 +17,6 @@
namespace NKAI
{
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<AIGateway> ai;
using namespace Goals;
std::string RecruitHero::toString() const

View File

@ -15,9 +15,6 @@
namespace NKAI
{
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<AIGateway> ai;
using namespace Goals;
bool SaveResources::operator==(const SaveResources & other) const

View File

@ -16,9 +16,6 @@
namespace NKAI
{
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<AIGateway> ai;
using namespace Goals;
ArmyUpgrade::ArmyUpgrade(const AIPath & upgradePath, const CGObjectInstance * upgrader, const ArmyUpgradeInfo & upgrade)

View File

@ -17,9 +17,6 @@
namespace NKAI
{
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<AIGateway> ai;
using namespace Goals;
bool HeroExchange::operator==(const HeroExchange & other) const

View File

@ -16,9 +16,6 @@
namespace NKAI
{
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<AIGateway> ai;
using namespace Goals;
bool UnlockCluster::operator==(const UnlockCluster & other) const

View File

@ -16,9 +16,6 @@
namespace NKAI
{
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<AIGateway> ai;
namespace AIPathfinding
{
void BattleAction::execute(const CGHeroInstance * hero) const

View File

@ -20,14 +20,11 @@
namespace NKAI
{
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<AIGateway> ai;
namespace AIPathfinding
{
void BuildBoatAction::execute(const CGHeroInstance * hero) const
{
return Goals::BuildBoat(shipyard).accept(ai.get());
return Goals::BuildBoat(shipyard).accept(ai);
}
Goals::TSubgoal BuildBoatAction::decompose(const CGHeroInstance * hero) const
@ -80,7 +77,7 @@ namespace AIPathfinding
void SummonBoatAction::execute(const CGHeroInstance * hero) const
{
Goals::AdventureSpellCast(hero, SpellID::SUMMON_BOAT).accept(ai.get());
Goals::AdventureSpellCast(hero, SpellID::SUMMON_BOAT).accept(ai);
}
const ChainActor * SummonBoatAction::getActor(const ChainActor * sourceActor) const

View File

@ -16,9 +16,6 @@
namespace NKAI
{
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<AIGateway> ai;
namespace AIPathfinding
{
void BuyArmyAction::execute(const CGHeroInstance * hero) const

View File

@ -16,9 +16,6 @@
namespace NKAI
{
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<AIGateway> ai;
namespace AIPathfinding
{
bool QuestAction::canAct(const AIPathNode * node) const

View File

@ -18,9 +18,6 @@ namespace NKAI
using namespace AIPathfinding;
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<AIGateway> ai;
void TownPortalAction::execute(const CGHeroInstance * hero) const
{
auto goal = Goals::AdventureSpellCast(hero, SpellID::TOWN_PORTAL);
@ -28,7 +25,7 @@ void TownPortalAction::execute(const CGHeroInstance * hero) const
goal.town = target;
goal.tile = target->visitablePos();
goal.accept(ai.get());
goal.accept(ai);
}
std::string TownPortalAction::toString() const

View File

@ -108,7 +108,7 @@ void CStupidAI::yourTacticPhase(int distance)
void CStupidAI::activeStack( const CStack * stack )
{
//boost::this_thread::sleep(boost::posix_time::seconds(2));
//boost::this_thread::sleep_for(boost::chrono::seconds(2));
print("activeStack called for " + stack->nodeName());
ReachabilityInfo dists = cb->getReachability(stack);
std::vector<EnemyInfo> enemiesShootable, enemiesReachable, enemiesUnreachable;

View File

@ -21,12 +21,8 @@
#include "../../lib/mapObjects/CQuest.h"
#include "../../lib/mapping/CMapDefines.h"
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
extern FuzzyHelper * fh;
//extern static const int3 dirs[8];
const CGObjectInstance * ObjectIdRef::operator->() const
{
return cb->getObj(id, false);

View File

@ -18,6 +18,7 @@
#include "../../lib/mapObjects/CGHeroInstance.h"
#include "../../CCallback.h"
class VCAI;
class CCallback;
struct creInfo;
@ -33,7 +34,8 @@ const int ALLOWED_ROAMING_HEROES = 8;
extern const double SAFE_ATTACK_CONSTANT;
extern const int GOLD_RESERVE;
extern boost::thread_specific_ptr<CCallback> cb;
extern thread_local CCallback * cb;
extern thread_local VCAI * ai;
//provisional class for AI to store a reference to an owned hero object
//checks if it's valid on access, should be used in place of const CGHeroInstance*
@ -192,7 +194,7 @@ void foreach_tile_pos(CCallback * cbp, const Func & foo) // avoid costly retriev
template<class Func>
void foreach_neighbour(const int3 & pos, const Func & foo)
{
CCallback * cbp = cb.get(); // avoid costly retrieval of thread-specific pointer
CCallback * cbp = cb; // avoid costly retrieval of thread-specific pointer
for(const int3 & dir : int3::getDirs())
{
const int3 n = pos + dir;

View File

@ -18,9 +18,6 @@
#define MIN_AI_STRENGTH (0.5f) //lower when combat AI gets smarter
#define UNGUARDED_OBJECT (100.0f) //we consider unguarded objects 100 times weaker than us
extern boost::thread_specific_ptr<VCAI> ai;
extern FuzzyHelper * fh;
engineBase::engineBase()
{
rules = new fl::RuleBlock();

View File

@ -23,9 +23,6 @@
FuzzyHelper * fh;
extern boost::thread_specific_ptr<VCAI> ai;
extern boost::thread_specific_ptr<CCallback> cb;
Goals::TSubgoal FuzzyHelper::chooseSolution(Goals::TGoalVec vec)
{
if(vec.empty())
@ -216,7 +213,7 @@ void FuzzyHelper::setPriority(Goals::TSubgoal & g) //calls evaluate - Visitor pa
ui64 FuzzyHelper::evaluateDanger(crint3 tile, const CGHeroInstance * visitor)
{
return evaluateDanger(tile, visitor, ai.get());
return evaluateDanger(tile, visitor, ai);
}
ui64 FuzzyHelper::evaluateDanger(crint3 tile, const CGHeroInstance * visitor, const VCAI * ai)

View File

@ -51,3 +51,5 @@ public:
ui64 evaluateDanger(crint3 tile, const CGHeroInstance * visitor, const VCAI * ai);
ui64 evaluateDanger(crint3 tile, const CGHeroInstance * visitor);
};
extern FuzzyHelper * fh;

View File

@ -16,10 +16,6 @@
#include "../BuildingManager.h"
#include "../../../lib/StringConstants.h"
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
extern FuzzyHelper * fh;
using namespace Goals;
TSubgoal Goals::sptr(const AbstractGoal & tmp)

View File

@ -14,10 +14,6 @@
#include "../AIhelper.h"
#include "../../../lib/mapObjects/CGTownInstance.h"
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
extern FuzzyHelper * fh;
using namespace Goals;
bool AdventureSpellCast::operator==(const AdventureSpellCast & other) const

View File

@ -19,11 +19,6 @@
#include "../../../lib/mapObjects/CGTownInstance.h"
#include "../../../lib/StringConstants.h"
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
extern FuzzyHelper * fh;
using namespace Goals;
TGoalVec Build::getAllPossibleSubgoals()

View File

@ -13,10 +13,6 @@
#include "../FuzzyHelper.h"
#include "../AIhelper.h"
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
extern FuzzyHelper * fh;
using namespace Goals;
bool BuildBoat::operator==(const BuildBoat & other) const

View File

@ -18,11 +18,6 @@
#include "../../../lib/mapObjects/CGTownInstance.h"
#include "../../../lib/StringConstants.h"
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
extern FuzzyHelper * fh;
using namespace Goals;
bool BuildThis::operator==(const BuildThis & other) const

View File

@ -13,11 +13,6 @@
#include "../AIhelper.h"
#include "../../../lib/mapObjects/CGTownInstance.h"
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
extern FuzzyHelper * fh;
using namespace Goals;
bool BuyArmy::operator==(const BuyArmy & other) const

View File

@ -16,11 +16,6 @@
#include "../FuzzyHelper.h"
#include "../AIhelper.h"
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
extern FuzzyHelper * fh;
using namespace Goals;
bool ClearWayTo::operator==(const ClearWayTo & other) const

View File

@ -18,11 +18,6 @@
#include "../../../lib/mapObjects/CGMarket.h"
#include "../../../lib/StringConstants.h"
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
extern FuzzyHelper * fh;
using namespace Goals;
bool CollectRes::operator==(const CollectRes & other) const

View File

@ -14,10 +14,6 @@
#include "../AIhelper.h"
#include "../../../lib/mapObjects/CQuest.h"
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
extern FuzzyHelper * fh;
using namespace Goals;
bool CompleteQuest::operator==(const CompleteQuest & other) const

View File

@ -17,11 +17,6 @@
#include "../BuildingManager.h"
#include "../../../lib/StringConstants.h"
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
extern FuzzyHelper * fh;
using namespace Goals;
bool Conquer::operator==(const Conquer & other) const

View File

@ -13,11 +13,6 @@
#include "../VCAI.h"
#include "../AIUtility.h"
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
extern FuzzyHelper * fh;
using namespace Goals;
bool DigAtTile::operator==(const DigAtTile & other) const

View File

@ -18,10 +18,6 @@
#include "../../../lib/StringConstants.h"
#include "../../../lib/CPlayerState.h"
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
extern FuzzyHelper * fh;
using namespace Goals;
namespace Goals
@ -41,8 +37,8 @@ namespace Goals
ExplorationHelper(HeroPtr h, bool gatherArmy)
{
cbp = cb.get();
aip = ai.get();
cbp = cb;
aip = ai;
hero = h;
ts = cbp->getPlayerTeam(ai->playerID);
sightRadius = hero->getSightRadius();

View File

@ -14,10 +14,6 @@
#include "../VCAI.h"
#include "../AIUtility.h"
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
extern FuzzyHelper * fh;
using namespace Goals;
bool FindObj::operator==(const FindObj & other) const

View File

@ -18,11 +18,6 @@
#include "../../../lib/mapObjects/CGTownInstance.h"
#include "../../../lib/StringConstants.h"
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
extern FuzzyHelper * fh;
using namespace Goals;
bool GatherArmy::operator==(const GatherArmy & other) const

View File

@ -18,11 +18,6 @@
#include "../../../lib/mapObjects/CGTownInstance.h"
#include "../../../lib/StringConstants.h"
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
extern FuzzyHelper * fh;
using namespace Goals;
bool GatherTroops::operator==(const GatherTroops & other) const

View File

@ -13,11 +13,6 @@
#include "../VCAI.h"
#include "../AIUtility.h"
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
extern FuzzyHelper * fh;
using namespace Goals;
bool GetArtOfType::operator==(const GetArtOfType & other) const
@ -28,4 +23,4 @@ bool GetArtOfType::operator==(const GetArtOfType & other) const
TSubgoal GetArtOfType::whatToDoToAchieve()
{
return sptr(FindObj(Obj::ARTIFACT, aid));
}
}

View File

@ -17,11 +17,6 @@
#include "../BuildingManager.h"
#include "../../../lib/StringConstants.h"
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
extern FuzzyHelper * fh;
using namespace Goals;
TSubgoal RecruitHero::whatToDoToAchieve()

View File

@ -18,10 +18,6 @@
#include "../ResourceManager.h"
#include "../BuildingManager.h"
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
extern FuzzyHelper * fh;
using namespace Goals;
bool VisitHero::operator==(const VisitHero & other) const

View File

@ -17,11 +17,6 @@
#include "../BuildingManager.h"
#include "../../../lib/StringConstants.h"
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
extern FuzzyHelper * fh;
using namespace Goals;
bool VisitObj::operator==(const VisitObj & other) const

View File

@ -17,11 +17,6 @@
#include "../BuildingManager.h"
#include "../../../lib/StringConstants.h"
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
extern FuzzyHelper * fh;
using namespace Goals;
bool VisitTile::operator==(const VisitTile & other) const

View File

@ -19,11 +19,6 @@
#include "../../../lib/mapObjects/CGTownInstance.h"
#include "../../../lib/StringConstants.h"
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
extern FuzzyHelper * fh;
using namespace Goals;
TSubgoal Win::whatToDoToAchieve()

View File

@ -38,8 +38,8 @@ extern FuzzyHelper * fh;
const double SAFE_ATTACK_CONSTANT = 1.5;
//one thread may be turn of AI and another will be handling a side effect for AI2
boost::thread_specific_ptr<CCallback> cb;
boost::thread_specific_ptr<VCAI> ai;
thread_local CCallback * cb = nullptr;
thread_local VCAI * ai = nullptr;
//std::map<int, std::map<int, int> > HeroView::infosCount;
@ -48,18 +48,18 @@ struct SetGlobalState
{
SetGlobalState(VCAI * AI)
{
assert(!ai.get());
assert(!cb.get());
assert(!ai);
assert(!cb);
ai.reset(AI);
cb.reset(AI->myCb.get());
ai = AI;
cb = AI->myCb.get();
}
~SetGlobalState()
{
//TODO: how to handle rm? shouldn't be called after ai is destroyed, hopefully
//TODO: to ensure that, make rm unique_ptr
ai.release();
cb.release();
ai = nullptr;
cb = nullptr;
}
};
@ -2497,6 +2497,8 @@ void VCAI::requestActionASAP(std::function<void()> whatToDo)
boost::shared_lock<boost::shared_mutex> gsLock(CGameState::mutex);
whatToDo();
});
newThread.detach();
}
void VCAI::lostHero(HeroPtr h)
@ -2675,7 +2677,7 @@ void AIStatus::waitTillFree()
{
boost::unique_lock<boost::mutex> lock(mx);
while(battle != NO_BATTLE || !remainingQueries.empty() || !objectsBeingVisited.empty() || ongoingHeroMovement)
cv.timed_wait(lock, boost::posix_time::milliseconds(100));
cv.wait_for(lock, boost::chrono::milliseconds(100));
}
bool AIStatus::haveTurn()

View File

@ -149,8 +149,8 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
#include <boost/algorithm/string.hpp>
#include <boost/crc.hpp>
#include <boost/current_function.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/date_time/posix_time/time_formatters.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/path.hpp>
@ -165,7 +165,10 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/adaptor/reversed.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/thread.hpp>
#include <boost/thread/thread_only.hpp>
#include <boost/thread/shared_mutex.hpp>
#include <boost/thread/recursive_mutex.hpp>
#include <boost/thread/once.hpp>
#ifndef M_PI
# define M_PI 3.14159265358979323846

View File

@ -27,11 +27,12 @@
#include "render/IScreenHandler.h"
#include "render/Graphics.h"
#include "../lib/filesystem/Filesystem.h"
#include "../lib/CConfigHandler.h"
#include "../lib/CGeneralTextHandler.h"
#include "../lib/CThreadHelper.h"
#include "../lib/VCMIDirs.h"
#include "../lib/VCMI_Lib.h"
#include "../lib/CConfigHandler.h"
#include "../lib/filesystem/Filesystem.h"
#include "../lib/logging/CBasicLogConfigurator.h"
@ -53,8 +54,6 @@
namespace po = boost::program_options;
namespace po_style = boost::program_options::command_line_style;
extern boost::thread_specific_ptr<bool> inGuiThread;
static po::variables_map vm;
#ifndef VCMI_IOS
@ -297,7 +296,11 @@ int main(int argc, char * argv[])
#ifndef VCMI_NO_THREADED_LOAD
//we can properly play intro only in the main thread, so we have to move loading to the separate thread
boost::thread loading(init);
boost::thread loading([]()
{
setThreadName("initialize");
init();
});
#else
init();
#endif
@ -411,7 +414,7 @@ int main(int argc, char * argv[])
else
{
while(true)
boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
boost::this_thread::sleep_for(boost::chrono::milliseconds(1000));
}
return 0;
@ -429,7 +432,7 @@ void playIntro()
static void mainLoop()
{
inGuiThread.reset(new bool(true));
setThreadName("MainGUI");
while(1) //main SDL events loop
{
@ -470,7 +473,7 @@ static void quitApplication()
vstd::clear_pointer(console);// should be removed after everything else since used by logging
boost::this_thread::sleep(boost::posix_time::milliseconds(750));//???
boost::this_thread::sleep_for(boost::chrono::milliseconds(750));//???
if(!settings["session"]["headless"].Bool())
GH.screenHandler().close();

View File

@ -238,7 +238,7 @@ void CSoundHandler::setChannelVolume(int channel, ui32 percent)
void CSoundHandler::setCallback(int channel, std::function<void()> function)
{
boost::unique_lock lockGuard(mutexCallbacks);
boost::mutex::scoped_lock lockGuard(mutexCallbacks);
auto iter = callbacks.find(channel);
@ -251,7 +251,7 @@ void CSoundHandler::setCallback(int channel, std::function<void()> function)
void CSoundHandler::soundFinishedCallback(int channel)
{
boost::unique_lock lockGuard(mutexCallbacks);
boost::mutex::scoped_lock lockGuard(mutexCallbacks);
if (callbacks.count(channel) == 0)
return;
@ -272,14 +272,14 @@ void CSoundHandler::soundFinishedCallback(int channel)
void CSoundHandler::initCallback(int channel)
{
boost::unique_lock lockGuard(mutexCallbacks);
boost::mutex::scoped_lock lockGuard(mutexCallbacks);
assert(callbacks.count(channel) == 0);
callbacks[channel] = {};
}
void CSoundHandler::initCallback(int channel, const std::function<void()> & function)
{
boost::unique_lock lockGuard(mutexCallbacks);
boost::mutex::scoped_lock lockGuard(mutexCallbacks);
assert(callbacks.count(channel) == 0);
callbacks[channel].push_back(function);
}

View File

@ -76,6 +76,7 @@
#include "../lib/UnlockGuard.h"
#include "../lib/RoadHandler.h"
#include "../lib/TerrainHandler.h"
#include "../lib/CThreadHelper.h"
#include "CServerHandler.h"
// FIXME: only needed for CGameState::mutex
#include "../lib/gameState/CGameState.h"
@ -135,7 +136,6 @@ CPlayerInterface::CPlayerInterface(PlayerColor Player):
makingTurn = false;
showingDialog = new CondSh<bool>(false);
cingconsole = new CInGameConsole();
GH.terminate_cond->set(false);
firstCall = 1; //if loading will be overwritten in serialize
autosaveCount = 0;
isAutoFightOn = false;
@ -654,6 +654,11 @@ void CPlayerInterface::buildChanged(const CGTownInstance *town, BuildingID build
void CPlayerInterface::battleStartBefore(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2)
{
// when battle starts, game will send battleStart pack *before* movement confirmation
// and since network thread wait for battle intro to play, movement confirmation will only happen after intro
// leading to several bugs, such as blocked input during intro
stillMoveHero.setn(STOP_MOVE);
//Don't wait for dialogs when we are non-active hot-seat player
if (LOCPLINT == this)
waitForAllDialogs();
@ -1447,7 +1452,7 @@ void CPlayerInterface::centerView (int3 pos, int focusTime)
{
auto unlockPim = vstd::makeUnlockGuard(*pim);
IgnoreEvents ignore(*this);
boost::this_thread::sleep(boost::posix_time::milliseconds(focusTime));
boost::this_thread::sleep_for(boost::chrono::milliseconds(focusTime));
}
}
CCS->curh->show();
@ -1591,7 +1596,6 @@ void CPlayerInterface::gameOver(PlayerColor player, const EVictoryLossCheckResul
{
if(adventureInt)
{
GH.terminate_cond->setn(true);
GH.windows().popWindows(GH.windows().count());
adventureInt.reset();
}
@ -1874,7 +1878,7 @@ void CPlayerInterface::waitForAllDialogs(bool unlockPim)
while(!dialogs.empty())
{
auto unlock = vstd::makeUnlockGuardIf(*pim, unlockPim);
boost::this_thread::sleep(boost::posix_time::milliseconds(5));
boost::this_thread::sleep_for(boost::chrono::milliseconds(5));
}
waitWhileDialog(unlockPim);
}
@ -1933,6 +1937,8 @@ void CPlayerInterface::setMovementStatus(bool value)
void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path)
{
setThreadName("doMoveHero");
int i = 1;
auto getObj = [&](int3 coord, bool ignoreHero)
{

View File

@ -231,7 +231,7 @@ void CServerHandler::startLocalServerAndConnect()
while(!androidTestServerReadyFlag.load())
{
logNetwork->info("still waiting...");
boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
boost::this_thread::sleep_for(boost::chrono::milliseconds(1000));
}
logNetwork->info("waiting for server finished...");
androidTestServerReadyFlag = false;
@ -261,7 +261,7 @@ void CServerHandler::justConnectToServer(const std::string & addr, const ui16 po
catch(std::runtime_error & error)
{
logNetwork->warn("\nCannot establish connection. %s Retrying in 1 second", error.what());
boost::this_thread::sleep(boost::posix_time::seconds(1));
boost::this_thread::sleep_for(boost::chrono::milliseconds(1000));
}
}
@ -307,7 +307,7 @@ void CServerHandler::stopServerConnection()
{
if(c->handler)
{
while(!c->handler->timed_join(boost::posix_time::milliseconds(50)))
while(!c->handler->timed_join(boost::chrono::milliseconds(50)))
applyPacksOnLobbyScreen();
c->handler->join();
}
@ -574,6 +574,8 @@ void CServerHandler::startMapAfterConnection(std::shared_ptr<CMapInfo> to)
void CServerHandler::startGameplay(VCMI_LIB_WRAP_NAMESPACE(CGameState) * gameState)
{
setThreadName("startGameplay");
if(CMM)
CMM->disable();
client = new CClient();
@ -630,7 +632,6 @@ void CServerHandler::endGameplay(bool closeConnection, bool restart)
{
if(CMM)
{
GH.terminate_cond->setn(false);
GH.curInt = CMM.get();
CMM->enable();
}
@ -761,20 +762,20 @@ void CServerHandler::debugStartTest(std::string filename, bool save)
else
startLocalServerAndConnect();
boost::this_thread::sleep(boost::posix_time::milliseconds(100));
boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
while(!settings["session"]["headless"].Bool() && !GH.windows().topWindow<CLobbyScreen>())
boost::this_thread::sleep(boost::posix_time::milliseconds(50));
boost::this_thread::sleep_for(boost::chrono::milliseconds(50));
while(!mi || mapInfo->fileURI != CSH->mi->fileURI)
{
setMapInfo(mapInfo);
boost::this_thread::sleep(boost::posix_time::milliseconds(50));
boost::this_thread::sleep_for(boost::chrono::milliseconds(50));
}
// "Click" on color to remove us from it
setPlayer(myFirstColor());
while(myFirstColor() != PlayerColor::CANNOT_DETERMINE)
boost::this_thread::sleep(boost::posix_time::milliseconds(50));
boost::this_thread::sleep_for(boost::chrono::milliseconds(50));
while(true)
{
@ -787,7 +788,7 @@ void CServerHandler::debugStartTest(std::string filename, bool save)
{
}
boost::this_thread::sleep(boost::posix_time::milliseconds(50));
boost::this_thread::sleep_for(boost::chrono::milliseconds(50));
}
}
@ -817,7 +818,7 @@ public:
void CServerHandler::threadHandleConnection()
{
setThreadName("CServerHandler::threadHandleConnection");
setThreadName("handleConnection");
c->enterLobbyConnectionMode();
try
@ -826,7 +827,7 @@ void CServerHandler::threadHandleConnection()
while(c->connected)
{
while(state == EClientState::STARTING)
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
boost::this_thread::sleep_for(boost::chrono::milliseconds(10));
CPack * pack = c->retrievePack();
if(state == EClientState::DISCONNECTING)
@ -898,7 +899,7 @@ void CServerHandler::visitForClient(CPackForClient & clientPack)
void CServerHandler::threadRunServer()
{
#if !defined(VCMI_MOBILE)
setThreadName("CServerHandler::threadRunServer");
setThreadName("runServer");
const std::string logName = (VCMIDirs::get().userLogsPath() / "server_log.txt").string();
std::string comm = VCMIDirs::get().serverPath().string()
+ " --port=" + std::to_string(getHostPort())

View File

@ -461,7 +461,7 @@ bool CVideoPlayer::playVideo(int x, int y, bool stopOnKey)
double frameDurationSec = packet_duration * av_q2d(format->streams[stream]->time_base);
uint32_t timeToSleepMillisec = 1000 * (frameDurationSec);
boost::this_thread::sleep(boost::posix_time::millisec(timeToSleepMillisec));
boost::this_thread::sleep_for(boost::chrono::milliseconds(timeToSleepMillisec));
}
return true;

View File

@ -181,7 +181,10 @@ void CClient::newGame(CGameState * initializedGameState)
gs->preInit(VLC);
logNetwork->trace("\tCreating gamestate: %i", CSH->th->getDiff());
if(!initializedGameState)
gs->init(&mapService, CSH->si.get(), settings["general"]["saveRandomMaps"].Bool());
{
Load::ProgressAccumulator progressTracking;
gs->init(&mapService, CSH->si.get(), progressTracking, settings["general"]["saveRandomMaps"].Bool());
}
logNetwork->trace("Initializing GameState (together): %d ms", CSH->th->getDiff());
initMapHandler();

View File

@ -53,6 +53,7 @@ public:
virtual void visitLobbyChatMessage(LobbyChatMessage & pack) override;
virtual void visitLobbyGuiAction(LobbyGuiAction & pack) override;
virtual void visitLobbyStartGame(LobbyStartGame & pack) override;
virtual void visitLobbyLoadProgress(LobbyLoadProgress & pack) override;
virtual void visitLobbyUpdateState(LobbyUpdateState & pack) override;
virtual void visitLobbyShowMessage(LobbyShowMessage & pack) override;
};

View File

@ -59,6 +59,9 @@ void ApplyOnLobbyHandlerNetPackVisitor::visitLobbyClientDisconnected(LobbyClient
void ApplyOnLobbyScreenNetPackVisitor::visitLobbyClientDisconnected(LobbyClientDisconnected & pack)
{
if(auto w = GH.windows().topWindow<CLoadingScreen>())
GH.windows().popWindow(w);
if(GH.windows().count() > 0)
GH.windows().popWindows(1);
}
@ -122,16 +125,31 @@ void ApplyOnLobbyHandlerNetPackVisitor::visitLobbyStartGame(LobbyStartGame & pac
handler.si = pack.initializedStartInfo;
handler.si->mode = modeBackup;
}
if(settings["session"]["headless"].Bool())
handler.startGameplay(pack.initializedGameState);
handler.startGameplay(pack.initializedGameState);
}
void ApplyOnLobbyScreenNetPackVisitor::visitLobbyStartGame(LobbyStartGame & pack)
{
if(pack.clientId != -1 && pack.clientId != handler.c->connectionID)
return;
GH.windows().createAndPushWindow<CLoadingScreen>(std::bind(&CServerHandler::startGameplay, &handler, pack.initializedGameState));
if(auto w = GH.windows().topWindow<CLoadingScreen>())
{
w->finish();
w->tick(0);
w->redraw();
}
else
GH.windows().createAndPushWindow<CLoadingScreen>();
}
void ApplyOnLobbyScreenNetPackVisitor::visitLobbyLoadProgress(LobbyLoadProgress & pack)
{
if(auto w = GH.windows().topWindow<CLoadingScreen>())
{
w->set(pack.progress);
w->tick(0);
w->redraw();
}
else
GH.windows().createAndPushWindow<CLoadingScreen>();
}
void ApplyOnLobbyHandlerNetPackVisitor::visitLobbyUpdateState(LobbyUpdateState & pack)

View File

@ -27,6 +27,7 @@
#include "../../CCallback.h"
#include "../../lib/CConfigHandler.h"
#include "../../lib/CThreadHelper.h"
#include "../../lib/TextOperations.h"
#include "../../lib/mapObjects/CArmedInstance.h"
@ -255,6 +256,7 @@ void CInGameConsole::endEnteringText(bool processEnteredText)
//some commands like gosolo don't work when executed from GUI thread
auto threadFunction = [=]()
{
setThreadName("processCommand");
ClientCommandManager commandController;
commandController.processCommand(txt.substr(1), true);
};

View File

@ -43,6 +43,7 @@
#include "../../lib/NetPacks.h"
#include "../../lib/UnlockGuard.h"
#include "../../lib/TerrainHandler.h"
#include "../../lib/CThreadHelper.h"
BattleInterface::BattleInterface(const CCreatureSet *army1, const CCreatureSet *army2,
const CGHeroInstance *hero1, const CGHeroInstance *hero2,
@ -104,11 +105,9 @@ void BattleInterface::playIntroSoundAndUnlockInterface()
{
auto onIntroPlayed = [this]()
{
boost::unique_lock<boost::recursive_mutex> un(*CPlayerInterface::pim);
if(LOCPLINT->battleInt)
{
boost::unique_lock<boost::recursive_mutex> un(*CPlayerInterface::pim);
onIntroSoundPlayed();
}
};
int battleIntroSoundChannel = CCS->soundh->playSoundFromSet(CCS->soundh->battleIntroSounds);
@ -326,7 +325,7 @@ void BattleInterface::battleFinished(const BattleResult& br, QueryID queryID)
curInt->cb->selectionMade(selection, queryID);
};
GH.windows().pushWindow(wnd);
curInt->waitWhileDialog(); // Avoid freeze when AI end turn after battle. Check bug #1897
CPlayerInterface::battleInt = nullptr;
}
@ -602,28 +601,13 @@ void BattleInterface::startAction(const BattleAction & action)
return;
}
const CStack *stack = curInt->cb->battleGetStackByID(action.stackNumber);
if (stack)
{
windowObject->updateQueue();
}
else
{
assert(action.actionType == EActionType::HERO_SPELL); //only cast spell is valid action without acting stack number
}
stacksController->startAction(action);
if(action.actionType == EActionType::HERO_SPELL) //when hero casts spell
if (!action.isUnitAction())
return;
if (!stack)
{
logGlobal->error("Something wrong with stackNumber in actionStarted. Stack number: %d", action.stackNumber);
return;
}
assert(curInt->cb->battleGetStackByID(action.stackNumber));
windowObject->updateQueue();
effectsController->startAction(action);
}
@ -731,6 +715,7 @@ void BattleInterface::requestAutofightingAIToTakeAction()
// HOWEVER this thread won't atttempt to lock game state, potentially leading to races
boost::thread aiThread([this, activeStack]()
{
setThreadName("autofightingAI");
curInt->autofightingAI->activeStack(activeStack);
});
aiThread.detach();

View File

@ -407,7 +407,7 @@ void BattleWindow::bFleef()
auto txt = boost::format(CGI->generaltexth->allTexts[340]) % heroName; //The Shackles of War are present. %s can not retreat!
//printing message
owner.curInt->showInfoDialog(boost::to_string(txt), comps);
owner.curInt->showInfoDialog(boost::str(txt), comps);
}
}

View File

@ -59,14 +59,6 @@ void InputSourceKeyboard::handleEventKeyDown(const SDL_KeyboardEvent & key)
Settings s = settings.write["session"];
switch(key.keysym.sym)
{
case SDLK_F5:
if(settings["session"]["spectate-locked-pim"].Bool())
CPlayerInterface::pim->unlock();
else
CPlayerInterface::pim->lock();
s["spectate-locked-pim"].Bool() = !settings["session"]["spectate-locked-pim"].Bool();
break;
case SDLK_F6:
s["spectate-ignore-hero"].Bool() = !settings["session"]["spectate-ignore-hero"].Bool();
break;

View File

@ -36,7 +36,7 @@
CGuiHandler GH;
boost::thread_specific_ptr<bool> inGuiThread;
static thread_local bool inGuiThread = false;
SObjectConstruction::SObjectConstruction(CIntObject *obj)
:myObj(obj)
@ -69,6 +69,8 @@ SSetCaptureState::~SSetCaptureState()
void CGuiHandler::init()
{
inGuiThread = true;
inputHandlerInstance = std::make_unique<InputHandler>();
eventDispatcherInstance = std::make_unique<EventDispatcher>();
windowHandlerInstance = std::make_unique<WindowHandler>();
@ -109,20 +111,8 @@ void CGuiHandler::stopTextInput()
void CGuiHandler::renderFrame()
{
// Updating GUI requires locking pim mutex (that protects screen and GUI state).
// During game:
// When ending the game, the pim mutex might be hold by other thread,
// that will notify us about the ending game by setting terminate_cond flag.
//in PreGame terminate_cond stay false
bool acquiredTheLockOnPim = false; //for tracking whether pim mutex locking succeeded
while(!terminate_cond->get() && !(acquiredTheLockOnPim = CPlayerInterface::pim->try_lock())) //try acquiring long until it succeeds or we are told to terminate
boost::this_thread::sleep(boost::posix_time::milliseconds(1));
if(acquiredTheLockOnPim)
{
// If we are here, pim mutex has been successfully locked - let's store it in a safe RAII lock.
boost::unique_lock<boost::recursive_mutex> un(*CPlayerInterface::pim, boost::adopt_lock);
boost::recursive_mutex::scoped_lock un(*CPlayerInterface::pim);
if(nullptr != curInt)
curInt->update();
@ -150,14 +140,10 @@ CGuiHandler::CGuiHandler()
, captureChildren(false)
, curInt(nullptr)
, fakeStatusBar(std::make_shared<EmptyStatusBar>())
, terminate_cond (new CondSh<bool>(false))
{
}
CGuiHandler::~CGuiHandler()
{
delete terminate_cond;
}
CGuiHandler::~CGuiHandler() = default;
ShortcutHandler & CGuiHandler::shortcuts()
{
@ -207,7 +193,7 @@ void CGuiHandler::drawFPSCounter()
bool CGuiHandler::amIGuiThread()
{
return inGuiThread.get() && *inGuiThread;
return inGuiThread;
}
void CGuiHandler::dispatchMainThread(const std::function<void()> & functor)

View File

@ -99,8 +99,6 @@ public:
/// Calls provided functor in main thread on next execution frame
void dispatchMainThread(const std::function<void()> & functor);
CondSh<bool> * terminate_cond; // confirm termination
};
extern CGuiHandler GH; //global gui handler

View File

@ -392,7 +392,6 @@ std::shared_ptr<CMainMenu> CMainMenu::create()
if(!CMM)
CMM = std::shared_ptr<CMainMenu>(new CMainMenu());
GH.terminate_cond->setn(false);
return CMM;
}
@ -562,12 +561,14 @@ void CSimpleJoinScreen::startConnectThread(const std::string & addr, ui16 port)
// https://github.com/libsdl-org/SDL/blob/main/docs/README-android.md#threads-and-the-java-vm
CVCMIServer::reuseClientJNIEnv(SDL_AndroidGetJNIEnv());
#endif
boost::thread(&CSimpleJoinScreen::connectThread, this, addr, port);
boost::thread connector(&CSimpleJoinScreen::connectThread, this, addr, port);
connector.detach();
}
void CSimpleJoinScreen::connectThread(const std::string & addr, ui16 port)
{
setThreadName("CSimpleJoinScreen::connectThread");
setThreadName("connectThread");
if(!addr.length())
CSH->startLocalServerAndConnect();
else
@ -582,36 +583,67 @@ void CSimpleJoinScreen::connectThread(const std::string & addr, ui16 port)
});
}
CLoadingScreen::CLoadingScreen(std::function<void()> loader)
: CWindowObject(BORDERED, getBackground()), loadingThread(loader)
CLoadingScreen::CLoadingScreen()
: CWindowObject(BORDERED, getBackground())
{
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
addUsedEvents(TIME);
CCS->musich->stopMusic(5000);
const auto & conf = CMainMenuConfig::get().getConfig()["loading"];
if(conf.isStruct())
{
const int posx = conf["x"].Integer(), posy = conf["y"].Integer();
const int blockSize = conf["size"].Integer();
const int blocksAmount = conf["amount"].Integer();
for(int i = 0; i < blocksAmount; ++i)
{
progressBlocks.push_back(std::make_shared<CAnimImage>(conf["name"].String(), i, 0, posx + i * blockSize, posy));
progressBlocks.back()->deactivate();
progressBlocks.back()->visible = false;
}
}
}
CLoadingScreen::~CLoadingScreen()
{
loadingThread.join();
}
void CLoadingScreen::showAll(Canvas & to)
void CLoadingScreen::tick(uint32_t msPassed)
{
//FIXME: filling screen with transparency? BLACK intended?
//Rect rect(0, 0, to->w, to->h);
//CSDL_Ext::fillRect(to, rect, Colors::TRANSPARENCY);
CWindowObject::showAll(to);
if(!progressBlocks.empty())
{
int status = float(get()) / 255.f * progressBlocks.size();
for(int i = 0; i < status; ++i)
{
progressBlocks.at(i)->activate();
progressBlocks.at(i)->visible = true;
}
}
}
std::string CLoadingScreen::getBackground()
{
const auto & conf = CMainMenuConfig::get().getConfig()["loading"].Vector();
std::string fname = "loadbar";
const auto & conf = CMainMenuConfig::get().getConfig()["loading"];
if(conf.empty())
if(conf.isStruct())
{
return "loadbar";
}
else
{
return RandomGeneratorUtil::nextItem(conf, CRandomGenerator::getDefault())->String();
if(conf["background"].isVector())
return RandomGeneratorUtil::nextItem(conf["background"].Vector(), CRandomGenerator::getDefault())->String();
if(conf["background"].isString())
return conf["background"].String();
return fname;
}
if(conf.isVector() && !conf.Vector().empty())
return RandomGeneratorUtil::nextItem(conf.Vector(), CRandomGenerator::getDefault())->String();
return fname;
}

View File

@ -11,6 +11,7 @@
#include "../windows/CWindowObject.h"
#include "../../lib/JsonNode.h"
#include "../../lib/LoadProgress.h"
VCMI_LIB_NAMESPACE_BEGIN
@ -22,9 +23,11 @@ class CTextInput;
class CGStatusBar;
class CTextBox;
class CTabbedInt;
class CAnimImage;
class CAnimation;
class CButton;
class CFilledTexture;
class CLabel;
// TODO: Find new location for these enums
@ -178,17 +181,17 @@ public:
CSimpleJoinScreen(bool host = true);
};
class CLoadingScreen : public CWindowObject
class CLoadingScreen : virtual public CWindowObject, virtual public Load::Progress
{
boost::thread loadingThread;
std::vector<std::shared_ptr<CAnimImage>> progressBlocks;
std::string getBackground();
public:
CLoadingScreen(std::function<void()> loader);
public:
CLoadingScreen();
~CLoadingScreen();
void showAll(Canvas & to) override;
void tick(uint32_t msPassed) override;
};
extern std::shared_ptr<CMainMenu> CMM;

View File

@ -38,7 +38,7 @@ void CMapHandler::waitForOngoingAnimations()
while(CGI->mh->hasOngoingAnimations())
{
auto unlockPim = vstd::makeUnlockGuard(*CPlayerInterface::pim);
boost::this_thread::sleep(boost::posix_time::milliseconds(1));
boost::this_thread::sleep_for(boost::chrono::milliseconds(1));
}
}

View File

@ -562,7 +562,7 @@ void CSpellWindow::SpellArea::hover(bool on)
if(mySpell)
{
if(on)
owner->statusBar->write(boost::to_string(boost::format("%s (%s)") % mySpell->getNameTranslated() % CGI->generaltexth->allTexts[171+mySpell->level]));
owner->statusBar->write(boost::str(boost::format("%s (%s)") % mySpell->getNameTranslated() % CGI->generaltexth->allTexts[171+mySpell->level]));
else
owner->statusBar->clear();
}

View File

@ -2,7 +2,11 @@
//images used in game selection screen
"game-select" : ["gamselb0", "gamselb1"],
"loading" : ["loadbar"],
"loading" :
{
"background" : ["loadbar"],
"x": 395, "y": 548, "size": 18, "amount": 20, "name": "loadprog"
},
//Main menu window, consists of several sub-menus aka items
"window":

View File

@ -214,7 +214,7 @@ void CConsoleHandler::setColor(EConsoleTextColor::EConsoleTextColor color)
int CConsoleHandler::run() const
{
setThreadName("CConsoleHandler::run");
setThreadName("consoleHandler");
//disabling sync to make in_avail() work (othervice always returns 0)
{
TLockGuard _(smx);
@ -233,7 +233,7 @@ int CConsoleHandler::run() const
(*cb)(buffer, false);
}
else
boost::this_thread::sleep(boost::posix_time::millisec(100));
boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
boost::this_thread::interruption_point();
#else

View File

@ -13,8 +13,6 @@
VCMI_LIB_NAMESPACE_BEGIN
boost::thread_specific_ptr<CRandomGenerator> CRandomGenerator::defaultRand;
CRandomGenerator::CRandomGenerator()
{
resetSeed();
@ -84,11 +82,8 @@ double CRandomGenerator::nextDouble()
CRandomGenerator & CRandomGenerator::getDefault()
{
if(!defaultRand.get())
{
defaultRand.reset(new CRandomGenerator());
}
return *defaultRand;
static thread_local CRandomGenerator defaultRand;
return defaultRand;
}
TGenerator & CRandomGenerator::getStdGenerator()

View File

@ -80,7 +80,6 @@ public:
private:
TGenerator rand;
static boost::thread_specific_ptr<CRandomGenerator> defaultRand;
public:
template <typename Handler>

View File

@ -29,10 +29,12 @@ CThreadHelper::CThreadHelper(std::vector<std::function<void()>> * Tasks, int Thr
}
void CThreadHelper::run()
{
boost::thread_group grupa;
std::vector<boost::thread> group;
for(int i=0;i<threads;i++)
grupa.create_thread(std::bind(&CThreadHelper::processTasks,this));
grupa.join_all();
group.emplace_back(std::bind(&CThreadHelper::processTasks,this));
for (auto & thread : group)
thread.join();
//thread group deletes threads, do not free manually
}

View File

@ -46,15 +46,15 @@ public:
void run()
{
boost::thread_group grupa;
std::vector<boost::thread> group;
for(size_t i=0; i<threads; i++)
{
std::shared_ptr<Payload> payload = context.at(i);
grupa.create_thread(std::bind(&ThreadPool::processTasks, this, payload));
group.emplace_back(std::bind(&ThreadPool::processTasks, this, payload));
}
grupa.join_all();
for (auto & thread : group)
thread.join();
//thread group deletes threads, do not free manually
}

View File

@ -18,6 +18,11 @@ Progress::Progress(): _progress(std::numeric_limits<Type>::min())
setupSteps(100);
}
Progress::Progress(int steps): _progress(std::numeric_limits<Type>::min())
{
setupSteps(steps);
}
Type Progress::get() const
{
if(_step >= _maxSteps)
@ -82,3 +87,49 @@ void Progress::step(int count)
_step += count;
}
}
void ProgressAccumulator::include(const Progress & p)
{
boost::unique_lock<boost::mutex> guard(_mx);
_progress.emplace_back(p);
}
void ProgressAccumulator::exclude(const Progress & p)
{
boost::unique_lock<boost::mutex> guard(_mx);
for(auto i = _progress.begin(); i != _progress.end(); ++i)
{
if(&i->get() == &p)
{
_accumulated += static_cast<long long>(p.get()) * p._maxSteps;
_steps += p._maxSteps;
_progress.erase(i);
return;
}
}
}
bool ProgressAccumulator::finished() const
{
boost::unique_lock<boost::mutex> guard(_mx);
for(auto i : _progress)
if(!i.get().finished())
return false;
return true;
}
Type ProgressAccumulator::get() const
{
boost::unique_lock<boost::mutex> guard(_mx);
auto sum = _accumulated;
auto totalSteps = _steps;
for(auto p : _progress)
{
sum += static_cast<long long>(p.get().get()) * p.get()._maxSteps;
totalSteps += p.get()._maxSteps;
}
if(totalSteps)
sum /= totalSteps;
return static_cast<Type>(sum);
}

View File

@ -18,6 +18,8 @@ namespace Load
using Type = unsigned char;
class ProgressAccumulator;
/*
* Purpose of that class is to track progress of computations
* Derive from this class if you want to translate user or system
@ -29,8 +31,9 @@ class DLL_LINKAGE Progress
public:
//Sets current state to 0.
//Amount of steps to finish progress will be equal to 100
//Amount of steps to finish progress will be equal to 100 for default constructor
Progress();
Progress(int steps);
virtual ~Progress() = default;
//Returns current state of the progress
@ -67,5 +70,25 @@ public:
private:
std::atomic<Type> _progress, _target;
std::atomic<int> _step, _maxSteps;
friend class ProgressAccumulator;
};
class DLL_LINKAGE ProgressAccumulator
{
public:
ProgressAccumulator() = default;
void include(const Progress &);
void exclude(const Progress &);
bool finished() const;
Type get() const;
private:
mutable boost::mutex _mx;
long long _accumulated = 0, _steps = 0;
std::vector<std::reference_wrapper<const Progress>> _progress;
};
}

View File

@ -145,6 +145,7 @@ public:
virtual void visitLobbyClientDisconnected(LobbyClientDisconnected & pack) {}
virtual void visitLobbyChatMessage(LobbyChatMessage & pack) {}
virtual void visitLobbyGuiAction(LobbyGuiAction & pack) {}
virtual void visitLobbyLoadProgress(LobbyLoadProgress & pack) {}
virtual void visitLobbyEndGame(LobbyEndGame & pack) {}
virtual void visitLobbyStartGame(LobbyStartGame & pack) {}
virtual void visitLobbyChangeHost(LobbyChangeHost & pack) {}

View File

@ -688,6 +688,11 @@ void LobbyGuiAction::visitTyped(ICPackVisitor & visitor)
visitor.visitLobbyGuiAction(*this);
}
void LobbyLoadProgress::visitTyped(ICPackVisitor & visitor)
{
visitor.visitLobbyLoadProgress(*this);
}
void LobbyEndGame::visitTyped(ICPackVisitor & visitor)
{
visitor.visitLobbyEndGame(*this);

View File

@ -99,6 +99,18 @@ struct DLL_LINKAGE LobbyGuiAction : public CLobbyPackToPropagate
}
};
struct DLL_LINKAGE LobbyLoadProgress : public CLobbyPackToPropagate
{
unsigned char progress;
virtual void visitTyped(ICPackVisitor & visitor) override;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & progress;
}
};
struct DLL_LINKAGE LobbyEndGame : public CLobbyPackToPropagate
{
bool closeConnection = false, restart = false;

View File

@ -194,7 +194,8 @@ void BattleAction::setTarget(const battle::Target & target_)
bool BattleAction::isUnitAction() const
{
static const std::array<EActionType, 9> actions = {
static const std::array<EActionType, 109> actions = {
EActionType::NO_ACTION,
EActionType::WALK,
EActionType::WAIT,
EActionType::DEFEND,
@ -205,7 +206,6 @@ bool BattleAction::isUnitAction() const
EActionType::BAD_MORALE,
EActionType::STACK_HEAL
};
return vstd::contains(actions, actionType);
}
@ -215,7 +215,15 @@ bool BattleAction::isSpellAction() const
EActionType::HERO_SPELL,
EActionType::MONSTER_SPELL
};
return vstd::contains(actions, actionType);
}
bool BattleAction::isBattleEndAction() const
{
static const std::array<EActionType, 2> actions = {
EActionType::RETREAT,
EActionType::SURRENDER
};
return vstd::contains(actions, actionType);
}
@ -227,7 +235,6 @@ bool BattleAction::isTacticsAction() const
EActionType::RETREAT,
EActionType::SURRENDER
};
return vstd::contains(actions, actionType);
}

View File

@ -46,6 +46,7 @@ public:
bool isTacticsAction() const;
bool isUnitAction() const;
bool isSpellAction() const;
bool isBattleEndAction() const;
std::string toString() const;
void aimToHex(const BattleHex & destination);

View File

@ -404,7 +404,7 @@ void CGameState::preInit(Services * services)
this->services = services;
}
void CGameState::init(const IMapService * mapService, StartInfo * si, bool allowSavingRandomMap)
void CGameState::init(const IMapService * mapService, StartInfo * si, Load::ProgressAccumulator & progressTracking, bool allowSavingRandomMap)
{
preInitAuto();
logGlobal->info("\tUsing random seed: %d", si->seedToBeUsed);
@ -416,7 +416,7 @@ void CGameState::init(const IMapService * mapService, StartInfo * si, bool allow
switch(scenarioOps->mode)
{
case StartInfo::NEW_GAME:
initNewGame(mapService, allowSavingRandomMap);
initNewGame(mapService, allowSavingRandomMap, progressTracking);
break;
case StartInfo::CAMPAIGN:
initCampaign();
@ -535,7 +535,7 @@ void CGameState::preInitAuto()
}
}
void CGameState::initNewGame(const IMapService * mapService, bool allowSavingRandomMap)
void CGameState::initNewGame(const IMapService * mapService, bool allowSavingRandomMap, Load::ProgressAccumulator & progressTracking)
{
if(scenarioOps->createRandomMap())
{
@ -544,8 +544,10 @@ void CGameState::initNewGame(const IMapService * mapService, bool allowSavingRan
// Gen map
CMapGenerator mapGenerator(*scenarioOps->mapGenOptions, scenarioOps->seedToBeUsed);
progressTracking.include(mapGenerator);
std::unique_ptr<CMap> randomMap = mapGenerator.generate();
progressTracking.exclude(mapGenerator);
if(allowSavingRandomMap)
{

View File

@ -11,6 +11,7 @@
#include "bonuses/CBonusSystemNode.h"
#include "IGameCallback.h"
#include "LoadProgress.h"
namespace boost
{
@ -89,7 +90,7 @@ public:
void preInit(Services * services);
void init(const IMapService * mapService, StartInfo * si, bool allowSavingRandomMap = false);
void init(const IMapService * mapService, StartInfo * si, Load::ProgressAccumulator &, bool allowSavingRandomMap = false);
void updateOnLoad(StartInfo * si);
ConstTransitivePtr<StartInfo> scenarioOps, initialOpts; //second one is a copy of settings received from pregame (not randomized)
@ -166,7 +167,7 @@ public:
private:
// ----- initialization -----
void preInitAuto();
void initNewGame(const IMapService * mapService, bool allowSavingRandomMap);
void initNewGame(const IMapService * mapService, bool allowSavingRandomMap, Load::ProgressAccumulator & progressTracking);
void checkMapChecksum();
void initGlobalBonuses();
void initGrailPosition();

View File

@ -288,7 +288,7 @@ std::string CLogFormatter::format(const LogRecord & record) const
boost::algorithm::replace_first(message, "%m", record.message);
boost::algorithm::replace_first(message, "%c", boost::posix_time::to_simple_string(record.timeStamp));
//return boost::to_string (boost::format("%d %d %d[%d] - %d") % dateStream.str() % level % record.domain.getName() % record.threadId % record.message);
//return boost::str (boost::format("%d %d %d[%d] - %d") % dateStream.str() % level % record.domain.getName() % record.threadId % record.message);
return message;
}

View File

@ -69,7 +69,7 @@ std::string CGCreature::getHoverText(const CGHeroInstance * hero) const
ms.appendLocalString(EMetaText::GENERAL_TXT,243);
break;
default: //decision = cost in gold
ms.appendRawString(boost::to_string(boost::format(VLC->generaltexth->allTexts[244]) % decision));
ms.appendRawString(boost::str(boost::format(VLC->generaltexth->allTexts[244]) % decision));
break;
}

Some files were not shown because too many files have changed in this diff Show More