mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Added list of active accounts and rooms to UI. Added room creation logic
This commit is contained in:
		| @@ -277,6 +277,7 @@ set(client_HEADERS | ||||
| 	renderSDL/SDL_PixelAccess.h | ||||
|  | ||||
| 	globalLobby/GlobalLobbyClient.h | ||||
| 	globalLobby/GlobalLobbyDefines.h | ||||
| 	globalLobby/GlobalLobbyLoginWindow.h | ||||
| 	globalLobby/GlobalLobbyServerSetup.h | ||||
| 	globalLobby/GlobalLobbyWidget.h | ||||
|   | ||||
| @@ -126,9 +126,6 @@ public: | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| static const std::string NAME_AFFIX = "client"; | ||||
| static const std::string NAME = GameConstants::VCMI_VERSION + std::string(" (") + NAME_AFFIX + ')'; //application name | ||||
|  | ||||
| CServerHandler::~CServerHandler() | ||||
| { | ||||
| 	networkHandler->stop(); | ||||
| @@ -141,7 +138,8 @@ CServerHandler::CServerHandler() | ||||
| 	, applier(std::make_unique<CApplier<CBaseForLobbyApply>>()) | ||||
| 	, lobbyClient(std::make_unique<GlobalLobbyClient>()) | ||||
| 	, client(nullptr) | ||||
| 	, loadMode(0) | ||||
| 	, loadMode(ELoadMode::NONE) | ||||
| 	, screenType(ESelectionScreen::unknown) | ||||
| 	, campaignStateToSend(nullptr) | ||||
| 	, campaignServerRestartLock(false) | ||||
| { | ||||
| @@ -158,7 +156,7 @@ void CServerHandler::threadRunNetwork() | ||||
| 	logGlobal->info("Ending network thread"); | ||||
| } | ||||
|  | ||||
| void CServerHandler::resetStateForLobby(const StartInfo::EMode mode, const std::vector<std::string> * names) | ||||
| void CServerHandler::resetStateForLobby(EStartMode mode, ESelectionScreen screen, const std::vector<std::string> & names) | ||||
| { | ||||
| 	hostClientId = -1; | ||||
| 	state = EClientState::NONE; | ||||
| @@ -169,9 +167,10 @@ void CServerHandler::resetStateForLobby(const StartInfo::EMode mode, const std:: | ||||
| 	playerNames.clear(); | ||||
| 	si->difficulty = 1; | ||||
| 	si->mode = mode; | ||||
| 	screenType = screen; | ||||
| 	myNames.clear(); | ||||
| 	if(names && !names->empty()) //if have custom set of player names - use it | ||||
| 		myNames = *names; | ||||
| 	if(!names.empty()) //if have custom set of player names - use it | ||||
| 		myNames = names; | ||||
| 	else | ||||
| 		myNames.push_back(settings["general"]["playerName"].String()); | ||||
| } | ||||
| @@ -617,7 +616,7 @@ void CServerHandler::sendStartGame(bool allowOnlyAI) const | ||||
| 	if(client) | ||||
| 	{ | ||||
| 		lsg.initializedStartInfo = std::make_shared<StartInfo>(* const_cast<StartInfo *>(client->getStartInfo(true))); | ||||
| 		lsg.initializedStartInfo->mode = StartInfo::NEW_GAME; | ||||
| 		lsg.initializedStartInfo->mode = EStartMode::NEW_GAME; | ||||
| 		lsg.initializedStartInfo->seedToBeUsed = lsg.initializedStartInfo->seedPostInit = 0; | ||||
| 		* si = * lsg.initializedStartInfo; | ||||
| 	} | ||||
| @@ -641,13 +640,13 @@ void CServerHandler::startGameplay(VCMI_LIB_WRAP_NAMESPACE(CGameState) * gameSta | ||||
|  | ||||
| 	switch(si->mode) | ||||
| 	{ | ||||
| 	case StartInfo::NEW_GAME: | ||||
| 	case EStartMode::NEW_GAME: | ||||
| 		client->newGame(gameState); | ||||
| 		break; | ||||
| 	case StartInfo::CAMPAIGN: | ||||
| 	case EStartMode::CAMPAIGN: | ||||
| 		client->newGame(gameState); | ||||
| 		break; | ||||
| 	case StartInfo::LOAD_GAME: | ||||
| 	case EStartMode::LOAD_GAME: | ||||
| 		client->loadGame(gameState); | ||||
| 		break; | ||||
| 	default: | ||||
| @@ -765,7 +764,7 @@ int CServerHandler::howManyPlayerInterfaces() | ||||
| 	return playerInts; | ||||
| } | ||||
|  | ||||
| ui8 CServerHandler::getLoadMode() | ||||
| ELoadMode CServerHandler::getLoadMode() | ||||
| { | ||||
| 	if(loadMode != ELoadMode::TUTORIAL && state == EClientState::GAMEPLAY) | ||||
| 	{ | ||||
| @@ -790,15 +789,13 @@ void CServerHandler::debugStartTest(std::string filename, bool save) | ||||
| 	auto mapInfo = std::make_shared<CMapInfo>(); | ||||
| 	if(save) | ||||
| 	{ | ||||
| 		resetStateForLobby(StartInfo::LOAD_GAME); | ||||
| 		resetStateForLobby(EStartMode::LOAD_GAME, ESelectionScreen::loadGame, {}); | ||||
| 		mapInfo->saveInit(ResourcePath(filename, EResType::SAVEGAME)); | ||||
| 		screenType = ESelectionScreen::loadGame; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		resetStateForLobby(StartInfo::NEW_GAME); | ||||
| 		resetStateForLobby(EStartMode::NEW_GAME, ESelectionScreen::newGame, {}); | ||||
| 		mapInfo->mapInit(filename); | ||||
| 		screenType = ESelectionScreen::newGame; | ||||
| 	} | ||||
| 	if(settings["session"]["donotstartserver"].Bool()) | ||||
| 		connectToServer(getLocalHostname(), getLocalPort()); | ||||
|   | ||||
| @@ -40,6 +40,9 @@ class GlobalLobbyClient; | ||||
| class HighScoreCalculation; | ||||
| class HighScoreParameter; | ||||
|  | ||||
| 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 | ||||
| { | ||||
| @@ -128,8 +131,8 @@ public: | ||||
| 	// For starting non-custom campaign and continue to next mission | ||||
| 	std::shared_ptr<CampaignState> campaignStateToSend; | ||||
|  | ||||
| 	ui8 screenType; // To create lobby UI only after server is setup | ||||
| 	ui8 loadMode; // For saves filtering in SelectionTab | ||||
| 	ESelectionScreen screenType; // To create lobby UI only after server is setup | ||||
| 	ELoadMode loadMode; // For saves filtering in SelectionTab | ||||
| 	//////////////////// | ||||
|  | ||||
| 	std::unique_ptr<CStopWatch> th; | ||||
| @@ -143,7 +146,7 @@ public: | ||||
| 	CServerHandler(); | ||||
| 	~CServerHandler(); | ||||
| 	 | ||||
| 	void resetStateForLobby(const StartInfo::EMode mode, const std::vector<std::string> * names = nullptr); | ||||
| 	void resetStateForLobby(EStartMode mode, ESelectionScreen screen, const std::vector<std::string> & names); | ||||
| 	void startLocalServerAndConnect(bool connectToLobby); | ||||
| 	void connectToServer(const std::string & addr, const ui16 port); | ||||
|  | ||||
| @@ -196,7 +199,7 @@ public: | ||||
|  | ||||
| 	// TODO: LobbyState must be updated within game so we should always know how many player interfaces our client handle | ||||
| 	int howManyPlayerInterfaces(); | ||||
| 	ui8 getLoadMode(); | ||||
| 	ELoadMode getLoadMode(); | ||||
|  | ||||
| 	void visitForLobby(CPackForLobby & lobbyPack); | ||||
| 	void visitForClient(CPackForClient & clientPack); | ||||
|   | ||||
| @@ -20,6 +20,8 @@ | ||||
| #include "lobby/SelectionTab.h" | ||||
| #include "lobby/CBonusSelection.h" | ||||
| #include "globalLobby/GlobalLobbyWindow.h" | ||||
| #include "globalLobby/GlobalLobbyServerSetup.h" | ||||
| #include "globalLobby/GlobalLobbyClient.h" | ||||
|  | ||||
| #include "CServerHandler.h" | ||||
| #include "CGameInfo.h" | ||||
| @@ -49,6 +51,18 @@ void ApplyOnLobbyHandlerNetPackVisitor::visitLobbyClientConnected(LobbyClientCon | ||||
| 			if (GH.windows().topWindow<CSimpleJoinScreen>()) | ||||
| 				GH.windows().popWindows(1); | ||||
|  | ||||
| 			if (!GH.windows().findWindows<GlobalLobbyServerSetup>().empty()) | ||||
| 			{ | ||||
| 				// announce opened game room | ||||
| 				// TODO: find better approach? | ||||
| 				int roomType = settings["lobby"]["roomType"].Integer(); | ||||
|  | ||||
| 				if (roomType != 0) | ||||
| 					handler.getGlobalLobby().sendOpenPrivateRoom(); | ||||
| 				else | ||||
| 					handler.getGlobalLobby().sendOpenPublicRoom(); | ||||
| 			} | ||||
|  | ||||
| 			while (!GH.windows().findWindows<GlobalLobbyWindow>().empty()) | ||||
| 			{ | ||||
| 				// if global lobby is open, pop all dialogs on top of it as well as lobby itself | ||||
| @@ -141,7 +155,7 @@ void ApplyOnLobbyHandlerNetPackVisitor::visitLobbyStartGame(LobbyStartGame & pac | ||||
| 	} | ||||
| 	 | ||||
| 	handler.state = EClientState::STARTING; | ||||
| 	if(handler.si->mode != StartInfo::LOAD_GAME || pack.clientId == handler.c->connectionID) | ||||
| 	if(handler.si->mode != EStartMode::LOAD_GAME || pack.clientId == handler.c->connectionID) | ||||
| 	{ | ||||
| 		auto modeBackup = handler.si->mode; | ||||
| 		handler.si = pack.initializedStartInfo; | ||||
|   | ||||
| @@ -16,6 +16,8 @@ | ||||
| #include "../gui/CGuiHandler.h" | ||||
| #include "../gui/EventDispatcher.h" | ||||
| #include "../gui/ShortcutHandler.h" | ||||
| #include "../CServerHandler.h" | ||||
| #include "../globalLobby/GlobalLobbyClient.h" | ||||
|  | ||||
| #include <SDL_clipboard.h> | ||||
| #include <SDL_events.h> | ||||
| @@ -31,6 +33,8 @@ InputSourceKeyboard::InputSourceKeyboard() | ||||
|  | ||||
| void InputSourceKeyboard::handleEventKeyDown(const SDL_KeyboardEvent & key) | ||||
| { | ||||
| 	assert(key.state == SDL_PRESSED); | ||||
|  | ||||
| 	if (SDL_IsTextInputActive() == SDL_TRUE) | ||||
| 	{ | ||||
| 		if(key.keysym.sym == SDLK_v && isKeyboardCtrlDown())  | ||||
| @@ -51,7 +55,11 @@ void InputSourceKeyboard::handleEventKeyDown(const SDL_KeyboardEvent & key) | ||||
| 			return; // ignore periodic event resends | ||||
| 	} | ||||
|  | ||||
| 	assert(key.state == SDL_PRESSED); | ||||
|  | ||||
| 	if(key.keysym.sym == SDLK_TAB && isKeyboardCtrlDown()) | ||||
| 	{ | ||||
| 		CSH->getGlobalLobby().activateInterface(); | ||||
| 	} | ||||
|  | ||||
| 	if(key.keysym.sym >= SDLK_F1 && key.keysym.sym <= SDLK_F15 && settings["session"]["spectate"].Bool()) | ||||
| 	{ | ||||
|   | ||||
| @@ -59,6 +59,12 @@ void GlobalLobbyClient::onPacketReceived(const std::shared_ptr<INetworkConnectio | ||||
| 	if(json["type"].String() == "activeAccounts") | ||||
| 		return receiveActiveAccounts(json); | ||||
|  | ||||
| 	if(json["type"].String() == "activeGameRooms") | ||||
| 		return receiveActiveGameRooms(json); | ||||
|  | ||||
| 	if(json["type"].String() == "joinRoomSuccess") | ||||
| 		return receiveJoinRoomSuccess(json); | ||||
|  | ||||
| 	throw std::runtime_error("Received unexpected message from lobby server: " + json["type"].String()); | ||||
| } | ||||
|  | ||||
| @@ -140,11 +146,51 @@ void GlobalLobbyClient::receiveChatMessage(const JsonNode & json) | ||||
|  | ||||
| void GlobalLobbyClient::receiveActiveAccounts(const JsonNode & json) | ||||
| { | ||||
| 	//for (auto const & jsonEntry : json["messages"].Vector()) | ||||
| 	//{ | ||||
| 	//	std::string accountID = jsonEntry["accountID"].String(); | ||||
| 	//	std::string displayName = jsonEntry["displayName"].String(); | ||||
| 	//} | ||||
| 	activeAccounts.clear(); | ||||
|  | ||||
| 	for (auto const & jsonEntry : json["accounts"].Vector()) | ||||
| 	{ | ||||
| 		GlobalLobbyAccount account; | ||||
|  | ||||
| 		account.accountID = jsonEntry["accountID"].String(); | ||||
| 		account.displayName = jsonEntry["displayName"].String(); | ||||
| 		account.status = jsonEntry["status"].String(); | ||||
|  | ||||
| 		activeAccounts.push_back(account); | ||||
| 	} | ||||
|  | ||||
| 	auto lobbyWindowPtr = lobbyWindow.lock(); | ||||
| 	if(lobbyWindowPtr) | ||||
| 		lobbyWindowPtr->onActiveAccounts(activeAccounts); | ||||
| } | ||||
|  | ||||
| void GlobalLobbyClient::receiveActiveGameRooms(const JsonNode & json) | ||||
| { | ||||
| 	activeRooms.clear(); | ||||
|  | ||||
| 	for (auto const & jsonEntry : json["gameRooms"].Vector()) | ||||
| 	{ | ||||
| 		GlobalLobbyRoom room; | ||||
|  | ||||
| 		room.gameRoomID = jsonEntry["gameRoomID"].String(); | ||||
| 		room.hostAccountID = jsonEntry["hostAccountID"].String(); | ||||
| 		room.hostAccountDisplayName = jsonEntry["hostAccountDisplayName"].String(); | ||||
| 		room.description = jsonEntry["description"].String(); | ||||
| //		room.status = jsonEntry["status"].String(); | ||||
| 		room.playersCount = jsonEntry["playersCount"].Integer(); | ||||
| 		room.playersLimit = jsonEntry["playersLimit"].Integer(); | ||||
|  | ||||
| 		activeRooms.push_back(room); | ||||
| 	} | ||||
|  | ||||
| 	auto lobbyWindowPtr = lobbyWindow.lock(); | ||||
| 	if(lobbyWindowPtr) | ||||
| 		lobbyWindowPtr->onActiveRooms(activeRooms); | ||||
| } | ||||
|  | ||||
| void GlobalLobbyClient::receiveJoinRoomSuccess(const JsonNode & json) | ||||
| { | ||||
| 	// TODO: store "gameRoomID" field and use it for future queries | ||||
| } | ||||
|  | ||||
| void GlobalLobbyClient::onConnectionEstablished(const std::shared_ptr<INetworkConnection> & connection) | ||||
| @@ -211,6 +257,24 @@ void GlobalLobbyClient::sendMessage(const JsonNode & data) | ||||
| 	networkConnection->sendPacket(payloadBuffer); | ||||
| } | ||||
|  | ||||
| void GlobalLobbyClient::sendOpenPublicRoom() | ||||
| { | ||||
| 	JsonNode toSend; | ||||
| 	toSend["type"].String() = "openGameRoom"; | ||||
| 	toSend["hostAccountID"] = settings["lobby"]["accountID"]; | ||||
| 	toSend["roomType"].String() = "public"; | ||||
| 	sendMessage(toSend); | ||||
| } | ||||
|  | ||||
| void GlobalLobbyClient::sendOpenPrivateRoom() | ||||
| { | ||||
| 	JsonNode toSend; | ||||
| 	toSend["type"].String() = "openGameRoom"; | ||||
| 	toSend["hostAccountID"] = settings["lobby"]["accountID"]; | ||||
| 	toSend["roomType"].String() = "private"; | ||||
| 	sendMessage(toSend); | ||||
| } | ||||
|  | ||||
| void GlobalLobbyClient::connect() | ||||
| { | ||||
| 	std::string hostname = settings["lobby"]["hostname"].String(); | ||||
| @@ -246,3 +310,27 @@ std::shared_ptr<GlobalLobbyWindow> GlobalLobbyClient::createLobbyWindow() | ||||
| 	lobbyWindowLock = lobbyWindowPtr; | ||||
| 	return lobbyWindowPtr; | ||||
| } | ||||
|  | ||||
| const std::vector<GlobalLobbyAccount> & GlobalLobbyClient::getActiveAccounts() const | ||||
| { | ||||
| 	return activeAccounts; | ||||
| } | ||||
|  | ||||
| const std::vector<GlobalLobbyRoom> & GlobalLobbyClient::getActiveRooms() const | ||||
| { | ||||
| 	return activeRooms; | ||||
| } | ||||
|  | ||||
| void GlobalLobbyClient::activateInterface() | ||||
| { | ||||
| 	if (!GH.windows().findWindows<GlobalLobbyWindow>().empty()) | ||||
| 		return; | ||||
|  | ||||
| 	if (!GH.windows().findWindows<GlobalLobbyLoginWindow>().empty()) | ||||
| 		return; | ||||
|  | ||||
| 	if (isConnected()) | ||||
| 		GH.windows().pushWindow(createLobbyWindow()); | ||||
| 	else | ||||
| 		GH.windows().pushWindow(createLoginWindow()); | ||||
| } | ||||
|   | ||||
| @@ -9,6 +9,7 @@ | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "GlobalLobbyDefines.h" | ||||
| #include "../../lib/network/NetworkInterface.h" | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_BEGIN | ||||
| @@ -18,8 +19,11 @@ VCMI_LIB_NAMESPACE_END | ||||
| class GlobalLobbyLoginWindow; | ||||
| class GlobalLobbyWindow; | ||||
|  | ||||
| class GlobalLobbyClient : public INetworkClientListener, boost::noncopyable | ||||
| class GlobalLobbyClient final : public INetworkClientListener, boost::noncopyable | ||||
| { | ||||
| 	std::vector<GlobalLobbyAccount> activeAccounts; | ||||
| 	std::vector<GlobalLobbyRoom> activeRooms; | ||||
|  | ||||
| 	std::shared_ptr<INetworkConnection> networkConnection; | ||||
|  | ||||
| 	std::weak_ptr<GlobalLobbyLoginWindow> loginWindow; | ||||
| @@ -40,14 +44,25 @@ class GlobalLobbyClient : public INetworkClientListener, boost::noncopyable | ||||
| 	void receiveChatHistory(const JsonNode & json); | ||||
| 	void receiveChatMessage(const JsonNode & json); | ||||
| 	void receiveActiveAccounts(const JsonNode & json); | ||||
| 	void receiveActiveGameRooms(const JsonNode & json); | ||||
| 	void receiveJoinRoomSuccess(const JsonNode & json); | ||||
|  | ||||
| 	std::shared_ptr<GlobalLobbyLoginWindow> createLoginWindow(); | ||||
| 	std::shared_ptr<GlobalLobbyWindow> createLobbyWindow(); | ||||
|  | ||||
| public: | ||||
| 	explicit GlobalLobbyClient(); | ||||
| 	~GlobalLobbyClient(); | ||||
|  | ||||
| 	const std::vector<GlobalLobbyAccount> & getActiveAccounts() const; | ||||
| 	const std::vector<GlobalLobbyRoom> & getActiveRooms() const; | ||||
|  | ||||
| 	/// Activate interface and pushes lobby UI as top window | ||||
| 	void activateInterface(); | ||||
| 	void sendMessage(const JsonNode & data); | ||||
| 	void sendOpenPublicRoom(); | ||||
| 	void sendOpenPrivateRoom(); | ||||
|  | ||||
| 	void connect(); | ||||
| 	bool isConnected(); | ||||
| 	std::shared_ptr<GlobalLobbyLoginWindow> createLoginWindow(); | ||||
| 	std::shared_ptr<GlobalLobbyWindow> createLobbyWindow(); | ||||
| }; | ||||
|   | ||||
							
								
								
									
										28
									
								
								client/globalLobby/GlobalLobbyDefines.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								client/globalLobby/GlobalLobbyDefines.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| /* | ||||
|  * GlobalLobbyClient.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 | ||||
|  | ||||
| struct GlobalLobbyAccount | ||||
| { | ||||
| 	std::string accountID; | ||||
| 	std::string displayName; | ||||
| 	std::string status; | ||||
| }; | ||||
|  | ||||
| struct GlobalLobbyRoom | ||||
| { | ||||
| 	std::string gameRoomID; | ||||
| 	std::string hostAccountID; | ||||
| 	std::string hostAccountDisplayName; | ||||
| 	std::string description; | ||||
| //	std::string status; | ||||
| 	int playersCount; | ||||
| 	int playersLimit; | ||||
| }; | ||||
| @@ -74,7 +74,7 @@ void GlobalLobbyLoginWindow::onLogin() | ||||
| void GlobalLobbyLoginWindow::onConnectionSuccess() | ||||
| { | ||||
| 	close(); | ||||
| 	GH.windows().pushWindow(CSH->getGlobalLobby().createLobbyWindow()); | ||||
| 	CSH->getGlobalLobby().activateInterface(); | ||||
| } | ||||
|  | ||||
| void GlobalLobbyLoginWindow::onConnectionFailed(const std::string & reason) | ||||
|   | ||||
| @@ -125,17 +125,15 @@ void GlobalLobbyServerSetup::onGameModeChanged(int value) | ||||
| void GlobalLobbyServerSetup::onCreate() | ||||
| { | ||||
| 	if(toggleGameMode->getSelected() == 0) | ||||
| 	{ | ||||
| 		CSH->resetStateForLobby(StartInfo::NEW_GAME, nullptr); | ||||
| 		CSH->screenType = ESelectionScreen::newGame; | ||||
| 	} | ||||
| 		CSH->resetStateForLobby(EStartMode::NEW_GAME, ESelectionScreen::newGame, {}); | ||||
| 	else | ||||
| 	{ | ||||
| 		CSH->resetStateForLobby(StartInfo::LOAD_GAME, nullptr); | ||||
| 		CSH->screenType = ESelectionScreen::loadGame; | ||||
| 	} | ||||
| 		CSH->resetStateForLobby(EStartMode::LOAD_GAME, ESelectionScreen::loadGame, {}); | ||||
|  | ||||
| 	CSH->loadMode = ELoadMode::MULTI; | ||||
| 	CSH->startLocalServerAndConnect(true); | ||||
|  | ||||
| 	buttonCreate->block(true); | ||||
| 	buttonClose->block(true); | ||||
| } | ||||
|  | ||||
| void GlobalLobbyServerSetup::onClose() | ||||
|   | ||||
| @@ -10,12 +10,19 @@ | ||||
|  | ||||
| #include "StdInc.h" | ||||
| #include "GlobalLobbyWidget.h" | ||||
|  | ||||
| #include "GlobalLobbyClient.h" | ||||
| #include "GlobalLobbyWindow.h" | ||||
|  | ||||
| #include "../CServerHandler.h" | ||||
| #include "../gui/CGuiHandler.h" | ||||
| #include "../gui/WindowHandler.h" | ||||
| #include "../widgets/Buttons.h" | ||||
| #include "../widgets/MiscWidgets.h" | ||||
| #include "../widgets/ObjectLists.h" | ||||
| #include "../widgets/TextControls.h" | ||||
|  | ||||
| #include "../../lib/MetaString.h" | ||||
| GlobalLobbyWidget::GlobalLobbyWidget(GlobalLobbyWindow * window) | ||||
| 	: window(window) | ||||
| { | ||||
| @@ -23,10 +30,59 @@ GlobalLobbyWidget::GlobalLobbyWidget(GlobalLobbyWindow * window) | ||||
| 	addCallback("sendMessage", [this](int) { this->window->doSendChatMessage(); }); | ||||
| 	addCallback("createGameRoom", [this](int) { this->window->doCreateGameRoom(); }); | ||||
|  | ||||
| 	REGISTER_BUILDER("accountList", &GlobalLobbyWidget::buildAccountList); | ||||
| 	REGISTER_BUILDER("roomList", &GlobalLobbyWidget::buildRoomList); | ||||
|  | ||||
| 	const JsonNode config(JsonPath::builtin("config/widgets/lobbyWindow.json")); | ||||
| 	build(config); | ||||
| } | ||||
|  | ||||
| std::shared_ptr<CIntObject> GlobalLobbyWidget::buildAccountList(const JsonNode & config) const | ||||
| { | ||||
| 	const auto & createCallback = [this](size_t index) -> std::shared_ptr<CIntObject> | ||||
| 	{ | ||||
| 		const auto & accounts = CSH->getGlobalLobby().getActiveAccounts(); | ||||
|  | ||||
| 		if(index < accounts.size()) | ||||
| 			return std::make_shared<GlobalLobbyAccountCard>(this->window, accounts[index]); | ||||
| 		return std::make_shared<CIntObject>(); | ||||
| 	}; | ||||
|  | ||||
| 	auto position = readPosition(config["position"]); | ||||
| 	auto itemOffset = readPosition(config["itemOffset"]); | ||||
| 	auto sliderPosition = readPosition(config["sliderPosition"]); | ||||
| 	auto sliderSize = readPosition(config["sliderSize"]); | ||||
| 	size_t visibleSize = 4; // FIXME: how many items can fit into UI? | ||||
| 	size_t totalSize = 4; //FIXME: how many items are there in total | ||||
| 	int sliderMode = 1 | 4; //  present, vertical, blue | ||||
| 	int initialPos = 0; | ||||
|  | ||||
| 	return std::make_shared<CListBox>(createCallback, position, itemOffset, visibleSize, totalSize, initialPos, sliderMode, Rect(sliderPosition, sliderSize) ); | ||||
| } | ||||
|  | ||||
| std::shared_ptr<CIntObject> GlobalLobbyWidget::buildRoomList(const JsonNode & config) const | ||||
| { | ||||
| 	const auto & createCallback = [this](size_t index) -> std::shared_ptr<CIntObject> | ||||
| 	{ | ||||
| 		const auto & rooms = CSH->getGlobalLobby().getActiveRooms(); | ||||
|  | ||||
| 		if(index < rooms.size()) | ||||
| 			return std::make_shared<GlobalLobbyRoomCard>(this->window, rooms[index]); | ||||
| 		return std::make_shared<CIntObject>(); | ||||
| 	}; | ||||
|  | ||||
| 	auto position = readPosition(config["position"]); | ||||
| 	auto itemOffset = readPosition(config["itemOffset"]); | ||||
| 	auto sliderPosition = readPosition(config["sliderPosition"]); | ||||
| 	auto sliderSize = readPosition(config["sliderSize"]); | ||||
| 	size_t visibleSize = 4; // FIXME: how many items can fit into UI? | ||||
| 	size_t totalSize = 4; //FIXME: how many items are there in total | ||||
| 	int sliderMode = 1 | 4; //  present, vertical, blue | ||||
| 	int initialPos = 0; | ||||
|  | ||||
| 	return std::make_shared<CListBox>(createCallback, position, itemOffset, visibleSize, totalSize, initialPos, sliderMode, Rect(sliderPosition, sliderSize) ); | ||||
| } | ||||
|  | ||||
| std::shared_ptr<CLabel> GlobalLobbyWidget::getAccountNameLabel() | ||||
| { | ||||
| 	return widget<CLabel>("accountNameLabel"); | ||||
| @@ -41,3 +97,54 @@ std::shared_ptr<CTextBox> GlobalLobbyWidget::getGameChat() | ||||
| { | ||||
| 	return widget<CTextBox>("gameChat"); | ||||
| } | ||||
|  | ||||
| std::shared_ptr<CListBox> GlobalLobbyWidget::getAccountList() | ||||
| { | ||||
| 	return widget<CListBox>("accountList"); | ||||
| } | ||||
|  | ||||
| std::shared_ptr<CListBox> GlobalLobbyWidget::getRoomList() | ||||
| { | ||||
| 	return widget<CListBox>("roomList"); | ||||
| } | ||||
|  | ||||
| GlobalLobbyAccountCard::GlobalLobbyAccountCard(GlobalLobbyWindow * window, const GlobalLobbyAccount & accountDescription) | ||||
| { | ||||
| 	OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE; | ||||
|  | ||||
| 	const auto & onInviteClicked = [window, accountID=accountDescription.accountID]() | ||||
| 	{ | ||||
| 		window->doInviteAccount(accountID); | ||||
| 	}; | ||||
|  | ||||
| 	pos.w = 130; | ||||
| 	pos.h = 40; | ||||
|  | ||||
| 	backgroundOverlay = std::make_shared<TransparentFilledRectangle>(Rect(0, 0, pos.w, pos.h), ColorRGBA(0,0,0,128), ColorRGBA(64,64,64,64)); | ||||
| 	labelName = std::make_shared<CLabel>( 5, 2, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, accountDescription.displayName); | ||||
| 	labelStatus = std::make_shared<CLabel>( 5, 20, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::YELLOW, accountDescription.status); | ||||
| 	buttonInvite = std::make_shared<CButton>(Point(95, 8), AnimationPath::builtin("settingsWindow/button32"), CButton::tooltip(), onInviteClicked); | ||||
| } | ||||
|  | ||||
| GlobalLobbyRoomCard::GlobalLobbyRoomCard(GlobalLobbyWindow * window, const GlobalLobbyRoom & roomDescription) | ||||
| { | ||||
| 	OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE; | ||||
|  | ||||
| 	const auto & onJoinClicked = [window, roomID=roomDescription.gameRoomID]() | ||||
| 	{ | ||||
| 		window->doJoinRoom(roomID); | ||||
| 	}; | ||||
|  | ||||
| 	auto roomSizeText = MetaString::createFromRawString("%d/%d"); | ||||
| 	roomSizeText.replaceNumber(roomDescription.playersCount); | ||||
| 	roomSizeText.replaceNumber(roomDescription.playersLimit); | ||||
|  | ||||
| 	pos.w = 230; | ||||
| 	pos.h = 40; | ||||
|  | ||||
| 	backgroundOverlay = std::make_shared<TransparentFilledRectangle>(Rect(0, 0, pos.w, pos.h), ColorRGBA(0,0,0,128), ColorRGBA(64,64,64,64)); | ||||
| 	labelName = std::make_shared<CLabel>( 5, 2, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, roomDescription.hostAccountDisplayName); | ||||
| 	labelStatus = std::make_shared<CLabel>( 5, 20, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::YELLOW, roomDescription.description); | ||||
| 	labelRoomSize = std::make_shared<CLabel>( 160, 2, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::YELLOW, roomSizeText.toString()); | ||||
| 	buttonJoin = std::make_shared<CButton>(Point(195, 8), AnimationPath::builtin("settingsWindow/button32"), CButton::tooltip(), onJoinClicked); | ||||
| } | ||||
|   | ||||
| @@ -12,15 +12,50 @@ | ||||
| #include "../gui/InterfaceObjectConfigurable.h" | ||||
|  | ||||
| class GlobalLobbyWindow; | ||||
| struct GlobalLobbyAccount; | ||||
| struct GlobalLobbyRoom; | ||||
| class CListBox; | ||||
|  | ||||
| class GlobalLobbyWidget : public InterfaceObjectConfigurable | ||||
| { | ||||
| 	GlobalLobbyWindow * window; | ||||
|  | ||||
| 	std::shared_ptr<CIntObject> buildAccountList(const JsonNode &) const; | ||||
| 	std::shared_ptr<CIntObject> buildRoomList(const JsonNode &) const; | ||||
|  | ||||
| public: | ||||
| 	GlobalLobbyWidget(GlobalLobbyWindow * window); | ||||
|  | ||||
| 	std::shared_ptr<CLabel> getAccountNameLabel(); | ||||
| 	std::shared_ptr<CTextInput> getMessageInput(); | ||||
| 	std::shared_ptr<CTextBox> getGameChat(); | ||||
| 	std::shared_ptr<CListBox> getAccountList(); | ||||
| 	std::shared_ptr<CListBox> getRoomList(); | ||||
| }; | ||||
|  | ||||
| class GlobalLobbyAccountCard : public CIntObject | ||||
| { | ||||
| public: | ||||
| 	GlobalLobbyAccountCard(GlobalLobbyWindow * window, const GlobalLobbyAccount & accountDescription); | ||||
|  | ||||
| 	GlobalLobbyWindow * window; | ||||
|  | ||||
| 	std::shared_ptr<TransparentFilledRectangle> backgroundOverlay; | ||||
| 	std::shared_ptr<CLabel> labelName; | ||||
| 	std::shared_ptr<CLabel> labelStatus; | ||||
| 	std::shared_ptr<CButton> buttonInvite; | ||||
| }; | ||||
|  | ||||
| class GlobalLobbyRoomCard : public CIntObject | ||||
| { | ||||
| public: | ||||
| 	GlobalLobbyRoomCard(GlobalLobbyWindow * window, const GlobalLobbyRoom & roomDescription); | ||||
|  | ||||
| 	GlobalLobbyWindow * window; | ||||
|  | ||||
| 	std::shared_ptr<TransparentFilledRectangle> backgroundOverlay; | ||||
| 	std::shared_ptr<CLabel> labelName; | ||||
| 	std::shared_ptr<CLabel> labelRoomSize; | ||||
| 	std::shared_ptr<CLabel> labelStatus; | ||||
| 	std::shared_ptr<CButton> buttonJoin; | ||||
| }; | ||||
|   | ||||
| @@ -19,6 +19,7 @@ | ||||
| #include "../gui/CGuiHandler.h" | ||||
| #include "../gui/WindowHandler.h" | ||||
| #include "../widgets/TextControls.h" | ||||
| #include "../widgets/ObjectLists.h" | ||||
|  | ||||
| #include "../../lib/CConfigHandler.h" | ||||
| #include "../../lib/MetaString.h" | ||||
| @@ -59,6 +60,16 @@ void GlobalLobbyWindow::doCreateGameRoom() | ||||
| 	// client requests to change room status to private or public | ||||
| } | ||||
|  | ||||
| void GlobalLobbyWindow::doInviteAccount(const std::string & accountID) | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| void GlobalLobbyWindow::doJoinRoom(const std::string & roomID) | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| void GlobalLobbyWindow::onGameChatMessage(const std::string & sender, const std::string & message, const std::string & when) | ||||
| { | ||||
| 	MetaString chatMessageFormatted; | ||||
| @@ -71,3 +82,13 @@ void GlobalLobbyWindow::onGameChatMessage(const std::string & sender, const std: | ||||
|  | ||||
| 	widget->getGameChat()->setText(chatHistory); | ||||
| } | ||||
|  | ||||
| void GlobalLobbyWindow::onActiveAccounts(const std::vector<GlobalLobbyAccount> & accounts) | ||||
| { | ||||
| 	widget->getAccountList()->reset(); | ||||
| } | ||||
|  | ||||
| void GlobalLobbyWindow::onActiveRooms(const std::vector<GlobalLobbyRoom> & rooms) | ||||
| { | ||||
| 	widget->getRoomList()->reset(); | ||||
| } | ||||
|   | ||||
| @@ -12,6 +12,8 @@ | ||||
| #include "../windows/CWindowObject.h" | ||||
|  | ||||
| class GlobalLobbyWidget; | ||||
| struct GlobalLobbyAccount; | ||||
| struct GlobalLobbyRoom; | ||||
|  | ||||
| class GlobalLobbyWindow : public CWindowObject | ||||
| { | ||||
| @@ -25,5 +27,10 @@ public: | ||||
| 	void doSendChatMessage(); | ||||
| 	void doCreateGameRoom(); | ||||
|  | ||||
| 	void doInviteAccount(const std::string & accountID); | ||||
| 	void doJoinRoom(const std::string & roomID); | ||||
|  | ||||
| 	void onGameChatMessage(const std::string & sender, const std::string & message, const std::string & when); | ||||
| 	void onActiveAccounts(const std::vector<GlobalLobbyAccount> & accounts); | ||||
| 	void onActiveRooms(const std::vector<GlobalLobbyRoom> & rooms); | ||||
| }; | ||||
|   | ||||
| @@ -768,7 +768,7 @@ void SelectionTab::parseSaves(const std::unordered_set<ResourcePath> & files) | ||||
| 			mapInfo->saveInit(file); | ||||
|  | ||||
| 			// Filter out other game modes | ||||
| 			bool isCampaign = mapInfo->scenarioOptionsOfSave->mode == StartInfo::CAMPAIGN; | ||||
| 			bool isCampaign = mapInfo->scenarioOptionsOfSave->mode == EStartMode::CAMPAIGN; | ||||
| 			bool isMultiplayer = mapInfo->amountOfHumanPlayersInSave > 1; | ||||
| 			bool isTutorial = boost::to_upper_copy(mapInfo->scenarioOptionsOfSave->mapname) == "MAPS/TUTORIAL"; | ||||
| 			switch(CSH->getLoadMode()) | ||||
|   | ||||
| @@ -187,11 +187,11 @@ static std::function<void()> genCommand(CMenuScreen * menu, std::vector<std::str | ||||
| 				switch(std::find(gameType.begin(), gameType.end(), commands.front()) - gameType.begin()) | ||||
| 				{ | ||||
| 				case 0: | ||||
| 					return std::bind(CMainMenu::openLobby, ESelectionScreen::newGame, true, nullptr, ELoadMode::NONE); | ||||
| 					return []() { CMainMenu::openLobby(ESelectionScreen::newGame, true, {}, ELoadMode::NONE);}; | ||||
| 				case 1: | ||||
| 					return []() { GH.windows().createAndPushWindow<CMultiMode>(ESelectionScreen::newGame); }; | ||||
| 				case 2: | ||||
| 					return std::bind(CMainMenu::openLobby, ESelectionScreen::campaignList, true, nullptr, ELoadMode::NONE); | ||||
| 					return []() { CMainMenu::openLobby(ESelectionScreen::campaignList, true, {}, ELoadMode::NONE);}; | ||||
| 				case 3: | ||||
| 					return std::bind(CMainMenu::startTutorial); | ||||
| 				} | ||||
| @@ -202,13 +202,14 @@ static std::function<void()> genCommand(CMenuScreen * menu, std::vector<std::str | ||||
| 				switch(std::find(gameType.begin(), gameType.end(), commands.front()) - gameType.begin()) | ||||
| 				{ | ||||
| 				case 0: | ||||
| 					return std::bind(CMainMenu::openLobby, ESelectionScreen::loadGame, true, nullptr, ELoadMode::SINGLE); | ||||
| 					return []() { CMainMenu::openLobby(ESelectionScreen::loadGame, true, {}, ELoadMode::SINGLE);}; | ||||
| 				case 1: | ||||
| 					return []() { GH.windows().createAndPushWindow<CMultiMode>(ESelectionScreen::loadGame); }; | ||||
| 				case 2: | ||||
| 					return std::bind(CMainMenu::openLobby, ESelectionScreen::loadGame, true, nullptr, ELoadMode::CAMPAIGN); | ||||
| 					return []() { CMainMenu::openLobby(ESelectionScreen::loadGame, true, {}, ELoadMode::CAMPAIGN);}; | ||||
| 				case 3: | ||||
| 					return std::bind(CMainMenu::openLobby, ESelectionScreen::loadGame, true, nullptr, ELoadMode::TUTORIAL); | ||||
| 					return []() { CMainMenu::openLobby(ESelectionScreen::loadGame, true, {}, ELoadMode::TUTORIAL);}; | ||||
|  | ||||
| 				} | ||||
| 			} | ||||
| 			break; | ||||
| @@ -358,10 +359,9 @@ void CMainMenu::update() | ||||
| 	GH.windows().simpleRedraw(); | ||||
| } | ||||
|  | ||||
| void CMainMenu::openLobby(ESelectionScreen screenType, bool host, const std::vector<std::string> * names, ELoadMode loadMode) | ||||
| void CMainMenu::openLobby(ESelectionScreen screenType, bool host, const std::vector<std::string> & names, ELoadMode loadMode) | ||||
| { | ||||
| 	CSH->resetStateForLobby(screenType == ESelectionScreen::newGame ? StartInfo::NEW_GAME : StartInfo::LOAD_GAME, names); | ||||
| 	CSH->screenType = screenType; | ||||
| 	CSH->resetStateForLobby(screenType == ESelectionScreen::newGame ? EStartMode::NEW_GAME : EStartMode::LOAD_GAME, screenType, names); | ||||
| 	CSH->loadMode = loadMode; | ||||
|  | ||||
| 	GH.windows().createAndPushWindow<CSimpleJoinScreen>(host); | ||||
| @@ -376,8 +376,7 @@ void CMainMenu::openCampaignLobby(const std::string & campaignFileName, std::str | ||||
|  | ||||
| void CMainMenu::openCampaignLobby(std::shared_ptr<CampaignState> campaign) | ||||
| { | ||||
| 	CSH->resetStateForLobby(StartInfo::CAMPAIGN); | ||||
| 	CSH->screenType = ESelectionScreen::campaignList; | ||||
| 	CSH->resetStateForLobby(EStartMode::CAMPAIGN, ESelectionScreen::campaignList, {}); | ||||
| 	CSH->campaignStateToSend = campaign; | ||||
| 	GH.windows().createAndPushWindow<CSimpleJoinScreen>(); | ||||
| } | ||||
| @@ -420,7 +419,7 @@ void CMainMenu::startTutorial() | ||||
| 		 | ||||
| 	auto mapInfo = std::make_shared<CMapInfo>(); | ||||
| 	mapInfo->mapInit(tutorialMap.getName()); | ||||
| 	CMainMenu::openLobby(ESelectionScreen::newGame, true, nullptr, ELoadMode::NONE); | ||||
| 	CMainMenu::openLobby(ESelectionScreen::newGame, true, {}, ELoadMode::NONE); | ||||
| 	CSH->startMapAfterConnection(mapInfo); | ||||
| } | ||||
|  | ||||
| @@ -470,10 +469,7 @@ CMultiMode::CMultiMode(ESelectionScreen ScreenType) | ||||
| void CMultiMode::openLobby() | ||||
| { | ||||
| 	close(); | ||||
| 	if (CSH->getGlobalLobby().isConnected()) | ||||
| 		GH.windows().pushWindow(CSH->getGlobalLobby().createLobbyWindow()); | ||||
| 	else | ||||
| 		GH.windows().pushWindow(CSH->getGlobalLobby().createLoginWindow()); | ||||
| 	CSH->getGlobalLobby().activateInterface(); | ||||
| } | ||||
|  | ||||
| void CMultiMode::hostTCP() | ||||
| @@ -547,7 +543,7 @@ void CMultiPlayers::enterSelectionScreen() | ||||
| 	Settings name = settings.write["general"]["playerName"]; | ||||
| 	name->String() = names[0]; | ||||
|  | ||||
| 	CMainMenu::openLobby(screenType, host, &names, loadMode); | ||||
| 	CMainMenu::openLobby(screenType, host, names, loadMode); | ||||
| } | ||||
|  | ||||
| CSimpleJoinScreen::CSimpleJoinScreen(bool host) | ||||
|   | ||||
| @@ -31,11 +31,11 @@ class CLabel; | ||||
|  | ||||
|  | ||||
| // TODO: Find new location for these enums | ||||
| enum ESelectionScreen : ui8 { | ||||
| enum class ESelectionScreen : ui8 { | ||||
| 	unknown = 0, newGame, loadGame, saveGame, scenarioInfo, campaignList | ||||
| }; | ||||
|  | ||||
| enum ELoadMode : ui8 | ||||
| enum class ELoadMode : ui8 | ||||
| { | ||||
| 	NONE = 0, SINGLE, MULTI, CAMPAIGN, TUTORIAL | ||||
| }; | ||||
| @@ -150,7 +150,7 @@ public: | ||||
| 	void activate() override; | ||||
| 	void onScreenResize() override; | ||||
| 	void update() override; | ||||
| 	static void openLobby(ESelectionScreen screenType, bool host, const std::vector<std::string> * names, ELoadMode loadMode); | ||||
| 	static void openLobby(ESelectionScreen screenType, bool host, const std::vector<std::string> & names, ELoadMode loadMode); | ||||
| 	static void openCampaignLobby(const std::string & campaignFileName, std::string campaignSet = ""); | ||||
| 	static void openCampaignLobby(std::shared_ptr<CampaignState> campaign); | ||||
| 	static void startTutorial(); | ||||
|   | ||||
| @@ -24,7 +24,7 @@ class CTextBox; | ||||
| class IImage; | ||||
| class Canvas; | ||||
| class TransparentFilledRectangle; | ||||
| enum ESelectionScreen : ui8; | ||||
| enum class ESelectionScreen : ui8; | ||||
|  | ||||
| class CMapOverview; | ||||
|  | ||||
|   | ||||
| @@ -45,25 +45,23 @@ | ||||
| 			"type": "labelTitleMain", | ||||
| 			"position": {"x": 15, "y": 10} | ||||
| 		}, | ||||
| 		 | ||||
|  | ||||
| 		{ | ||||
| 			"type": "areaFilled", | ||||
| 			"rect": {"x": 5, "y": 50, "w": 250, "h": 150} | ||||
| 			"rect": {"x": 5, "y": 50, "w": 250, "h": 500} | ||||
| 		}, | ||||
| 		{ | ||||
| 			"type": "labelTitle", | ||||
| 			"position": {"x": 15, "y": 53}, | ||||
| 			"text" : "Match Filter" | ||||
| 		}, | ||||
|  | ||||
| 		{ | ||||
| 			"type": "areaFilled", | ||||
| 			"rect": {"x": 5, "y": 210, "w": 250, "h": 340} | ||||
| 			"text" : "Room List" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"type": "labelTitle", | ||||
| 			"position": {"x": 15, "y": 213}, | ||||
| 			"text" : "Match List" | ||||
| 			"type" : "roomList", | ||||
| 			"name" : "roomList", | ||||
| 			"position" : { "x" : 7, "y" : 69 }, | ||||
| 			"itemOffset" : { "x" : 0, "y" : 40 }, | ||||
| 			"sliderPosition" : { "x" : 230, "y" : 0 }, | ||||
| 			"sliderSize" : { "x" : 450, "y" : 450 } | ||||
| 		}, | ||||
| 		 | ||||
| 		{ | ||||
| @@ -112,9 +110,17 @@ | ||||
| 		{ | ||||
| 			"type": "labelTitle", | ||||
| 			"position": {"x": 880, "y": 53}, | ||||
| 			"text" : "Player List" | ||||
| 			"text" : "Account List" | ||||
| 		}, | ||||
| 		 | ||||
| 		{ | ||||
| 			"type" : "accountList", | ||||
| 			"name" : "accountList", | ||||
| 			"position" : { "x" : 872, "y" : 69 }, | ||||
| 			"itemOffset" : { "x" : 0, "y" : 40 }, | ||||
| 			"sliderPosition" : { "x" : 130, "y" : 0 }, | ||||
| 			"sliderSize" : { "x" : 520, "y" : 520 } | ||||
| 		}, | ||||
|  | ||||
| 		{ | ||||
| 			"type": "button", | ||||
| 			"position": {"x": 840, "y": 10}, | ||||
|   | ||||
| @@ -111,7 +111,7 @@ void LobbyInfo::verifyStateBeforeStart(bool ignoreNoHuman) const | ||||
| 	if(i == si->playerInfos.cend() && !ignoreNoHuman) | ||||
| 		throw std::domain_error(VLC->generaltexth->translate("core.genrltxt.530")); | ||||
|  | ||||
| 	if(si->mapGenOptions && si->mode == StartInfo::NEW_GAME) | ||||
| 	if(si->mapGenOptions && si->mode == EStartMode::NEW_GAME) | ||||
| 	{ | ||||
| 		if(!si->mapGenOptions->checkOptions()) | ||||
| 			throw std::domain_error(VLC->generaltexth->translate("core.genrltxt.751")); | ||||
|   | ||||
| @@ -98,12 +98,18 @@ struct DLL_LINKAGE PlayerSettings | ||||
| 	HeroTypeID getHeroValidated() const; | ||||
| }; | ||||
|  | ||||
| enum class EStartMode : int32_t | ||||
| { | ||||
| 	NEW_GAME, | ||||
| 	LOAD_GAME, | ||||
| 	CAMPAIGN, | ||||
| 	INVALID = 255 | ||||
| }; | ||||
|  | ||||
| /// Struct which describes the difficulty, the turn time,.. of a heroes match. | ||||
| struct DLL_LINKAGE StartInfo | ||||
| { | ||||
| 	enum EMode {NEW_GAME, LOAD_GAME, CAMPAIGN, INVALID = 255}; | ||||
|  | ||||
| 	EMode mode; | ||||
| 	EStartMode mode; | ||||
| 	ui8 difficulty; //0=easy; 4=impossible | ||||
|  | ||||
| 	using TPlayerInfos = std::map<PlayerColor, PlayerSettings>; | ||||
| @@ -152,7 +158,7 @@ struct DLL_LINKAGE StartInfo | ||||
| 		h & campState; | ||||
| 	} | ||||
|  | ||||
| 	StartInfo() : mode(INVALID), difficulty(1), seedToBeUsed(0), seedPostInit(0), | ||||
| 	StartInfo() : mode(EStartMode::INVALID), difficulty(1), seedToBeUsed(0), seedPostInit(0), | ||||
| 		mapfileChecksum(0), startTimeIso8601(vstd::getDateTimeISO8601Basic(std::time(nullptr))), fileURI("") | ||||
| 	{ | ||||
|  | ||||
|   | ||||
| @@ -189,10 +189,10 @@ void CGameState::init(const IMapService * mapService, StartInfo * si, Load::Prog | ||||
|  | ||||
| 	switch(scenarioOps->mode) | ||||
| 	{ | ||||
| 	case StartInfo::NEW_GAME: | ||||
| 	case EStartMode::NEW_GAME: | ||||
| 		initNewGame(mapService, allowSavingRandomMap, progressTracking); | ||||
| 		break; | ||||
| 	case StartInfo::CAMPAIGN: | ||||
| 	case EStartMode::CAMPAIGN: | ||||
| 		initCampaign(); | ||||
| 		break; | ||||
| 	default: | ||||
| @@ -711,7 +711,7 @@ void CGameState::initFogOfWar() | ||||
|  | ||||
| void CGameState::initStartingBonus() | ||||
| { | ||||
| 	if (scenarioOps->mode == StartInfo::CAMPAIGN) | ||||
| 	if (scenarioOps->mode == EStartMode::CAMPAIGN) | ||||
| 		return; | ||||
| 	// These are the single scenario bonuses; predefined | ||||
| 	// campaign bonuses are spread out over other init* functions. | ||||
|   | ||||
| @@ -39,7 +39,7 @@ CampaignHeroReplacement::CampaignHeroReplacement(CGHeroInstance * hero, const Ob | ||||
| CGameStateCampaign::CGameStateCampaign(CGameState * owner): | ||||
| 	gameState(owner) | ||||
| { | ||||
| 	assert(gameState->scenarioOps->mode == StartInfo::CAMPAIGN); | ||||
| 	assert(gameState->scenarioOps->mode == EStartMode::CAMPAIGN); | ||||
| 	assert(gameState->scenarioOps->campState != nullptr); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -95,7 +95,10 @@ void NetworkConnection::sendPacket(const std::vector<uint8_t> & message) | ||||
| 	ostream.write(reinterpret_cast<const char *>(&messageSize), messageHeaderSize); | ||||
| 	ostream.write(reinterpret_cast<const char *>(message.data()), message.size()); | ||||
|  | ||||
| 	boost::asio::write(*socket, writeBuffer ); | ||||
| 	boost::system::error_code ec; | ||||
| 	boost::asio::write(*socket, writeBuffer, ec ); | ||||
|  | ||||
| 	// FIXME: handle error? | ||||
| } | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_END | ||||
|   | ||||
| @@ -37,7 +37,7 @@ struct DLL_LINKAGE LobbyClientConnected : public CLobbyPackToPropagate | ||||
| 	// Set by client before sending pack to server | ||||
| 	std::string uuid; | ||||
| 	std::vector<std::string> names; | ||||
| 	StartInfo::EMode mode = StartInfo::INVALID; | ||||
| 	EStartMode mode = EStartMode::INVALID; | ||||
| 	// Changed by server before announcing pack | ||||
| 	int clientId = -1; | ||||
| 	int hostClientId = -1; | ||||
|   | ||||
| @@ -106,6 +106,11 @@ bool CConnection::isMyConnection(const std::shared_ptr<INetworkConnection> & oth | ||||
| 	return otherConnection != nullptr && networkConnection.lock() == otherConnection; | ||||
| } | ||||
|  | ||||
| std::shared_ptr<INetworkConnection> CConnection::getConnection() | ||||
| { | ||||
| 	return networkConnection.lock(); | ||||
| } | ||||
|  | ||||
| void CConnection::disableStackSendingByID() | ||||
| { | ||||
| 	packReader->sendStackInstanceByIds = false; | ||||
|   | ||||
| @@ -41,6 +41,7 @@ class DLL_LINKAGE CConnection : boost::noncopyable | ||||
|  | ||||
| public: | ||||
| 	bool isMyConnection(const std::shared_ptr<INetworkConnection> & otherConnection) const; | ||||
| 	std::shared_ptr<INetworkConnection> getConnection(); | ||||
|  | ||||
| 	std::string uuid; | ||||
| 	int connectionID; | ||||
|   | ||||
| @@ -96,7 +96,7 @@ void LobbyDatabase::prepareStatements() | ||||
| 	)"; | ||||
|  | ||||
| 	static const std::string insertGameRoomText = R"( | ||||
| 		INSERT INTO gameRooms(roomID, hostAccountID, status, playerLimit) VALUES(?, ?, 'empty', 8); | ||||
| 		INSERT INTO gameRooms(roomID, hostAccountID, status, playerLimit) VALUES(?, ?, 0, 8); | ||||
| 	)"; | ||||
|  | ||||
| 	static const std::string insertGameRoomPlayersText = R"( | ||||
| @@ -119,6 +119,12 @@ void LobbyDatabase::prepareStatements() | ||||
|  | ||||
| 	// UPDATE | ||||
|  | ||||
| 	static const std::string setAccountOnlineText = R"( | ||||
| 		UPDATE accounts | ||||
| 		SET online = ? | ||||
| 		WHERE accountID = ? | ||||
| 	)"; | ||||
|  | ||||
| 	static const std::string setGameRoomStatusText = R"( | ||||
| 		UPDATE gameRooms | ||||
| 		SET status = ? | ||||
| @@ -145,7 +151,7 @@ void LobbyDatabase::prepareStatements() | ||||
| 	static const std::string getIdleGameRoomText = R"( | ||||
| 		SELECT roomID | ||||
| 		FROM gameRooms | ||||
| 		WHERE hostAccountID = ? AND status = 'idle' | ||||
| 		WHERE hostAccountID = ? AND status = 0 | ||||
| 		LIMIT 1 | ||||
| 	)"; | ||||
|  | ||||
| @@ -153,7 +159,7 @@ void LobbyDatabase::prepareStatements() | ||||
| 		SELECT grp.roomID | ||||
| 		FROM gameRoomPlayers grp | ||||
| 		LEFT JOIN gameRooms gr ON gr.roomID = grp.roomID | ||||
| 		WHERE accountID = ? AND status IN ('public', 'private', 'busy') | ||||
| 		WHERE accountID = ? AND status IN (1, 2) | ||||
| 		LIMIT 1 | ||||
| 	)"; | ||||
|  | ||||
| @@ -163,6 +169,13 @@ void LobbyDatabase::prepareStatements() | ||||
| 		WHERE online = 1 | ||||
| 	)"; | ||||
|  | ||||
| 	static const std::string getActiveGameRoomsText = R"( | ||||
| 		SELECT roomID, hostAccountID, displayName, status, 0, playerLimit | ||||
| 		FROM gameRooms | ||||
| 		LEFT JOIN accounts ON hostAccountID = accountID | ||||
| 		WHERE status = 1 | ||||
| 	)"; | ||||
|  | ||||
| 	static const std::string getAccountDisplayNameText = R"( | ||||
| 		SELECT displayName | ||||
| 		FROM accounts | ||||
| @@ -216,6 +229,7 @@ void LobbyDatabase::prepareStatements() | ||||
| 	deleteGameRoomPlayersStatement = database->prepare(deleteGameRoomPlayersText); | ||||
| 	deleteGameRoomInvitesStatement = database->prepare(deleteGameRoomInvitesText); | ||||
|  | ||||
| 	setAccountOnlineStatement = database->prepare(setAccountOnlineText); | ||||
| 	setGameRoomStatusStatement = database->prepare(setGameRoomStatusText); | ||||
| 	setGameRoomPlayerLimitStatement = database->prepare(setGameRoomPlayerLimitText); | ||||
|  | ||||
| @@ -223,6 +237,7 @@ void LobbyDatabase::prepareStatements() | ||||
| 	getIdleGameRoomStatement = database->prepare(getIdleGameRoomText); | ||||
| 	getAccountGameRoomStatement = database->prepare(getAccountGameRoomText); | ||||
| 	getActiveAccountsStatement = database->prepare(getActiveAccountsText); | ||||
| 	getActiveGameRoomsStatement = database->prepare(getActiveGameRoomsText); | ||||
| 	getAccountDisplayNameStatement = database->prepare(getAccountDisplayNameText); | ||||
|  | ||||
| 	isAccountCookieValidStatement = database->prepare(isAccountCookieValidText); | ||||
| @@ -285,6 +300,11 @@ std::vector<LobbyChatMessage> LobbyDatabase::getRecentMessageHistory() | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| void LobbyDatabase::setAccountOnline(const std::string & accountID, bool isOnline) | ||||
| { | ||||
| 	setAccountOnlineStatement->executeOnce(isOnline ? 1 : 0, accountID); | ||||
| } | ||||
|  | ||||
| void LobbyDatabase::setGameRoomStatus(const std::string & roomID, LobbyRoomState roomStatus) | ||||
| { | ||||
| 	setGameRoomStatusStatement->executeOnce(vstd::to_underlying(roomStatus), roomID); | ||||
| @@ -404,7 +424,16 @@ bool LobbyDatabase::isAccountIDExists(const std::string & accountID) | ||||
|  | ||||
| std::vector<LobbyGameRoom> LobbyDatabase::getActiveGameRooms() | ||||
| { | ||||
| 	return {}; | ||||
| 	std::vector<LobbyGameRoom> result; | ||||
|  | ||||
| 	while(getActiveGameRoomsStatement->execute()) | ||||
| 	{ | ||||
| 		LobbyGameRoom entry; | ||||
| 		getActiveGameRoomsStatement->getColumns(entry.roomID, entry.hostAccountID, entry.hostAccountDisplayName, entry.roomStatus, entry.playersCount, entry.playersLimit); | ||||
| 		result.push_back(entry); | ||||
| 	} | ||||
| 	getActiveGameRoomsStatement->reset(); | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| std::vector<LobbyAccount> LobbyDatabase::getActiveAccounts() | ||||
| @@ -425,6 +454,7 @@ std::string LobbyDatabase::getIdleGameRoom(const std::string & hostAccountID) | ||||
| { | ||||
| 	std::string result; | ||||
|  | ||||
| 	getIdleGameRoomStatement->setBinds(hostAccountID); | ||||
| 	if(getIdleGameRoomStatement->execute()) | ||||
| 		getIdleGameRoomStatement->getColumns(result); | ||||
|  | ||||
| @@ -436,6 +466,7 @@ std::string LobbyDatabase::getAccountGameRoom(const std::string & accountID) | ||||
| { | ||||
| 	std::string result; | ||||
|  | ||||
| 	getAccountGameRoomStatement->setBinds(accountID); | ||||
| 	if(getAccountGameRoomStatement->execute()) | ||||
| 		getAccountGameRoomStatement->getColumns(result); | ||||
|  | ||||
|   | ||||
| @@ -31,13 +31,15 @@ class LobbyDatabase | ||||
| 	SQLiteStatementPtr deleteGameRoomPlayersStatement; | ||||
| 	SQLiteStatementPtr deleteGameRoomInvitesStatement; | ||||
|  | ||||
| 	SQLiteStatementPtr setAccountOnlineStatement; | ||||
| 	SQLiteStatementPtr setGameRoomStatusStatement; | ||||
| 	SQLiteStatementPtr setGameRoomPlayerLimitStatement; | ||||
|  | ||||
| 	SQLiteStatementPtr getRecentMessageHistoryStatement; | ||||
| 	SQLiteStatementPtr getIdleGameRoomStatement; | ||||
| 	SQLiteStatementPtr getAccountGameRoomStatement; | ||||
| 	SQLiteStatementPtr getActiveGameRoomsStatement; | ||||
| 	SQLiteStatementPtr getActiveAccountsStatement; | ||||
| 	SQLiteStatementPtr getAccountGameRoomStatement; | ||||
| 	SQLiteStatementPtr getAccountDisplayNameStatement; | ||||
|  | ||||
| 	SQLiteStatementPtr isAccountCookieValidStatement; | ||||
| @@ -54,6 +56,7 @@ public: | ||||
| 	explicit LobbyDatabase(const boost::filesystem::path & databasePath); | ||||
| 	~LobbyDatabase(); | ||||
|  | ||||
| 	void setAccountOnline(const std::string & accountID, bool isOnline); | ||||
| 	void setGameRoomStatus(const std::string & roomID, LobbyRoomState roomStatus); | ||||
| 	void setGameRoomPlayerLimit(const std::string & roomID, uint32_t playerLimit); | ||||
|  | ||||
|   | ||||
| @@ -18,7 +18,9 @@ struct LobbyAccount | ||||
|  | ||||
| struct LobbyGameRoom | ||||
| { | ||||
| 	std::string roomUUID; | ||||
| 	std::string roomID; | ||||
| 	std::string hostAccountID; | ||||
| 	std::string hostAccountDisplayName; | ||||
| 	std::string roomStatus; | ||||
| 	uint32_t playersCount; | ||||
| 	uint32_t playersLimit; | ||||
| @@ -48,10 +50,10 @@ enum class LobbyInviteStatus : int32_t | ||||
|  | ||||
| enum class LobbyRoomState : int32_t | ||||
| { | ||||
| 	IDLE, // server is ready but no players are in the room | ||||
| 	PUBLIC, // host has joined and allows anybody to join | ||||
| 	PRIVATE, // host has joined but only allows those he invited to join | ||||
| 	//BUSY,        // match is ongoing | ||||
| 	//CANCELLED,   // game room was cancelled without starting the game | ||||
| 	//CLOSED,      // game room was closed after playing for some time | ||||
| 	IDLE = 0, // server is ready but no players are in the room | ||||
| 	PUBLIC = 1, // host has joined and allows anybody to join | ||||
| 	PRIVATE = 2, // host has joined but only allows those he invited to join | ||||
| 	//BUSY = 3, // match is ongoing | ||||
| 	//CANCELLED = 4, // game room was cancelled without starting the game | ||||
| 	CLOSED = 5, // game room was closed after playing for some time | ||||
| }; | ||||
|   | ||||
| @@ -140,7 +140,7 @@ void LobbyServer::broadcastActiveAccounts() | ||||
| 		JsonNode jsonEntry; | ||||
| 		jsonEntry["accountID"].String() = account.accountID; | ||||
| 		jsonEntry["displayName"].String() = account.displayName; | ||||
| 		//		jsonEntry["status"].String() = account.status; | ||||
| 		jsonEntry["status"].String() = "In Lobby"; // TODO: in room status, in match status, offline status(?) | ||||
| 		reply["accounts"].Vector().push_back(jsonEntry); | ||||
| 	} | ||||
|  | ||||
| @@ -157,10 +157,13 @@ void LobbyServer::broadcastActiveGameRooms() | ||||
| 	for(const auto & gameRoom : activeGameRoomStats) | ||||
| 	{ | ||||
| 		JsonNode jsonEntry; | ||||
| 		jsonEntry["gameRoomID"].String() = gameRoom.roomUUID; | ||||
| 		jsonEntry["status"].String() = gameRoom.roomStatus; | ||||
| 		jsonEntry["status"].Integer() = gameRoom.playersCount; | ||||
| 		jsonEntry["status"].Integer() = gameRoom.playersLimit; | ||||
| 		jsonEntry["gameRoomID"].String() = gameRoom.roomID; | ||||
| 		jsonEntry["hostAccountID"].String() = gameRoom.hostAccountID; | ||||
| 		jsonEntry["hostAccountDisplayName"].String() = gameRoom.hostAccountDisplayName; | ||||
| 		jsonEntry["description"].String() = "TODO: ROOM DESCRIPTION"; | ||||
| //		jsonEntry["status"].String() = gameRoom.roomStatus; | ||||
| 		jsonEntry["playersCount"].Integer() = gameRoom.playersCount; | ||||
| 		jsonEntry["playersLimit"].Integer() = gameRoom.playersLimit; | ||||
| 		reply["gameRooms"].Vector().push_back(jsonEntry); | ||||
| 	} | ||||
|  | ||||
| @@ -204,6 +207,12 @@ void LobbyServer::onNewConnection(const NetworkConnectionPtr & connection) | ||||
|  | ||||
| void LobbyServer::onDisconnected(const NetworkConnectionPtr & connection) | ||||
| { | ||||
| 	if (activeAccounts.count(connection)) | ||||
| 		database->setAccountOnline(activeAccounts.at(connection).accountID, false); | ||||
|  | ||||
| 	if (activeGameRooms.count(connection)) | ||||
| 		database->setGameRoomStatus(activeGameRooms.at(connection).roomID, LobbyRoomState::CLOSED); | ||||
|  | ||||
| 	// NOTE: lost connection can be in only one of these lists (or in none of them) | ||||
| 	// calling on all possible containers since calling std::map::erase() with non-existing key is legal | ||||
| 	activeAccounts.erase(connection); | ||||
| @@ -334,6 +343,7 @@ void LobbyServer::receiveClientLogin(const NetworkConnectionPtr & connection, co | ||||
| 	// prolong existing cookie | ||||
| 	database->updateAccessCookie(accountID, accountCookie); | ||||
| 	database->updateAccountLoginTime(accountID); | ||||
| 	database->setAccountOnline(accountID, true); | ||||
|  | ||||
| 	std::string displayName = database->getAccountDisplayName(accountID); | ||||
|  | ||||
| @@ -369,6 +379,8 @@ void LobbyServer::receiveServerLogin(const NetworkConnectionPtr & connection, co | ||||
| 		activeGameRooms[connection].roomID = gameRoomID; | ||||
| 		sendLoginSuccess(connection, accountCookie, {}); | ||||
| 	} | ||||
|  | ||||
| 	broadcastActiveGameRooms(); | ||||
| } | ||||
|  | ||||
| void LobbyServer::receiveClientProxyLogin(const NetworkConnectionPtr & connection, const JsonNode & json) | ||||
| @@ -451,7 +463,7 @@ void LobbyServer::receiveOpenGameRoom(const NetworkConnectionPtr & connection, c | ||||
| 		database->setGameRoomStatus(gameRoomID, LobbyRoomState::PRIVATE); | ||||
|  | ||||
| 	// TODO: additional flags / initial settings, e.g. allowCheats | ||||
| 	// TODO: connection mode: direct or proxy. For now direct is assumed | ||||
| 	// TODO: connection mode: direct or proxy. For now direct is assumed. Proxy might be needed later, for hosted servers | ||||
|  | ||||
| 	broadcastActiveGameRooms(); | ||||
| 	sendJoinRoomSuccess(connection, gameRoomID); | ||||
|   | ||||
| @@ -15,6 +15,7 @@ set(server_SRCS | ||||
| 		processors/PlayerMessageProcessor.cpp | ||||
| 		processors/TurnOrderProcessor.cpp | ||||
|  | ||||
| 		EntryPoint.cpp | ||||
| 		CGameHandler.cpp | ||||
| 		GlobalLobbyProcessor.cpp | ||||
| 		ServerSpellCastEnvironment.cpp | ||||
|   | ||||
| @@ -10,44 +10,15 @@ | ||||
| #include "StdInc.h" | ||||
| #include "CVCMIServer.h" | ||||
|  | ||||
| #include "../lib/filesystem/Filesystem.h" | ||||
| #include "../lib/campaign/CampaignState.h" | ||||
| #include "../lib/CThreadHelper.h" | ||||
| #include "../lib/CArtHandler.h" | ||||
| #include "../lib/CGeneralTextHandler.h" | ||||
| #include "../lib/CHeroHandler.h" | ||||
| #include "../lib/CTownHandler.h" | ||||
| #include "../lib/CBuildingHandler.h" | ||||
| #include "../lib/spells/CSpellHandler.h" | ||||
| #include "../lib/CCreatureHandler.h" | ||||
| #include "zlib.h" | ||||
| #include "../lib/StartInfo.h" | ||||
| #include "../lib/mapping/CMapHeader.h" | ||||
| #include "../lib/rmg/CMapGenOptions.h" | ||||
| #include "LobbyNetPackVisitors.h" | ||||
| #ifdef VCMI_ANDROID | ||||
| #include <jni.h> | ||||
| #include <android/log.h> | ||||
| #include "lib/CAndroidVMHelper.h" | ||||
| #endif | ||||
| #include "../lib/VCMI_Lib.h" | ||||
| #include "../lib/VCMIDirs.h" | ||||
| #include "CGameHandler.h" | ||||
| #include "GlobalLobbyProcessor.h" | ||||
| #include "LobbyNetPackVisitors.h" | ||||
| #include "processors/PlayerMessageProcessor.h" | ||||
| #include "../lib/mapping/CMapInfo.h" | ||||
| #include "../lib/GameConstants.h" | ||||
| #include "../lib/logging/CBasicLogConfigurator.h" | ||||
| #include "../lib/CConfigHandler.h" | ||||
| #include "../lib/ScopeGuard.h" | ||||
| #include "../lib/serializer/CMemorySerializer.h" | ||||
| #include "../lib/serializer/Cast.h" | ||||
| #include "../lib/serializer/Connection.h" | ||||
|  | ||||
| #include "../lib/UnlockGuard.h" | ||||
|  | ||||
| // for applier | ||||
| #include "../lib/CHeroHandler.h" | ||||
| #include "../lib/registerTypes/RegisterTypesLobbyPacks.h" | ||||
| #include "../lib/serializer/CMemorySerializer.h" | ||||
| #include "../lib/serializer/Connection.h" | ||||
|  | ||||
| // UUID generation | ||||
| #include <boost/uuid/uuid.hpp> | ||||
| @@ -55,8 +26,6 @@ | ||||
| #include <boost/uuid/uuid_generators.hpp> | ||||
| #include <boost/program_options.hpp> | ||||
|  | ||||
| #include "../lib/gameState/CGameState.h" | ||||
|  | ||||
| template<typename T> class CApplyOnServer; | ||||
|  | ||||
| class CBaseForServerApply | ||||
| @@ -147,9 +116,6 @@ public: | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| std::string SERVER_NAME_AFFIX = "server"; | ||||
| std::string SERVER_NAME = GameConstants::VCMI_VERSION + std::string(" (") + SERVER_NAME_AFFIX + ')'; | ||||
|  | ||||
| CVCMIServer::CVCMIServer(boost::program_options::variables_map & opts) | ||||
| 	: state(EServerState::LOBBY), cmdLineOptions(opts), currentClientId(1), currentPlayerId(1), restartGameplay(false) | ||||
| { | ||||
| @@ -158,20 +124,29 @@ CVCMIServer::CVCMIServer(boost::program_options::variables_map & opts) | ||||
| 	applier = std::make_shared<CApplier<CBaseForServerApply>>(); | ||||
| 	registerTypesLobbyPacks(*applier); | ||||
|  | ||||
| 	networkHandler = INetworkHandler::createHandler(); | ||||
|  | ||||
| 	if(cmdLineOptions.count("lobby")) | ||||
| 		lobbyProcessor = std::make_unique<GlobalLobbyProcessor>(*this); | ||||
| 	else | ||||
| 		startAcceptingIncomingConnections(); | ||||
| } | ||||
|  | ||||
| CVCMIServer::~CVCMIServer() = default; | ||||
|  | ||||
| void CVCMIServer::startAcceptingIncomingConnections() | ||||
| { | ||||
| 	uint16_t port = 3030; | ||||
|  | ||||
| 	if(cmdLineOptions.count("port")) | ||||
| 		port = cmdLineOptions["port"].as<uint16_t>(); | ||||
| 	logNetwork->info("Port %d will be used", port); | ||||
|  | ||||
| 	networkHandler = INetworkHandler::createHandler(); | ||||
| 	networkServer = networkHandler->createServerTCP(*this); | ||||
| 	networkServer->start(port); | ||||
| 	establishOutgoingConnection(); | ||||
| 	logNetwork->info("Listening for connections at port %d", port); | ||||
| } | ||||
|  | ||||
| CVCMIServer::~CVCMIServer() = default; | ||||
|  | ||||
| void CVCMIServer::onNewConnection(const std::shared_ptr<INetworkConnection> & connection) | ||||
| { | ||||
| 	if(state == EServerState::LOBBY) | ||||
| @@ -206,7 +181,7 @@ EServerState CVCMIServer::getState() const | ||||
|  | ||||
| std::shared_ptr<CConnection> CVCMIServer::findConnection(const std::shared_ptr<INetworkConnection> & netConnection) | ||||
| { | ||||
| 	for (auto const & gameConnection : activeConnections) | ||||
| 	for(const auto & gameConnection : activeConnections) | ||||
| 	{ | ||||
| 		if (gameConnection->isMyConnection(netConnection)) | ||||
| 			return gameConnection; | ||||
| @@ -249,12 +224,6 @@ void CVCMIServer::onTimer() | ||||
| 	networkHandler->createTimer(*this, serverUpdateInterval); | ||||
| } | ||||
|  | ||||
| void CVCMIServer::establishOutgoingConnection() | ||||
| { | ||||
| 	if(cmdLineOptions.count("lobby")) | ||||
| 		lobbyProcessor = std::make_unique<GlobalLobbyProcessor>(*this); | ||||
| } | ||||
|  | ||||
| void CVCMIServer::prepareToRestart() | ||||
| { | ||||
| 	if(state == EServerState::GAMEPLAY) | ||||
| @@ -304,7 +273,7 @@ bool CVCMIServer::prepareToStartGame() | ||||
| 	gh = std::make_shared<CGameHandler>(this); | ||||
| 	switch(si->mode) | ||||
| 	{ | ||||
| 	case StartInfo::CAMPAIGN: | ||||
| 	case EStartMode::CAMPAIGN: | ||||
| 		logNetwork->info("Preparing to start new campaign"); | ||||
| 		si->startTimeIso8601 = vstd::getDateTimeISO8601Basic(std::time(nullptr)); | ||||
| 		si->fileURI = mi->fileURI; | ||||
| @@ -313,14 +282,14 @@ bool CVCMIServer::prepareToStartGame() | ||||
| 		gh->init(si.get(), progressTracking); | ||||
| 		break; | ||||
|  | ||||
| 	case StartInfo::NEW_GAME: | ||||
| 	case EStartMode::NEW_GAME: | ||||
| 		logNetwork->info("Preparing to start new game"); | ||||
| 		si->startTimeIso8601 = vstd::getDateTimeISO8601Basic(std::time(nullptr)); | ||||
| 		si->fileURI = mi->fileURI; | ||||
| 		gh->init(si.get(), progressTracking); | ||||
| 		break; | ||||
|  | ||||
| 	case StartInfo::LOAD_GAME: | ||||
| 	case EStartMode::LOAD_GAME: | ||||
| 		logNetwork->info("Preparing to start loaded game"); | ||||
| 		if(!gh->load(si->mapname)) | ||||
| 		{ | ||||
| @@ -346,7 +315,7 @@ void CVCMIServer::startGameImmediately() | ||||
| 	for(auto c : activeConnections) | ||||
| 		c->enterGameplayConnectionMode(gh->gs); | ||||
|  | ||||
| 	gh->start(si->mode == StartInfo::LOAD_GAME); | ||||
| 	gh->start(si->mode == EStartMode::LOAD_GAME); | ||||
| 	state = EServerState::GAMEPLAY; | ||||
| 	lastTimerUpdateTime = gameplayStartTime = std::chrono::steady_clock::now(); | ||||
| 	onTimer(); | ||||
| @@ -360,7 +329,11 @@ void CVCMIServer::onDisconnected(const std::shared_ptr<INetworkConnection> & con | ||||
| 	vstd::erase(activeConnections, c); | ||||
|  | ||||
| 	if(activeConnections.empty() || hostClientId == c->connectionID) | ||||
| 	{ | ||||
| 		networkHandler->stop(); | ||||
| 		state = EServerState::SHUTDOWN; | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if(gh && state == EServerState::GAMEPLAY) | ||||
| 	{ | ||||
| @@ -428,7 +401,7 @@ bool CVCMIServer::passHost(int toConnectionId) | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| void CVCMIServer::clientConnected(std::shared_ptr<CConnection> c, std::vector<std::string> & names, std::string uuid, StartInfo::EMode mode) | ||||
| void CVCMIServer::clientConnected(std::shared_ptr<CConnection> c, std::vector<std::string> & names, std::string uuid, EStartMode mode) | ||||
| { | ||||
| 	if(state != EServerState::LOBBY) | ||||
| 		throw std::runtime_error("CVCMIServer::clientConnected called while game is not accepting clients!"); | ||||
| @@ -468,16 +441,16 @@ void CVCMIServer::clientConnected(std::shared_ptr<CConnection> c, std::vector<st | ||||
|  | ||||
| void CVCMIServer::clientDisconnected(std::shared_ptr<CConnection> c) | ||||
| { | ||||
| 	networkServer->closeConnection(c->getConnection()); | ||||
| 	vstd::erase(activeConnections, c); | ||||
|  | ||||
| 	if(activeConnections.empty() || hostClientId == c->connectionID) | ||||
| 	{ | ||||
| 		networkHandler->stop(); | ||||
| 		state = EServerState::SHUTDOWN; | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	// TODO: close network connection | ||||
|  | ||||
| //	PlayerReinitInterface startAiPack; | ||||
| //	startAiPack.playerConnectionId = PlayerSettings::PLAYER_AI; | ||||
| // | ||||
| @@ -565,7 +538,7 @@ void CVCMIServer::updateStartInfoOnMapChange(std::shared_ptr<CMapInfo> mapInfo, | ||||
| 	if(mi->scenarioOptionsOfSave) | ||||
| 	{ | ||||
| 		si = CMemorySerializer::deepCopy(*mi->scenarioOptionsOfSave); | ||||
| 		si->mode = StartInfo::LOAD_GAME; | ||||
| 		si->mode = EStartMode::LOAD_GAME; | ||||
| 		if(si->campState) | ||||
| 			campaignMap = si->campState->currentScenario().value(); | ||||
|  | ||||
| @@ -581,7 +554,7 @@ void CVCMIServer::updateStartInfoOnMapChange(std::shared_ptr<CMapInfo> mapInfo, | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	else if(si->mode == StartInfo::NEW_GAME || si->mode == StartInfo::CAMPAIGN) | ||||
| 	else if(si->mode == EStartMode::NEW_GAME || si->mode == EStartMode::CAMPAIGN) | ||||
| 	{ | ||||
| 		if(mi->campaign) | ||||
| 			return; | ||||
| @@ -634,7 +607,7 @@ void CVCMIServer::updateAndPropagateLobbyState() | ||||
| { | ||||
| 	// Update player settings for RMG | ||||
| 	// TODO: find appropriate location for this code | ||||
| 	if(si->mapGenOptions && si->mode == StartInfo::NEW_GAME) | ||||
| 	if(si->mapGenOptions && si->mode == EStartMode::NEW_GAME) | ||||
| 	{ | ||||
| 		for(const auto & psetPair : si->playerInfos) | ||||
| 		{ | ||||
| @@ -971,140 +944,3 @@ ui8 CVCMIServer::getIdOfFirstUnallocatedPlayer() const | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static void handleCommandOptions(int argc, const char * argv[], boost::program_options::variables_map & options) | ||||
| { | ||||
| 	namespace po = boost::program_options; | ||||
| 	po::options_description opts("Allowed options"); | ||||
| 	opts.add_options() | ||||
| 	("help,h", "display help and exit") | ||||
| 	("version,v", "display version information and exit") | ||||
| 	("run-by-client", "indicate that server launched by client on same machine") | ||||
| 	("port", po::value<ui16>(), "port at which server will listen to connections from client") | ||||
| 	("lobby", "start server in lobby mode in which server connects to a global lobby"); | ||||
|  | ||||
| 	if(argc > 1) | ||||
| 	{ | ||||
| 		try | ||||
| 		{ | ||||
| 			po::store(po::parse_command_line(argc, argv, opts), options); | ||||
| 		} | ||||
| 		catch(boost::program_options::error & e) | ||||
| 		{ | ||||
| 			std::cerr << "Failure during parsing command-line options:\n" << e.what() << std::endl; | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| #ifdef SINGLE_PROCESS_APP | ||||
| 	options.emplace("run-by-client", po::variable_value{true, true}); | ||||
| #endif | ||||
|  | ||||
| 	po::notify(options); | ||||
|  | ||||
| #ifndef SINGLE_PROCESS_APP | ||||
| 	if(options.count("help")) | ||||
| 	{ | ||||
| 		auto time = std::time(nullptr); | ||||
| 		printf("%s - A Heroes of Might and Magic 3 clone\n", GameConstants::VCMI_VERSION.c_str()); | ||||
| 		printf("Copyright (C) 2007-%d VCMI dev team - see AUTHORS file\n", std::localtime(&time)->tm_year + 1900); | ||||
| 		printf("This is free software; see the source for copying conditions. There is NO\n"); | ||||
| 		printf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"); | ||||
| 		printf("\n"); | ||||
| 		std::cout << opts; | ||||
| 		exit(0); | ||||
| 	} | ||||
|  | ||||
| 	if(options.count("version")) | ||||
| 	{ | ||||
| 		printf("%s\n", GameConstants::VCMI_VERSION.c_str()); | ||||
| 		std::cout << VCMIDirs::get().genHelpString(); | ||||
| 		exit(0); | ||||
| 	} | ||||
| #endif | ||||
| } | ||||
|  | ||||
| #ifdef SINGLE_PROCESS_APP | ||||
| #define main server_main | ||||
| #endif | ||||
|  | ||||
| #if VCMI_ANDROID_DUAL_PROCESS | ||||
| void CVCMIServer::create() | ||||
| { | ||||
| 	const int argc = 1; | ||||
| 	const char * argv[argc] = { "android-server" }; | ||||
| #else | ||||
| int main(int argc, const char * argv[]) | ||||
| { | ||||
| #endif | ||||
|  | ||||
| #if !defined(VCMI_ANDROID) && !defined(SINGLE_PROCESS_APP) | ||||
| 	// Correct working dir executable folder (not bundle folder) so we can use executable relative paths | ||||
| 	boost::filesystem::current_path(boost::filesystem::system_complete(argv[0]).parent_path()); | ||||
| #endif | ||||
|  | ||||
| #ifndef VCMI_IOS | ||||
| 	console = new CConsoleHandler(); | ||||
| #endif | ||||
| 	CBasicLogConfigurator logConfig(VCMIDirs::get().userLogsPath() / "VCMI_Server_log.txt", console); | ||||
| 	logConfig.configureDefault(); | ||||
| 	logGlobal->info(SERVER_NAME); | ||||
|  | ||||
| 	boost::program_options::variables_map opts; | ||||
| 	handleCommandOptions(argc, argv, opts); | ||||
| 	preinitDLL(console, false); | ||||
| 	logConfig.configure(); | ||||
|  | ||||
| 	loadDLLClasses(); | ||||
| 	srand((ui32)time(nullptr)); | ||||
|  | ||||
| 	CVCMIServer server(opts); | ||||
|  | ||||
| #ifdef SINGLE_PROCESS_APP | ||||
| 	boost::condition_variable * cond = reinterpret_cast<boost::condition_variable *>(const_cast<char *>(argv[0])); | ||||
| 	cond->notify_one(); | ||||
| #endif | ||||
|  | ||||
| 	server.run(); | ||||
|  | ||||
| #if VCMI_ANDROID_DUAL_PROCESS | ||||
| 	CAndroidVMHelper envHelper; | ||||
| 	envHelper.callStaticVoidMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "killServer"); | ||||
| #endif | ||||
| 	logConfig.deconfigure(); | ||||
| 	vstd::clear_pointer(VLC); | ||||
|  | ||||
| #if !VCMI_ANDROID_DUAL_PROCESS | ||||
| 	return 0; | ||||
| #endif | ||||
| } | ||||
|  | ||||
| #if VCMI_ANDROID_DUAL_PROCESS | ||||
| extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_createServer(JNIEnv * env, jclass cls) | ||||
| { | ||||
| 	__android_log_write(ANDROID_LOG_INFO, "VCMI", "Got jni call to init server"); | ||||
| 	CAndroidVMHelper::cacheVM(env); | ||||
|  | ||||
| 	CVCMIServer::create(); | ||||
| } | ||||
|  | ||||
| extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_initClassloader(JNIEnv * baseEnv, jclass cls) | ||||
| { | ||||
| 	CAndroidVMHelper::initClassloader(baseEnv); | ||||
| } | ||||
| #elif defined(SINGLE_PROCESS_APP) | ||||
| void CVCMIServer::create(boost::condition_variable * cond, const std::vector<std::string> & args) | ||||
| { | ||||
| 	std::vector<const void *> argv = {cond}; | ||||
| 	for(auto & a : args) | ||||
| 		argv.push_back(a.c_str()); | ||||
| 	main(argv.size(), reinterpret_cast<const char **>(&*argv.begin())); | ||||
| } | ||||
|  | ||||
| #ifdef VCMI_ANDROID | ||||
| void CVCMIServer::reuseClientJNIEnv(void * jniEnv) | ||||
| { | ||||
| 	CAndroidVMHelper::initClassloader(jniEnv); | ||||
| 	CAndroidVMHelper::alwaysUseLoadedClass = true; | ||||
| } | ||||
| #endif // VCMI_ANDROID | ||||
| #endif // VCMI_ANDROID_DUAL_PROCESS | ||||
|   | ||||
| @@ -70,8 +70,6 @@ private: | ||||
| 	std::shared_ptr<CApplier<CBaseForServerApply>> applier; | ||||
| 	EServerState state; | ||||
|  | ||||
| 	void establishOutgoingConnection(); | ||||
|  | ||||
| 	std::shared_ptr<CConnection> findConnection(const std::shared_ptr<INetworkConnection> &); | ||||
|  | ||||
| 	int currentClientId; | ||||
| @@ -84,7 +82,6 @@ public: | ||||
| 	void onNewConnection(const std::shared_ptr<INetworkConnection> &) override; | ||||
| 	void onTimer() override; | ||||
|  | ||||
|  | ||||
| 	std::shared_ptr<CGameHandler> gh; | ||||
| 	boost::program_options::variables_map cmdLineOptions; | ||||
|  | ||||
| @@ -96,6 +93,7 @@ public: | ||||
| 	bool prepareToStartGame(); | ||||
| 	void prepareToRestart(); | ||||
| 	void startGameImmediately(); | ||||
| 	void startAcceptingIncomingConnections(); | ||||
|  | ||||
| 	void threadHandleClient(std::shared_ptr<CConnection> c); | ||||
|  | ||||
| @@ -107,7 +105,7 @@ public: | ||||
| 	void setPlayerConnectedId(PlayerSettings & pset, ui8 player) const; | ||||
| 	void updateStartInfoOnMapChange(std::shared_ptr<CMapInfo> mapInfo, std::shared_ptr<CMapGenOptions> mapGenOpt = {}); | ||||
|  | ||||
| 	void clientConnected(std::shared_ptr<CConnection> c, std::vector<std::string> & names, std::string uuid, StartInfo::EMode mode); | ||||
| 	void clientConnected(std::shared_ptr<CConnection> c, std::vector<std::string> & names, std::string uuid, EStartMode mode); | ||||
| 	void clientDisconnected(std::shared_ptr<CConnection> c); | ||||
| 	void reconnectPlayer(int connId); | ||||
|  | ||||
|   | ||||
							
								
								
									
										170
									
								
								server/EntryPoint.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								server/EntryPoint.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,170 @@ | ||||
| /* | ||||
|  * EntryPoint.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 "CVCMIServer.h" | ||||
|  | ||||
| #include "../lib/CConsoleHandler.h" | ||||
| #include "../lib/logging/CBasicLogConfigurator.h" | ||||
| #include "../lib/VCMIDirs.h" | ||||
| #include "../lib/VCMI_Lib.h" | ||||
|  | ||||
| #ifdef VCMI_ANDROID | ||||
| #include <jni.h> | ||||
| #include <android/log.h> | ||||
| #include "lib/CAndroidVMHelper.h" | ||||
| #endif | ||||
|  | ||||
| #include <boost/program_options.hpp> | ||||
|  | ||||
| std::string SERVER_NAME_AFFIX = "server"; | ||||
| std::string SERVER_NAME = GameConstants::VCMI_VERSION + std::string(" (") + SERVER_NAME_AFFIX + ')'; | ||||
|  | ||||
| static void handleCommandOptions(int argc, const char * argv[], boost::program_options::variables_map & options) | ||||
| { | ||||
| 	namespace po = boost::program_options; | ||||
| 	po::options_description opts("Allowed options"); | ||||
| 	opts.add_options() | ||||
| 	("help,h", "display help and exit") | ||||
| 	("version,v", "display version information and exit") | ||||
| 	("run-by-client", "indicate that server launched by client on same machine") | ||||
| 	("port", po::value<ui16>(), "port at which server will listen to connections from client") | ||||
| 	("lobby", "start server in lobby mode in which server connects to a global lobby"); | ||||
|  | ||||
| 	if(argc > 1) | ||||
| 	{ | ||||
| 		try | ||||
| 		{ | ||||
| 			po::store(po::parse_command_line(argc, argv, opts), options); | ||||
| 		} | ||||
| 		catch(boost::program_options::error & e) | ||||
| 		{ | ||||
| 			std::cerr << "Failure during parsing command-line options:\n" << e.what() << std::endl; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| #ifdef SINGLE_PROCESS_APP | ||||
| 	options.emplace("run-by-client", po::variable_value{true, true}); | ||||
| #endif | ||||
|  | ||||
| 	po::notify(options); | ||||
|  | ||||
| #ifndef SINGLE_PROCESS_APP | ||||
| 	if(options.count("help")) | ||||
| 	{ | ||||
| 		auto time = std::time(nullptr); | ||||
| 		printf("%s - A Heroes of Might and Magic 3 clone\n", GameConstants::VCMI_VERSION.c_str()); | ||||
| 		printf("Copyright (C) 2007-%d VCMI dev team - see AUTHORS file\n", std::localtime(&time)->tm_year + 1900); | ||||
| 		printf("This is free software; see the source for copying conditions. There is NO\n"); | ||||
| 		printf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"); | ||||
| 		printf("\n"); | ||||
| 		std::cout << opts; | ||||
| 		exit(0); | ||||
| 	} | ||||
|  | ||||
| 	if(options.count("version")) | ||||
| 	{ | ||||
| 		printf("%s\n", GameConstants::VCMI_VERSION.c_str()); | ||||
| 		std::cout << VCMIDirs::get().genHelpString(); | ||||
| 		exit(0); | ||||
| 	} | ||||
| #endif | ||||
| } | ||||
|  | ||||
| #ifdef SINGLE_PROCESS_APP | ||||
| #define main server_main | ||||
| #endif | ||||
|  | ||||
| #if VCMI_ANDROID_DUAL_PROCESS | ||||
| void CVCMIServer::create() | ||||
| { | ||||
| 	const int argc = 1; | ||||
| 	const char * argv[argc] = { "android-server" }; | ||||
| #else | ||||
| int main(int argc, const char * argv[]) | ||||
| { | ||||
| #endif | ||||
|  | ||||
| #if !defined(VCMI_ANDROID) && !defined(SINGLE_PROCESS_APP) | ||||
| 	// Correct working dir executable folder (not bundle folder) so we can use executable relative paths | ||||
| 	boost::filesystem::current_path(boost::filesystem::system_complete(argv[0]).parent_path()); | ||||
| #endif | ||||
|  | ||||
| #ifndef VCMI_IOS | ||||
| 	console = new CConsoleHandler(); | ||||
| #endif | ||||
| 	CBasicLogConfigurator logConfig(VCMIDirs::get().userLogsPath() / "VCMI_Server_log.txt", console); | ||||
| 	logConfig.configureDefault(); | ||||
| 	logGlobal->info(SERVER_NAME); | ||||
|  | ||||
| 	boost::program_options::variables_map opts; | ||||
| 	handleCommandOptions(argc, argv, opts); | ||||
| 	preinitDLL(console, false); | ||||
| 	logConfig.configure(); | ||||
|  | ||||
| 	loadDLLClasses(); | ||||
| 	srand((ui32)time(nullptr)); | ||||
|  | ||||
| 	{ | ||||
| 		CVCMIServer server(opts); | ||||
|  | ||||
| #ifdef SINGLE_PROCESS_APP | ||||
| 		boost::condition_variable * cond = reinterpret_cast<boost::condition_variable *>(const_cast<char *>(argv[0])); | ||||
| 		cond->notify_one(); | ||||
| #endif | ||||
|  | ||||
| 		server.run(); | ||||
|  | ||||
| 		// CVCMIServer destructor must be called here - before VLC cleanup | ||||
| 	} | ||||
|  | ||||
|  | ||||
| #if VCMI_ANDROID_DUAL_PROCESS | ||||
| 	CAndroidVMHelper envHelper; | ||||
| 	envHelper.callStaticVoidMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "killServer"); | ||||
| #endif | ||||
| 	logConfig.deconfigure(); | ||||
| 	vstd::clear_pointer(VLC); | ||||
|  | ||||
| #if !VCMI_ANDROID_DUAL_PROCESS | ||||
| 	return 0; | ||||
| #endif | ||||
| } | ||||
|  | ||||
| #if VCMI_ANDROID_DUAL_PROCESS | ||||
| extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_createServer(JNIEnv * env, jclass cls) | ||||
| { | ||||
| 	__android_log_write(ANDROID_LOG_INFO, "VCMI", "Got jni call to init server"); | ||||
| 	CAndroidVMHelper::cacheVM(env); | ||||
|  | ||||
| 	CVCMIServer::create(); | ||||
| } | ||||
|  | ||||
| extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_initClassloader(JNIEnv * baseEnv, jclass cls) | ||||
| { | ||||
| 	CAndroidVMHelper::initClassloader(baseEnv); | ||||
| } | ||||
| #elif defined(SINGLE_PROCESS_APP) | ||||
| void CVCMIServer::create(boost::condition_variable * cond, const std::vector<std::string> & args) | ||||
| { | ||||
| 	std::vector<const void *> argv = {cond}; | ||||
| 	for(auto & a : args) | ||||
| 		argv.push_back(a.c_str()); | ||||
| 	main(argv.size(), reinterpret_cast<const char **>(&*argv.begin())); | ||||
| } | ||||
|  | ||||
| #ifdef VCMI_ANDROID | ||||
| void CVCMIServer::reuseClientJNIEnv(void * jniEnv) | ||||
| { | ||||
| 	CAndroidVMHelper::initClassloader(jniEnv); | ||||
| 	CAndroidVMHelper::alwaysUseLoadedClass = true; | ||||
| } | ||||
| #endif // VCMI_ANDROID | ||||
| #endif // VCMI_ANDROID_DUAL_PROCESS | ||||
| @@ -57,6 +57,7 @@ void GlobalLobbyProcessor::receiveLoginSuccess(const JsonNode & json) | ||||
| { | ||||
| 	// no-op, wait just for any new commands from lobby | ||||
| 	logGlobal->info("Succesfully connected to lobby server"); | ||||
| 	owner.startAcceptingIncomingConnections(); | ||||
| } | ||||
|  | ||||
| void GlobalLobbyProcessor::receiveAccountJoinsRoom(const JsonNode & json) | ||||
| @@ -83,6 +84,7 @@ void GlobalLobbyProcessor::onConnectionEstablished(const std::shared_ptr<INetwor | ||||
|  | ||||
| 		JsonNode toSend; | ||||
| 		toSend["type"].String() = "serverLogin"; | ||||
| 		toSend["gameRoomID"].String() = owner.uuid; | ||||
| 		toSend["accountID"] = settings["lobby"]["accountID"]; | ||||
| 		toSend["accountCookie"] = settings["lobby"]["accountCookie"]; | ||||
| 		sendMessage(toSend); | ||||
| @@ -97,7 +99,7 @@ void GlobalLobbyProcessor::onConnectionEstablished(const std::shared_ptr<INetwor | ||||
|  | ||||
| 		JsonNode toSend; | ||||
| 		toSend["type"].String() = "serverProxyLogin"; | ||||
| 		toSend["gameRoomID"].String() = ""; | ||||
| 		toSend["gameRoomID"].String() = owner.uuid; | ||||
| 		toSend["accountID"].String() = accountID; | ||||
| 		toSend["accountCookie"] = settings["lobby"]["accountCookie"]; | ||||
| 		sendMessage(toSend); | ||||
|   | ||||
| @@ -158,7 +158,7 @@ void ApplyOnServerNetPackVisitor::visitLobbySetMap(LobbySetMap & pack) | ||||
| void ApplyOnServerNetPackVisitor::visitLobbySetCampaign(LobbySetCampaign & pack) | ||||
| { | ||||
| 	srv.si->mapname = pack.ourCampaign->getFilename(); | ||||
| 	srv.si->mode = StartInfo::CAMPAIGN; | ||||
| 	srv.si->mode = EStartMode::CAMPAIGN; | ||||
| 	srv.si->campState = pack.ourCampaign; | ||||
| 	srv.si->turnTimerInfo = TurnTimerInfo{}; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user