Переглянути джерело

Implemented connection of match server to global lobby

Ivan Savenko 1 рік тому
батько
коміт
9fb7d2817a

BIN
launcher/icons/menu-lobby.png


BIN
launcher/icons/room-private.png


+ 2 - 0
server/CMakeLists.txt

@@ -16,6 +16,7 @@ set(server_SRCS
 		processors/TurnOrderProcessor.cpp
 
 		CGameHandler.cpp
+		GlobalLobbyProcessor.cpp
 		ServerSpellCastEnvironment.cpp
 		CVCMIServer.cpp
 		NetPacksServer.cpp
@@ -41,6 +42,7 @@ set(server_HEADERS
 		processors/TurnOrderProcessor.h
 
 		CGameHandler.h
+		GlobalLobbyProcessor.h
 		ServerSpellCastEnvironment.h
 		CVCMIServer.h
 		LobbyNetPackVisitors.h

+ 6 - 23
server/CVCMIServer.cpp

@@ -8,7 +8,7 @@
  *
  */
 #include "StdInc.h"
-#include <boost/program_options.hpp>
+#include "CVCMIServer.h"
 
 #include "../lib/filesystem/Filesystem.h"
 #include "../lib/campaign/CampaignState.h"
@@ -21,7 +21,6 @@
 #include "../lib/spells/CSpellHandler.h"
 #include "../lib/CCreatureHandler.h"
 #include "zlib.h"
-#include "CVCMIServer.h"
 #include "../lib/StartInfo.h"
 #include "../lib/mapping/CMapHeader.h"
 #include "../lib/rmg/CMapGenOptions.h"
@@ -34,6 +33,7 @@
 #include "../lib/VCMI_Lib.h"
 #include "../lib/VCMIDirs.h"
 #include "CGameHandler.h"
+#include "GlobalLobbyProcessor.h"
 #include "processors/PlayerMessageProcessor.h"
 #include "../lib/mapping/CMapInfo.h"
 #include "../lib/GameConstants.h"
@@ -53,6 +53,7 @@
 #include <boost/uuid/uuid.hpp>
 #include <boost/uuid/uuid_io.hpp>
 #include <boost/uuid/uuid_generators.hpp>
+#include <boost/program_options.hpp>
 
 #include "../lib/gameState/CGameState.h"
 
@@ -165,6 +166,7 @@ CVCMIServer::CVCMIServer(boost::program_options::variables_map & opts)
 	networkHandler = INetworkHandler::createHandler();
 	networkServer = networkHandler->createServerTCP(*this);
 	networkServer->start(port);
+	establishOutgoingConnection();
 	logNetwork->info("Listening for connections at port %d", port);
 }
 
@@ -172,9 +174,6 @@ CVCMIServer::~CVCMIServer() = default;
 
 void CVCMIServer::onNewConnection(const std::shared_ptr<INetworkConnection> & connection)
 {
-	if (activeConnections.empty())
-		establishOutgoingConnection();
-
 	if(state == EServerState::LOBBY)
 	{
 		activeConnections.push_back(std::make_shared<CConnection>(connection));
@@ -195,16 +194,6 @@ void CVCMIServer::onPacketReceived(const std::shared_ptr<INetworkConnection> & c
 	pack->visit(visitor);
 }
 
-void CVCMIServer::onConnectionFailed(const std::string & errorMessage)
-{
-	//TODO: handle failure to connect to lobby
-}
-
-void CVCMIServer::onConnectionEstablished(const std::shared_ptr<INetworkConnection> &)
-{
-	//TODO: handle connection to lobby - login?
-}
-
 void CVCMIServer::setState(EServerState value)
 {
 	state = value;
@@ -262,14 +251,8 @@ void CVCMIServer::onTimer()
 
 void CVCMIServer::establishOutgoingConnection()
 {
-	if(!cmdLineOptions.count("lobby"))
-		return;
-
-	std::string hostname = settings["lobby"]["hostname"].String();
-	int16_t port = settings["lobby"]["port"].Integer();
-
-	outgoingConnection = networkHandler->createClientTCP(*this);
-	outgoingConnection->start(hostname, port);
+	if(cmdLineOptions.count("lobby"))
+		lobbyProcessor = std::make_unique<GlobalLobbyProcessor>(*this);
 }
 
 void CVCMIServer::prepareToRestart()

+ 5 - 8
server/CVCMIServer.h

@@ -37,6 +37,7 @@ VCMI_LIB_NAMESPACE_END
 class CGameHandler;
 class CBaseForServerApply;
 class CBaseForGHApply;
+class GlobalLobbyProcessor;
 
 enum class EServerState : ui8
 {
@@ -47,15 +48,11 @@ enum class EServerState : ui8
 	SHUTDOWN
 };
 
-class CVCMIServer : public LobbyInfo, public INetworkServerListener, public INetworkClientListener, public INetworkTimerListener
+class CVCMIServer : public LobbyInfo, public INetworkServerListener, public INetworkTimerListener
 {
-	std::unique_ptr<INetworkHandler> networkHandler;
-
 	/// Network server instance that receives and processes incoming connections on active socket
 	std::unique_ptr<INetworkServer> networkServer;
-
-	/// Outgoing connection established by this server to game lobby for proxy mode (only in lobby game)
-	std::unique_ptr<INetworkClient> outgoingConnection;
+	std::unique_ptr<GlobalLobbyProcessor> lobbyProcessor;
 
 	std::chrono::steady_clock::time_point gameplayStartTime;
 	std::chrono::steady_clock::time_point lastTimerUpdateTime;
@@ -64,6 +61,8 @@ public:
 	/// List of all active connections
 	std::vector<std::shared_ptr<CConnection>> activeConnections;
 
+	std::unique_ptr<INetworkHandler> networkHandler;
+
 private:
 	bool restartGameplay; // FIXME: this is just a hack
 
@@ -75,8 +74,6 @@ private:
 	void onDisconnected(const std::shared_ptr<INetworkConnection> & connection) override;
 	void onPacketReceived(const std::shared_ptr<INetworkConnection> & connection, const std::vector<uint8_t> & message) override;
 	void onNewConnection(const std::shared_ptr<INetworkConnection> &) override;
-	void onConnectionFailed(const std::string & errorMessage) override;
-	void onConnectionEstablished(const std::shared_ptr<INetworkConnection> &) override;
 	void onTimer() override;
 
 	void establishOutgoingConnection();

+ 82 - 0
server/GlobalLobbyProcessor.cpp

@@ -0,0 +1,82 @@
+/*
+ * GlobalLobbyProcessor.cpp, 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
+ *
+ */
+#include "StdInc.h"
+#include "GlobalLobbyProcessor.h"
+
+#include "CVCMIServer.h"
+#include "../lib/CConfigHandler.h"
+
+GlobalLobbyProcessor::GlobalLobbyProcessor(CVCMIServer & owner)
+	: owner(owner)
+	, networkClient(owner.networkHandler->createClientTCP(*this))
+{
+	std::string hostname = settings["lobby"]["hostname"].String();
+	int16_t port = settings["lobby"]["port"].Integer();
+	networkClient->start(hostname, port);
+	logGlobal->info("Connecting to lobby server");
+}
+
+void GlobalLobbyProcessor::onDisconnected(const std::shared_ptr<INetworkConnection> & connection)
+{
+	throw std::runtime_error("Lost connection to a lobby server!");
+}
+
+void GlobalLobbyProcessor::onPacketReceived(const std::shared_ptr<INetworkConnection> & connection, const std::vector<uint8_t> & message)
+{
+	JsonNode json(message.data(), message.size());
+
+	if(json["type"].String() == "loginFailed")
+		return receiveLoginFailed(json);
+
+	if(json["type"].String() == "loginSuccess")
+		return receiveLoginSuccess(json);
+
+	throw std::runtime_error("Received unexpected message from lobby server: " + json["type"].String());
+}
+
+void GlobalLobbyProcessor::receiveLoginFailed(const JsonNode & json)
+{
+	throw std::runtime_error("Failed to login into a lobby server!");
+}
+
+void GlobalLobbyProcessor::receiveLoginSuccess(const JsonNode & json)
+{
+	// no-op, wait just for any new commands from lobby
+	logGlobal->info("Succesfully connected to lobby server");
+}
+
+void GlobalLobbyProcessor::onConnectionFailed(const std::string & errorMessage)
+{
+	throw std::runtime_error("Failed to connect to a lobby server!");
+}
+
+void GlobalLobbyProcessor::onConnectionEstablished(const std::shared_ptr<INetworkConnection> &)
+{
+	logGlobal->info("Connection to lobby server established");
+
+	JsonNode toSend;
+	toSend["type"].String() = "serverLogin";
+	toSend["accountID"] = settings["lobby"]["accountID"];
+	toSend["accountCookie"] = settings["lobby"]["accountCookie"];
+	sendMessage(toSend);
+}
+
+void GlobalLobbyProcessor::sendMessage(const JsonNode & data)
+{
+	std::string payloadString = data.toJson(true);
+
+	// FIXME: find better approach
+	uint8_t * payloadBegin = reinterpret_cast<uint8_t *>(payloadString.data());
+	uint8_t * payloadEnd = payloadBegin + payloadString.size();
+
+	std::vector<uint8_t> payloadBuffer(payloadBegin, payloadEnd);
+
+	networkClient->sendPacket(payloadBuffer);
+}

+ 39 - 0
server/GlobalLobbyProcessor.h

@@ -0,0 +1,39 @@
+/*
+ * GlobalLobbyProcessor.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/network/NetworkInterface.h"
+
+VCMI_LIB_NAMESPACE_BEGIN
+class JsonNode;
+VCMI_LIB_NAMESPACE_END
+
+class CVCMIServer;
+
+class GlobalLobbyProcessor : public INetworkClientListener
+{
+	CVCMIServer & owner;
+
+	std::shared_ptr<INetworkConnection> controlConnection;
+//	std::set<std::shared_ptr<INetworkConnection>> proxyConnections;
+	std::unique_ptr<INetworkClient> networkClient;
+
+	void onDisconnected(const std::shared_ptr<INetworkConnection> & connection) override;
+	void onPacketReceived(const std::shared_ptr<INetworkConnection> & connection, const std::vector<uint8_t> & message) override;
+	void onConnectionFailed(const std::string & errorMessage) override;
+	void onConnectionEstablished(const std::shared_ptr<INetworkConnection> &) override;
+
+	void sendMessage(const JsonNode & data);
+
+	void receiveLoginFailed(const JsonNode & json);
+	void receiveLoginSuccess(const JsonNode & json);
+public:
+	GlobalLobbyProcessor(CVCMIServer & owner);
+};