/* * Client.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 #include #include #include "../lib/callback/IClient.h" #include "../lib/callback/CGameInfoCallback.h" #include "../lib/ConditionalWait.h" #include "../lib/ResourceSet.h" VCMI_LIB_NAMESPACE_BEGIN struct CPackForClient; struct CPackForServer; class IBattleEventsReceiver; class CBattleGameInterface; class CGameInterface; class BattleAction; class BattleInfo; struct BankConfig; class CCallback; class CBattleCallback; #if SCRIPTING_ENABLED namespace scripting { class PoolImpl; } #endif namespace events { class EventBus; } VCMI_LIB_NAMESPACE_END class CClient; class CBaseForCLApply; template class ThreadSafeVector { using TLock = std::unique_lock; std::vector items; std::mutex mx; std::condition_variable cond; std::atomic isTerminating = false; public: void requestTermination() { isTerminating = true; clear(); } void clear() { TLock lock(mx); items.clear(); cond.notify_all(); } void pushBack(const T & item) { assert(!isTerminating); TLock lock(mx); items.push_back(item); cond.notify_all(); } void waitWhileContains(const T & item) { TLock lock(mx); cond.wait(lock, [this, &item](){ return !vstd::contains(items, item);}); if (isTerminating) throw TerminationRequestedException(); } bool tryRemovingElement(const T & item) //returns false if element was not present { assert(!isTerminating); TLock lock(mx); auto itr = vstd::find(items, item); if(itr == items.end()) //not in container { return false; } items.erase(itr); cond.notify_all(); return true; } }; class CPlayerEnvironment : public Environment { public: PlayerColor player; CClient * cl; std::shared_ptr mainCallback; CPlayerEnvironment(PlayerColor player_, CClient * cl_, std::shared_ptr mainCallback_); const Services * services() const override; vstd::CLoggerBase * logger() const override; events::EventBus * eventBus() const override; const BattleCb * battle(const BattleID & battle) const override; const GameCb * game() const override; }; /// Class which handles client - server logic class CClient : public Environment, public IClient { std::shared_ptr gamestate; int requestCounter = 1; public: std::map> playerint; std::map> battleints; std::map>> additionalBattleInts; std::unique_ptr currentBattleAction; CClient(); ~CClient(); const Services * services() const override; const BattleCb * battle(const BattleID & battle) const override; const GameCb * game() const override; vstd::CLoggerBase * logger() const override; events::EventBus * eventBus() const override; std::shared_ptr gameStatePtr() { return gamestate; } CGameState & gameState() { return *gamestate; } const CGameState & gameState() const { return *gamestate; } IGameInfoCallback & gameInfo(); void newGame(std::shared_ptr gameState); void loadGame(std::shared_ptr gameState); void endNetwork(); void finishGameplay(); void endGame(); void initMapHandler(); void initPlayerEnvironments(); void initPlayerInterfaces(); std::string aiNameForPlayer(const PlayerSettings & ps, bool battleAI, bool alliedToHuman) const; //empty means no AI -> human std::string aiNameForPlayer(bool battleAI, bool alliedToHuman) const; void installNewPlayerInterface(std::shared_ptr gameInterface, PlayerColor color, bool battlecb = false); void installNewBattleInterface(std::shared_ptr battleInterface, PlayerColor color, bool needCallback = true); //Set of metrhods that allows adding more interfaces for this player that'll receive game event call-ins. void registerBattleInterface(std::shared_ptr battleEvents, PlayerColor color); void unregisterBattleInterface(std::shared_ptr battleEvents, PlayerColor color); ThreadSafeVector waitingRequest; void handlePack(CPackForClient & pack); //applies the given pack and deletes it int sendRequest(const CPackForServer & request, PlayerColor player, bool waitTillRealize) override; //returns ID given to that request std::optional makeSurrenderRetreatDecision(PlayerColor player, const BattleID & battleID, const BattleStateInfoForRetreat & battleState) override; void battleStarted(const BattleID & battle); void battleFinished(const BattleID & battleID); void startPlayerBattleAction(const BattleID & battleID, PlayerColor color); friend class CCallback; //handling players actions friend class CBattleCallback; //handling players actions void removeGUI() const; private: std::map> battleCallbacks; //callbacks given to player interfaces std::map> playerEnvironments; #if SCRIPTING_ENABLED std::shared_ptr clientScripts; #endif std::unique_ptr clientEventBus; void reinitScripting(); };