File: CServerHandler.h

package info (click to toggle)
vcmi 1.6.5%2Bdfsg-2
  • links: PTS, VCS
  • area: contrib
  • in suites: forky, sid, trixie
  • size: 32,060 kB
  • sloc: cpp: 238,971; python: 265; sh: 224; xml: 157; ansic: 78; objc: 61; makefile: 49
file content (219 lines) | stat: -rw-r--r-- 7,933 bytes parent folder | download
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;