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
|
/*
* 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/network/NetworkInterface.h"
#include "../lib/StartInfo.h"
#include "../lib/gameState/GameStatistics.h"
VCMI_LIB_NAMESPACE_BEGIN
class CConnection;
class PlayerColor;
struct StartInfo;
struct TurnTimerInfo;
class CMapInfo;
class CGameState;
struct ClientPlayer;
struct CPackForLobby;
struct CPackForClient;
class HighScoreParameter;
VCMI_LIB_NAMESPACE_END
class CClient;
class CBaseForLobbyApply;
class GlobalLobbyClient;
class GameChatHandler;
class IServerRunner;
enum class ESelectionScreen : ui8;
enum class ELoadMode : ui8;
// 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
};
enum class EServerMode : uint8_t
{
NONE = 0,
LOCAL, // no global lobby
LOBBY_HOST, // We are hosting global server available via global lobby
LOBBY_GUEST // Connecting to a remote server via proxy provided by global lobby
};
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<CampaignState> newCampaign) = 0;
virtual void setCampaignMap(CampaignScenarioID 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 setPlayerName(PlayerColor color, const std::string & name) const = 0;
virtual void setPlayerHandicap(PlayerColor color, Handicap handicap) const = 0;
virtual void setPlayerOption(ui8 what, int32_t value, PlayerColor player) const = 0;
virtual void setDifficulty(int to) const = 0;
virtual void setTurnTimerInfo(const TurnTimerInfo &) const = 0;
virtual void setSimturnsInfo(const SimturnsInfo &) const = 0;
virtual void setExtraOptionsInfo(const ExtraOptionsInfo & info) 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;
virtual void sendRestartGame() const = 0;
};
/// structure to handle running server and connecting to it
class CServerHandler final : public IServerAPI, public LobbyInfo, public INetworkClientListener, public INetworkTimerListener, boost::noncopyable
{
friend class ApplyOnLobbyHandlerNetPackVisitor;
std::unique_ptr<INetworkHandler> networkHandler;
std::shared_ptr<INetworkConnection> networkConnection;
std::unique_ptr<GlobalLobbyClient> lobbyClient;
std::unique_ptr<GameChatHandler> gameChat;
std::unique_ptr<IServerRunner> serverRunner;
std::shared_ptr<CMapInfo> mapToStart;
std::vector<std::string> localPlayerNames;
boost::thread threadNetwork;
std::atomic<EClientState> state;
void threadRunNetwork();
void waitForServerShutdown();
void onPacketReceived(const NetworkConnectionPtr &, const std::vector<std::byte> & message) override;
void onConnectionFailed(const std::string & errorMessage) override;
void onConnectionEstablished(const NetworkConnectionPtr &) override;
void onDisconnected(const NetworkConnectionPtr &, const std::string & errorMessage) override;
void onTimer() override;
void applyPackOnLobbyScreen(CPackForLobby & pack);
std::string serverHostname;
ui16 serverPort;
bool isServerLocal() const;
public:
/// High-level connection overlay that is capable of (de)serializing network data
std::shared_ptr<CConnection> logicConnection;
////////////////////
// FIXME: Bunch of crutches to glue it all together
// For starting non-custom campaign and continue to next mission
std::shared_ptr<CampaignState> campaignStateToSend;
ESelectionScreen screenType; // To create lobby UI only after server is setup
EServerMode serverMode;
ELoadMode loadMode; // For saves filtering in SelectionTab
////////////////////
std::unique_ptr<CStopWatch> th;
std::unique_ptr<CClient> client;
CServerHandler();
~CServerHandler();
void resetStateForLobby(EStartMode mode, ESelectionScreen screen, EServerMode serverMode, const std::vector<std::string> & playerNames);
void startLocalServerAndConnect(bool connectToLobby);
void connectToServer(const std::string & addr, const ui16 port);
GameChatHandler & getGameChat();
GlobalLobbyClient & getGlobalLobby();
INetworkHandler & getNetworkHandler();
// Helpers for lobby state access
std::set<PlayerColor> getHumanColors();
PlayerColor myFirstColor() const;
bool isMyColor(PlayerColor color) const;
ui8 myFirstId() const; // Used by chat only!
EClientState getState() const;
void setState(EClientState newState);
bool isHost() const;
bool isGuest() const;
bool inLobbyRoom() const;
bool inGame() const;
const std::string & getCurrentHostname() const;
const std::string & getLocalHostname() const;
const std::string & getRemoteHostname() const;
ui16 getCurrentPort() const;
ui16 getLocalPort() const;
ui16 getRemotePort() const;
// Lobby server API for UI
void sendLobbyPack(const CPackForLobby & pack) const override;
void sendClientConnecting() const override;
void sendClientDisconnecting() override;
void setCampaignState(std::shared_ptr<CampaignState> newCampaign) override;
void setCampaignMap(CampaignScenarioID 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 setPlayerName(PlayerColor color, const std::string & name) const override;
void setPlayerHandicap(PlayerColor color, Handicap handicap) const override;
void setPlayerOption(ui8 what, int32_t value, PlayerColor player) const override;
void setDifficulty(int to) const override;
void setTurnTimerInfo(const TurnTimerInfo &) const override;
void setSimturnsInfo(const SimturnsInfo &) const override;
void setExtraOptionsInfo(const ExtraOptionsInfo &) const override;
void sendMessage(const std::string & txt) const override;
void sendGuiAction(ui8 action) const override;
void sendRestartGame() const override;
void sendStartGame(bool allowOnlyAI = false) const override;
void startMapAfterConnection(std::shared_ptr<CMapInfo> to);
bool validateGameStart(bool allowOnlyAI = false) const;
void debugStartTest(std::string filename, bool save = false);
void startGameplay(VCMI_LIB_WRAP_NAMESPACE(CGameState) * gameState = nullptr);
void showHighScoresAndEndGameplay(PlayerColor player, bool victory, const StatisticDataSet & statistic);
void endNetwork();
void endGameplay();
void restartGameplay();
void startCampaignScenario(HighScoreParameter param, std::shared_ptr<CampaignState> cs, const StatisticDataSet & statistic);
void showServerError(const std::string & txt) const;
// TODO: LobbyState must be updated within game so we should always know how many player interfaces our client handle
int howManyPlayerInterfaces();
ELoadMode getLoadMode();
void visitForLobby(CPackForLobby & lobbyPack);
void visitForClient(CPackForClient & clientPack);
};
extern CServerHandler * CSH;
|