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
|
/*
* CServerHandler.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 "../lib/CStopWatch.h"
#include "../lib/StartInfo.h"
struct SharedMemory;
class CConnection;
class PlayerColor;
struct StartInfo;
class CMapInfo;
struct ClientPlayer;
struct CPack;
struct CPackForLobby;
class CClient;
template<typename T> class CApplier;
class CBaseForLobbyApply;
// TODO: Add mutex so we can't set CONNECTION_CANCELLED if client already connected, but thread not setup yet
enum class EClientState : ui8
{
NONE = 0,
CONNECTING, // Trying to connect to server
CONNECTION_CANCELLED, // Connection cancelled by player, stop attempts to connect
LOBBY, // Client is connected to lobby
LOBBY_CAMPAIGN, // Client is on scenario bonus selection screen
STARTING, // Gameplay interfaces being created, we pause netpacks retrieving
GAMEPLAY, // In-game, used by some UI
DISCONNECTING // We disconnecting, drop all netpacks
};
class IServerAPI
{
protected:
virtual void sendLobbyPack(const CPackForLobby & pack) const = 0;
public:
virtual ~IServerAPI() {}
virtual void sendClientConnecting() const = 0;
virtual void sendClientDisconnecting() = 0;
virtual void setCampaignState(std::shared_ptr<CCampaignState> newCampaign) = 0;
virtual void setCampaignMap(int mapId) const = 0;
virtual void setCampaignBonus(int bonusId) const = 0;
virtual void setMapInfo(std::shared_ptr<CMapInfo> to, std::shared_ptr<CMapGenOptions> mapGenOpts = {}) const = 0;
virtual void setPlayer(PlayerColor color) const = 0;
virtual void setPlayerOption(ui8 what, ui8 dir, PlayerColor player) const = 0;
virtual void setDifficulty(int to) const = 0;
virtual void setTurnLength(int npos) const = 0;
virtual void sendMessage(const std::string & txt) const = 0;
virtual void sendGuiAction(ui8 action) const = 0; // TODO: possibly get rid of it?
virtual void sendStartGame(bool allowOnlyAI = false) const = 0;
};
/// structure to handle running server and connecting to it
class CServerHandler : public IServerAPI, public LobbyInfo
{
std::shared_ptr<CApplier<CBaseForLobbyApply>> applier;
std::shared_ptr<boost::recursive_mutex> mx;
std::list<CPackForLobby *> packsForLobbyScreen; //protected by mx
std::vector<std::string> myNames;
void threadHandleConnection();
void threadRunServer();
void sendLobbyPack(const CPackForLobby & pack) const override;
public:
std::atomic<EClientState> state;
////////////////////
// FIXME: Bunch of crutches to glue it all together
// For starting non-custom campaign and continue to next mission
std::shared_ptr<CCampaignState> campaignStateToSend;
ui8 screenType; // To create lobby UI only after server is setup
ui8 loadMode; // For saves filtering in SelectionTab
////////////////////
std::unique_ptr<CStopWatch> th;
std::shared_ptr<boost::thread> threadRunLocalServer;
std::shared_ptr<CConnection> c;
CClient * client;
CServerHandler();
void resetStateForLobby(const StartInfo::EMode mode, const std::vector<std::string> * names = nullptr);
void startLocalServerAndConnect();
void justConnectToServer(const std::string &addr = "", const ui16 port = 0);
void applyPacksOnLobbyScreen();
void stopServerConnection();
// Helpers for lobby state access
std::set<PlayerColor> getHumanColors();
PlayerColor myFirstColor() const;
bool isMyColor(PlayerColor color) const;
ui8 myFirstId() const; // Used by chat only!
bool isServerLocal() const;
bool isHost() const;
bool isGuest() const;
static ui16 getDefaultPort();
static std::string getDefaultPortStr();
// Lobby server API for UI
void sendClientConnecting() const override;
void sendClientDisconnecting() override;
void setCampaignState(std::shared_ptr<CCampaignState> newCampaign) override;
void setCampaignMap(int mapId) const override;
void setCampaignBonus(int bonusId) const override;
void setMapInfo(std::shared_ptr<CMapInfo> to, std::shared_ptr<CMapGenOptions> mapGenOpts = {}) const override;
void setPlayer(PlayerColor color) const override;
void setPlayerOption(ui8 what, ui8 dir, PlayerColor player) const override;
void setDifficulty(int to) const override;
void setTurnLength(int npos) const override;
void sendMessage(const std::string & txt) const override;
void sendGuiAction(ui8 action) const override;
void sendStartGame(bool allowOnlyAI = false) const override;
void startGameplay();
void endGameplay(bool closeConnection = true, bool restart = false);
void startCampaignScenario(std::shared_ptr<CCampaignState> cs = {});
// TODO: LobbyState must be updated within game so we should always know how many player interfaces our client handle
int howManyPlayerInterfaces();
ui8 getLoadMode();
void debugStartTest(std::string filename, bool save = false);
};
extern CServerHandler * CSH;
|