1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
|
/*
* CGameHandler.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 <vcmi/Environment.h>
#include "../lib/IGameCallback.h"
#include "../lib/LoadProgress.h"
#include "../lib/ScriptHandler.h"
#include "../lib/gameState/GameStatistics.h"
#include "../lib/networkPacks/PacksForServer.h"
VCMI_LIB_NAMESPACE_BEGIN
struct SideInBattle;
class IMarket;
class SpellCastEnvironment;
class CConnection;
class CCommanderInstance;
class EVictoryLossCheckResult;
class CRandomGenerator;
struct CPackForServer;
struct NewTurn;
struct CGarrisonOperationPack;
struct SetResources;
struct NewStructures;
#if SCRIPTING_ENABLED
namespace scripting
{
class PoolImpl;
}
#endif
VCMI_LIB_NAMESPACE_END
class HeroPoolProcessor;
class CVCMIServer;
class CBaseForGHApply;
class PlayerMessageProcessor;
class BattleProcessor;
class TurnOrderProcessor;
class TurnTimerHandler;
class QueriesProcessor;
class CObjectVisitQuery;
class NewTurnProcessor;
class CGameHandler : public IGameCallback, public Environment
{
CVCMIServer * lobby;
public:
std::unique_ptr<HeroPoolProcessor> heroPool;
std::unique_ptr<BattleProcessor> battles;
std::unique_ptr<QueriesProcessor> queries;
std::unique_ptr<TurnOrderProcessor> turnOrder;
std::unique_ptr<TurnTimerHandler> turnTimerHandler;
std::unique_ptr<NewTurnProcessor> newTurnProcessor;
std::unique_ptr<CRandomGenerator> randomNumberGenerator;
//use enums as parameters, because doMove(sth, true, false, true) is not readable
enum EGuardLook {CHECK_FOR_GUARDS, IGNORE_GUARDS};
enum EVisitDest {VISIT_DEST, DONT_VISIT_DEST};
enum ELEaveTile {LEAVING_TILE, REMAINING_ON_TILE};
std::unique_ptr<PlayerMessageProcessor> playerMessages;
std::map<PlayerColor, std::set<std::shared_ptr<CConnection>>> connections; //player color -> connection to client with interface of that player
//queries stuff
ui32 QID;
SpellCastEnvironment * spellEnv;
const Services * services() const override;
const BattleCb * battle(const BattleID & battleID) const override;
const GameCb * game() const override;
vstd::CLoggerBase * logger() const override;
events::EventBus * eventBus() const override;
CVCMIServer * gameLobby() const;
bool isValidObject(const CGObjectInstance *obj) const;
bool isBlockedByQueries(const CPackForServer *pack, PlayerColor player);
bool isAllowedExchange(ObjectInstanceID id1, ObjectInstanceID id2);
void giveSpells(const CGTownInstance *t, const CGHeroInstance *h);
// Helpers to create new object of specified type
CGObjectInstance * createNewObject(const int3 & visitablePosition, MapObjectID objectID, MapObjectSubID subID);
void createWanderingMonster(const int3 & visitablePosition, CreatureID creature);
void createBoat(const int3 & visitablePosition, BoatId type, PlayerColor initiator) override;
void createHole(const int3 & visitablePosition, PlayerColor initiator);
void newObject(CGObjectInstance * object, PlayerColor initiator);
explicit CGameHandler(CVCMIServer * lobby);
~CGameHandler();
//////////////////////////////////////////////////////////////////////////
//from IGameCallback
//do sth
void changeSpells(const CGHeroInstance * hero, bool give, const std::set<SpellID> &spells) override;
void setResearchedSpells(const CGTownInstance * town, int level, const std::vector<SpellID> & spells, bool accepted) override;
bool removeObject(const CGObjectInstance * obj, const PlayerColor & initiator) override;
void setOwner(const CGObjectInstance * obj, PlayerColor owner) override;
void giveExperience(const CGHeroInstance * hero, TExpType val) override;
void changePrimSkill(const CGHeroInstance * hero, PrimarySkill which, si64 val, bool abs=false) override;
void changeSecSkill(const CGHeroInstance * hero, SecondarySkill which, int val, bool abs=false) override;
void showBlockingDialog(const IObjectInterface * caller, BlockingDialog *iw) override;
void showTeleportDialog(TeleportDialog *iw) override;
void showGarrisonDialog(ObjectInstanceID upobj, ObjectInstanceID hid, bool removableUnits) override;
void showObjectWindow(const CGObjectInstance * object, EOpenWindowMode window, const CGHeroInstance * visitor, bool addQuery) override;
void giveResource(PlayerColor player, GameResID which, int val) override;
void giveResources(PlayerColor player, TResources resources) override;
void giveCreatures(const CArmedInstance *objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) override;
void takeCreatures(ObjectInstanceID objid, const std::vector<CStackBasicDescriptor> &creatures) override;
bool changeStackType(const StackLocation &sl, const CCreature *c) override;
bool changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue = false) override;
bool insertNewStack(const StackLocation &sl, const CCreature *c, TQuantity count) override;
bool eraseStack(const StackLocation &sl, bool forceRemoval = false) override;
bool swapStacks(const StackLocation &sl1, const StackLocation &sl2) override;
bool addToSlot(const StackLocation &sl, const CCreature *c, TQuantity count) override;
void tryJoiningArmy(const CArmedInstance *src, const CArmedInstance *dst, bool removeObjWhenFinished, bool allowMerging) override;
bool moveStack(const StackLocation &src, const StackLocation &dst, TQuantity count = -1) override;
void removeAfterVisit(const CGObjectInstance *object) override;
bool giveHeroNewArtifact(const CGHeroInstance * h, const CArtifact * artType, const SpellID & spellId, const ArtifactPosition & pos);
bool giveHeroNewArtifact(const CGHeroInstance * h, const ArtifactID & artId, const ArtifactPosition & pos) override;
bool giveHeroNewScroll(const CGHeroInstance * h, const SpellID & spellId, const ArtifactPosition & pos) override;
bool putArtifact(const ArtifactLocation & al, const ArtifactInstanceID & id, std::optional<bool> askAssemble) override;
void removeArtifact(const ArtifactLocation &al) override;
void removeArtifact(const ObjectInstanceID & srcId, const std::vector<ArtifactPosition> & slotsPack);
bool moveArtifact(const PlayerColor & player, const ArtifactLocation & src, const ArtifactLocation & dst) override;
bool bulkMoveArtifacts(const PlayerColor & player, ObjectInstanceID srcId, ObjectInstanceID dstId, bool swap, bool equipped, bool backpack);
bool manageBackpackArtifacts(const PlayerColor & player, const ObjectInstanceID heroID, const ManageBackpackArtifacts::ManageCmd & sortType);
bool saveArtifactsCostume(const PlayerColor & player, const ObjectInstanceID heroID, uint32_t costumeIdx);
bool switchArtifactsCostume(const PlayerColor & player, const ObjectInstanceID heroID, uint32_t costumeIdx);
bool eraseArtifactByClient(const ArtifactLocation & al);
void synchronizeArtifactHandlerLists();
void heroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero) override;
void stopHeroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero) override;
void startBattle(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, const BattleLayout & layout, const CGTownInstance *town) override; //use hero=nullptr for no hero
void startBattle(const CArmedInstance *army1, const CArmedInstance *army2) override; //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle
bool moveHero(ObjectInstanceID hid, int3 dst, EMovementMode movementMode, bool transit = false, PlayerColor asker = PlayerColor::NEUTRAL) override;
void giveHeroBonus(GiveBonus * bonus) override;
void setMovePoints(SetMovePoints * smp) override;
void setMovePoints(ObjectInstanceID hid, int val, bool absolute) override;
void setManaPoints(ObjectInstanceID hid, int val) override;
void giveHero(ObjectInstanceID id, PlayerColor player, ObjectInstanceID boatId = ObjectInstanceID()) override;
void changeObjPos(ObjectInstanceID objid, int3 newPos, const PlayerColor & initiator) override;
void heroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2) override;
void changeFogOfWar(int3 center, ui32 radius, PlayerColor player, ETileVisibility mode) override;
void changeFogOfWar(const std::unordered_set<int3> &tiles, PlayerColor player,ETileVisibility mode) override;
void castSpell(const spells::Caster * caster, SpellID spellID, const int3 &pos) override;
/// Returns hero that is currently visiting this object, or nullptr if no visit is active
const CGHeroInstance * getVisitingHero(const CGObjectInstance *obj);
const CGObjectInstance * getVisitingObject(const CGHeroInstance *hero);
bool isVisitCoveredByAnotherQuery(const CGObjectInstance *obj, const CGHeroInstance *hero) override;
void setObjPropertyValue(ObjectInstanceID objid, ObjProperty prop, int32_t value) override;
void setObjPropertyID(ObjectInstanceID objid, ObjProperty prop, ObjPropertyID identifier) override;
void setBankObjectConfiguration(ObjectInstanceID objid, const BankConfig & configuration) override;
void setRewardableObjectConfiguration(ObjectInstanceID objid, const Rewardable::Configuration & configuration) override;
void setRewardableObjectConfiguration(ObjectInstanceID townInstanceID, BuildingID buildingID, const Rewardable::Configuration & configuration) override;
void showInfoDialog(InfoWindow * iw) override;
//////////////////////////////////////////////////////////////////////////
void useScholarSkill(ObjectInstanceID hero1, ObjectInstanceID hero2);
void setPortalDwelling(const CGTownInstance * town, bool forced, bool clear);
void visitObjectOnTile(const TerrainTile &t, const CGHeroInstance * h);
bool teleportHero(ObjectInstanceID hid, ObjectInstanceID dstid, ui8 source, PlayerColor asker = PlayerColor::NEUTRAL);
void visitCastleObjects(const CGTownInstance * obj, const CGHeroInstance * hero) override;
void visitCastleObjects(const CGTownInstance * obj, std::vector<const CGHeroInstance * > visitors);
void levelUpHero(const CGHeroInstance * hero, SecondarySkill skill);//handle client respond and send one more request if needed
void levelUpHero(const CGHeroInstance * hero);//initial call - check if hero have remaining levelups & handle them
void levelUpCommander (const CCommanderInstance * c, int skill); //secondary skill 1 to 6, special skill : skill - 100
void levelUpCommander (const CCommanderInstance * c);
void expGiven(const CGHeroInstance *hero); //triggers needed level-ups, handles also commander of this hero
//////////////////////////////////////////////////////////////////////////
void init(StartInfo *si, Load::ProgressAccumulator & progressTracking);
void handleClientDisconnection(std::shared_ptr<CConnection> c);
void handleReceivedPack(CPackForServer & pack);
bool hasPlayerAt(PlayerColor player, std::shared_ptr<CConnection> c) const;
bool hasBothPlayersAtSameConnection(PlayerColor left, PlayerColor right) const;
bool queryReply( QueryID qid, std::optional<int32_t> reply, PlayerColor player );
bool buildBoat( ObjectInstanceID objid, PlayerColor player );
bool setFormation( ObjectInstanceID hid, EArmyFormation formation );
bool tradeResources(const IMarket *market, ui32 amountToSell, PlayerColor player, GameResID toSell, GameResID toBuy);
bool sacrificeCreatures(const IMarket * market, const CGHeroInstance * hero, const std::vector<SlotID> & slot, const std::vector<ui32> & count);
bool sendResources(ui32 val, PlayerColor player, GameResID r1, PlayerColor r2);
bool sellCreatures(ui32 count, const IMarket *market, const CGHeroInstance * hero, SlotID slot, GameResID resourceID);
bool transformInUndead(const IMarket *market, const CGHeroInstance * hero, SlotID slot);
bool assembleArtifacts (ObjectInstanceID heroID, ArtifactPosition artifactSlot, bool assemble, ArtifactID assembleTo);
bool buyArtifact( ObjectInstanceID hid, ArtifactID aid ); //for blacksmith and mage guild only -> buying for gold in common buildings
bool buyArtifact( const IMarket *m, const CGHeroInstance *h, GameResID rid, ArtifactID aid); //for artifact merchant and black market -> buying for any resource in special building / advobject
bool sellArtifact( const IMarket *m, const CGHeroInstance *h, ArtifactInstanceID aid, GameResID rid); //for artifact merchant selling
//void lootArtifacts (TArtHolder source, TArtHolder dest, std::vector<ui32> &arts); //after battle - move al arts to winer
bool buySecSkill( const IMarket *m, const CGHeroInstance *h, SecondarySkill skill);
bool garrisonSwap(ObjectInstanceID tid);
bool swapGarrisonOnSiege(ObjectInstanceID tid) override;
bool upgradeCreature( ObjectInstanceID objid, SlotID pos, CreatureID upgID );
bool recruitCreatures(ObjectInstanceID objid, ObjectInstanceID dst, CreatureID crid, ui32 cram, si32 level, PlayerColor player);
bool buildStructure(ObjectInstanceID tid, BuildingID bid, bool force=false);//force - for events: no cost, no checkings
bool visitTownBuilding(ObjectInstanceID tid, BuildingID bid);
bool razeStructure(ObjectInstanceID tid, BuildingID bid);
bool spellResearch(ObjectInstanceID tid, SpellID spellAtSlot, bool accepted);
bool disbandCreature( ObjectInstanceID id, SlotID pos );
bool arrangeStacks( ObjectInstanceID id1, ObjectInstanceID id2, ui8 what, SlotID p1, SlotID p2, si32 val, PlayerColor player);
bool bulkMoveArmy(ObjectInstanceID srcArmy, ObjectInstanceID destArmy, SlotID srcSlot);
bool bulkSplitStack(SlotID src, ObjectInstanceID srcOwner, si32 howMany);
bool bulkMergeStacks(SlotID slotSrc, ObjectInstanceID srcOwner);
bool bulkSmartSplitStack(SlotID slotSrc, ObjectInstanceID srcOwner);
void save(const std::string &fname);
bool load(const std::string &fname);
void onPlayerTurnStarted(PlayerColor which);
void onPlayerTurnEnded(PlayerColor which);
void onNewTurn();
void addStatistics(StatisticDataSet &stat) const;
bool complain(const std::string &problem); //sends message to all clients, prints on the logs and return true
void objectVisited( const CGObjectInstance * obj, const CGHeroInstance * h );
void objectVisitEnded(const CGHeroInstance *h, PlayerColor player);
bool dig(const CGHeroInstance *h);
void moveArmy(const CArmedInstance *src, const CArmedInstance *dst, bool allowMerging);
template <typename Handler> void serialize(Handler &h)
{
h & QID;
h & *randomNumberGenerator;
h & *battles;
h & *heroPool;
h & *playerMessages;
h & *turnOrder;
h & *turnTimerHandler;
#if SCRIPTING_ENABLED
JsonNode scriptsState;
if(h.saving)
serverScripts->serializeState(h.saving, scriptsState);
h & scriptsState;
if(!h.saving)
serverScripts->serializeState(h.saving, scriptsState);
#endif
}
void sendToAllClients(CPackForClient & pack);
void sendAndApply(CPackForClient & pack) override;
void sendAndApply(CGarrisonOperationPack & pack);
void sendAndApply(SetResources & pack);
void sendAndApply(NewStructures & pack);
void wrongPlayerMessage(CPackForServer * pack, PlayerColor expectedplayer);
/// Unconditionally throws with "Action not allowed" message
[[noreturn]] void throwNotAllowedAction(CPackForServer * pack);
/// Throws if player stated in pack is not making turn right now
void throwIfPlayerNotActive(CPackForServer * pack);
/// Throws if object is not owned by pack sender
void throwIfWrongOwner(CPackForServer * pack, ObjectInstanceID id);
/// Throws if player is not present on connection of this pack
void throwIfWrongPlayer(CPackForServer * pack, PlayerColor player);
void throwIfWrongPlayer(CPackForServer * pack);
[[noreturn]] void throwAndComplain(CPackForServer * pack, std::string txt);
bool isPlayerOwns(CPackForServer * pack, ObjectInstanceID id);
void start(bool resume);
void tick(int millisecondsPassed);
bool sacrificeArtifact(const IMarket * market, const CGHeroInstance * hero, const std::vector<ArtifactInstanceID> & arts);
void spawnWanderingMonsters(CreatureID creatureID);
// Check for victory and loss conditions
void checkVictoryLossConditionsForPlayer(PlayerColor player);
void checkVictoryLossConditions(const std::set<PlayerColor> & playerColors);
void checkVictoryLossConditionsForAll();
vstd::RNG & getRandomGenerator() override;
#if SCRIPTING_ENABLED
scripting::Pool * getGlobalContextPool() const override;
// scripting::Pool * getContextPool() const override;
#endif
friend class CVCMIServer;
private:
std::unique_ptr<events::EventBus> serverEventBus;
#if SCRIPTING_ENABLED
std::shared_ptr<scripting::PoolImpl> serverScripts;
#endif
void reinitScripting();
void getVictoryLossMessage(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult, InfoWindow & out) const;
const std::string complainNoCreatures;
const std::string complainNotEnoughCreatures;
const std::string complainInvalidSlot;
};
class ExceptionNotAllowedAction : public std::exception
{
};
|