mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Initial version of global lobby server available in client
This commit is contained in:
		| @@ -89,6 +89,10 @@ if(NOT APPLE_IOS AND NOT ANDROID) | ||||
| 	option(ENABLE_MONOLITHIC_INSTALL "Install everything in single directory on Linux and Mac" OFF) | ||||
| endif() | ||||
|  | ||||
| if(NOT APPLE_IOS AND NOT ANDROID) | ||||
| 	option(ENABLE_LOBBY "Enable compilation of lobby server" ON) | ||||
| endif() | ||||
|  | ||||
| option(ENABLE_CCACHE "Speed up recompilation by caching previous compilations" OFF) | ||||
| if(ENABLE_CCACHE) | ||||
| 	find_program(CCACHE ccache REQUIRED) | ||||
| @@ -475,6 +479,10 @@ if(TARGET SDL2_ttf::SDL2_ttf) | ||||
| 	add_library(SDL2::TTF ALIAS SDL2_ttf::SDL2_ttf) | ||||
| endif() | ||||
|  | ||||
| if(ENABLE_LOBBY) | ||||
| 	find_package(SQLite3 REQUIRED) | ||||
| endif() | ||||
|  | ||||
| if(ENABLE_LAUNCHER OR ENABLE_EDITOR) | ||||
| 	# Widgets finds its own dependencies (QtGui and QtCore). | ||||
| 	find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Network) | ||||
| @@ -622,6 +630,9 @@ endif() | ||||
| if(ENABLE_EDITOR) | ||||
| 	add_subdirectory(mapeditor) | ||||
| endif() | ||||
| if(ENABLE_LOBBY) | ||||
| 	add_subdirectory(lobby) | ||||
| endif() | ||||
| add_subdirectory(client) | ||||
| add_subdirectory(server) | ||||
| if(ENABLE_TEST) | ||||
|   | ||||
| @@ -95,6 +95,8 @@ set(client_SRCS | ||||
| 	renderSDL/ScreenHandler.cpp | ||||
| 	renderSDL/SDL_Extensions.cpp | ||||
|  | ||||
| 	serverLobby/LobbyWindow.cpp | ||||
|  | ||||
| 	widgets/Buttons.cpp | ||||
| 	widgets/CArtifactHolder.cpp | ||||
| 	widgets/CComponent.cpp | ||||
| @@ -270,6 +272,8 @@ set(client_HEADERS | ||||
| 	renderSDL/SDL_Extensions.h | ||||
| 	renderSDL/SDL_PixelAccess.h | ||||
|  | ||||
| 	serverLobby/LobbyWindow.h | ||||
|  | ||||
| 	widgets/Buttons.h | ||||
| 	widgets/CArtifactHolder.h | ||||
| 	widgets/CComponent.h | ||||
|   | ||||
| @@ -129,6 +129,9 @@ void InterfaceObjectConfigurable::build(const JsonNode &config) | ||||
| 	 | ||||
| 	for(const auto & item : items->Vector()) | ||||
| 		addWidget(item["name"].String(), buildWidget(item)); | ||||
|  | ||||
| 	pos.w = config["width"].Integer(); | ||||
| 	pos.h = config["height"].Integer(); | ||||
| } | ||||
|  | ||||
| void InterfaceObjectConfigurable::addConditional(const std::string & name, bool active) | ||||
|   | ||||
| @@ -24,6 +24,7 @@ | ||||
| #include "../gui/Shortcut.h" | ||||
| #include "../gui/WindowHandler.h" | ||||
| #include "../render/Canvas.h" | ||||
| #include "../serverLobby/LobbyWindow.h" | ||||
| #include "../widgets/CComponent.h" | ||||
| #include "../widgets/Buttons.h" | ||||
| #include "../widgets/MiscWidgets.h" | ||||
| @@ -459,9 +460,17 @@ CMultiMode::CMultiMode(ESelectionScreen ScreenType) | ||||
| 	buttonHotseat = std::make_shared<CButton>(Point(373, 78), AnimationPath::builtin("MUBHOT.DEF"), CGI->generaltexth->zelp[266], std::bind(&CMultiMode::hostTCP, this)); | ||||
| 	buttonHost = std::make_shared<CButton>(Point(373, 78 + 57 * 1), AnimationPath::builtin("MUBHOST.DEF"), CButton::tooltip(CGI->generaltexth->translate("vcmi.mainMenu.hostTCP"), ""), std::bind(&CMultiMode::hostTCP, this)); | ||||
| 	buttonJoin = std::make_shared<CButton>(Point(373, 78 + 57 * 2), AnimationPath::builtin("MUBJOIN.DEF"), CButton::tooltip(CGI->generaltexth->translate("vcmi.mainMenu.joinTCP"), ""), std::bind(&CMultiMode::joinTCP, this)); | ||||
| 	buttonLobby = std::make_shared<CButton>(Point(373, 78 + 57 * 4), AnimationPath::builtin("MUBONL.DEF"), CGI->generaltexth->zelp[265], std::bind(&CMultiMode::openLobby, this)); | ||||
|  | ||||
| 	buttonCancel = std::make_shared<CButton>(Point(373, 424), AnimationPath::builtin("MUBCANC.DEF"), CGI->generaltexth->zelp[288], [=](){ close();}, EShortcut::GLOBAL_CANCEL); | ||||
| } | ||||
|  | ||||
| void CMultiMode::openLobby() | ||||
| { | ||||
| 	close(); | ||||
| 	GH.windows().createAndPushWindow<LobbyWindow>(); | ||||
| } | ||||
|  | ||||
| void CMultiMode::hostTCP() | ||||
| { | ||||
| 	auto savedScreenType = screenType; | ||||
|   | ||||
| @@ -86,12 +86,14 @@ public: | ||||
| 	std::shared_ptr<CPicture> picture; | ||||
| 	std::shared_ptr<CTextInput> playerName; | ||||
| 	std::shared_ptr<CButton> buttonHotseat; | ||||
| 	std::shared_ptr<CButton> buttonLobby; | ||||
| 	std::shared_ptr<CButton> buttonHost; | ||||
| 	std::shared_ptr<CButton> buttonJoin; | ||||
| 	std::shared_ptr<CButton> buttonCancel; | ||||
| 	std::shared_ptr<CGStatusBar> statusBar; | ||||
|  | ||||
| 	CMultiMode(ESelectionScreen ScreenType); | ||||
| 	void openLobby(); | ||||
| 	void hostTCP(); | ||||
| 	void joinTCP(); | ||||
| 	std::string getPlayerName(); | ||||
|   | ||||
							
								
								
									
										40
									
								
								client/serverLobby/LobbyWindow.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								client/serverLobby/LobbyWindow.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| /* | ||||
|  * LobbyWindow.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 "LobbyWindow.h" | ||||
|  | ||||
| #include "../gui/CGuiHandler.h" | ||||
| #include "../gui/WindowHandler.h" | ||||
|  | ||||
| void LobbyClient::onPacketReceived(const std::vector<uint8_t> & message) | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| LobbyWidget::LobbyWidget() | ||||
| { | ||||
| 	addCallback("closeWindow", [](int) { GH.windows().popWindows(1); }); | ||||
|  | ||||
| 	const JsonNode config(JsonPath::builtin("config/widgets/lobbyWindow.json")); | ||||
| 	build(config); | ||||
| } | ||||
|  | ||||
| LobbyWindow::LobbyWindow(): | ||||
| 	CWindowObject(BORDERED) | ||||
| { | ||||
| 	OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE; | ||||
| 	widget = std::make_shared<LobbyWidget>(); | ||||
| 	pos = widget->pos; | ||||
| 	center(); | ||||
| 	connection = std::make_shared<LobbyClient>(); | ||||
|  | ||||
| 	connection->start("127.0.0.1", 30303); | ||||
| } | ||||
							
								
								
									
										37
									
								
								client/serverLobby/LobbyWindow.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								client/serverLobby/LobbyWindow.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| /* | ||||
|  * LobbyWindow.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 "../gui/InterfaceObjectConfigurable.h" | ||||
| #include "../windows/CWindowObject.h" | ||||
|  | ||||
| #include "../../lib/network/NetworkClient.h" | ||||
|  | ||||
| class LobbyWidget : public InterfaceObjectConfigurable | ||||
| { | ||||
| public: | ||||
| 	LobbyWidget(); | ||||
| }; | ||||
|  | ||||
| class LobbyClient : public NetworkClient | ||||
| { | ||||
| 	void onPacketReceived(const std::vector<uint8_t> & message) override; | ||||
| public: | ||||
| 	LobbyClient() = default; | ||||
| }; | ||||
|  | ||||
| class LobbyWindow : public CWindowObject | ||||
| { | ||||
| 	std::shared_ptr<LobbyWidget> widget; | ||||
| 	std::shared_ptr<LobbyClient> connection; | ||||
|  | ||||
| public: | ||||
| 	LobbyWindow(); | ||||
| }; | ||||
| @@ -124,6 +124,10 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE) | ||||
| 		${MAIN_LIB_DIR}/modding/IdentifierStorage.cpp | ||||
| 		${MAIN_LIB_DIR}/modding/ModUtility.cpp | ||||
|  | ||||
| 		${MAIN_LIB_DIR}/network/NetworkClient.cpp | ||||
| 		${MAIN_LIB_DIR}/network/NetworkConnection.cpp | ||||
| 		${MAIN_LIB_DIR}/network/NetworkServer.cpp | ||||
|  | ||||
| 		${MAIN_LIB_DIR}/networkPacks/NetPacksLib.cpp | ||||
|  | ||||
| 		${MAIN_LIB_DIR}/pathfinder/CGPathNode.cpp | ||||
| @@ -471,6 +475,11 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE) | ||||
| 		${MAIN_LIB_DIR}/modding/ModUtility.h | ||||
| 		${MAIN_LIB_DIR}/modding/ModVerificationInfo.h | ||||
|  | ||||
| 		${MAIN_LIB_DIR}/network/NetworkClient.h | ||||
| 		${MAIN_LIB_DIR}/network/NetworkConnection.h | ||||
| 		${MAIN_LIB_DIR}/network/NetworkDefines.h | ||||
| 		${MAIN_LIB_DIR}/network/NetworkServer.h | ||||
|  | ||||
| 		${MAIN_LIB_DIR}/networkPacks/ArtifactLocation.h | ||||
| 		${MAIN_LIB_DIR}/networkPacks/BattleChanges.h | ||||
| 		${MAIN_LIB_DIR}/networkPacks/Component.h | ||||
|   | ||||
							
								
								
									
										186
									
								
								config/widgets/lobbyWindow.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										186
									
								
								config/widgets/lobbyWindow.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,186 @@ | ||||
| { | ||||
| 	"customTypes" : { | ||||
| 		"labelTitleMain" : { | ||||
| 			"type": "label", | ||||
| 			"font": "big", | ||||
| 			"alignment": "left", | ||||
| 			"color": "yellow" | ||||
| 		}, | ||||
| 		"labelTitle" : { | ||||
| 			"type": "label", | ||||
| 			"font": "small", | ||||
| 			"alignment": "left", | ||||
| 			"color": "yellow" | ||||
| 		}, | ||||
| 		"backgroundTexture" : { | ||||
| 			"type": "texture", | ||||
| 			"font": "tiny", | ||||
| 			"color" : "blue", | ||||
| 			"image": "DIBOXBCK" | ||||
| 		}, | ||||
| 		"areaFilled":{ | ||||
| 			"type": "transparentFilledRectangle", | ||||
| 			"color": [0, 0, 0, 75], | ||||
| 			"colorLine": [64, 80, 128, 255] | ||||
| 		} | ||||
| 	}, | ||||
| 	 | ||||
| 	 | ||||
| 	"width": 1024, | ||||
| 	"height": 600, | ||||
| 	 | ||||
| 	"items": | ||||
| 	[ | ||||
| 		{ | ||||
| 			"type": "backgroundTexture", | ||||
| 			"rect": {"w": 1024, "h": 600} | ||||
| 		}, | ||||
| 		 | ||||
| 		{ | ||||
| 			"type": "areaFilled", | ||||
| 			"rect": {"x": 5, "y": 5, "w": 250, "h": 40} | ||||
| 		}, | ||||
| 		{ | ||||
| 			"type": "labelTitleMain", | ||||
| 			"position": {"x": 15, "y": 10}, | ||||
| 			"text" : "Player Name" | ||||
| 		}, | ||||
| 		 | ||||
| 		{ | ||||
| 			"type": "areaFilled", | ||||
| 			"rect": {"x": 5, "y": 50, "w": 250, "h": 150} | ||||
| 		}, | ||||
| 		{ | ||||
| 			"type": "labelTitle", | ||||
| 			"position": {"x": 15, "y": 53}, | ||||
| 			"text" : "Match Filter" | ||||
| 		}, | ||||
|  | ||||
| 		{ | ||||
| 			"type": "areaFilled", | ||||
| 			"rect": {"x": 5, "y": 210, "w": 250, "h": 310} | ||||
| 		}, | ||||
| 		{ | ||||
| 			"type": "labelTitle", | ||||
| 			"position": {"x": 15, "y": 213}, | ||||
| 			"text" : "Match List" | ||||
| 		}, | ||||
| 		 | ||||
| 		{ | ||||
| 			"type": "areaFilled", | ||||
| 			"rect": {"x": 270, "y": 50, "w": 150, "h": 540} | ||||
| 		}, | ||||
| 		{ | ||||
| 			"type": "labelTitle", | ||||
| 			"position": {"x": 280, "y": 53}, | ||||
| 			"text" : "Channel List" | ||||
| 		}, | ||||
| 		 | ||||
| 		{ | ||||
| 			"type": "areaFilled", | ||||
| 			"rect": {"x": 430, "y": 50, "w": 430, "h": 515} | ||||
| 		}, | ||||
| 		{ | ||||
| 			"type": "labelTitle", | ||||
| 			"position": {"x": 440, "y": 53}, | ||||
| 			"text" : "Game Chat" | ||||
| 		}, | ||||
| 		 | ||||
| 		{ | ||||
| 			"type": "areaFilled", | ||||
| 			"rect": {"x": 430, "y": 565, "w": 395, "h": 25} | ||||
| 		}, | ||||
| 		{ | ||||
| 			"type": "labelTitle", | ||||
| 			"position": {"x": 440, "y": 568}, | ||||
| 			"text" : "Enter Message" | ||||
| 		}, | ||||
| 		 | ||||
| 		{ | ||||
| 			"type": "areaFilled", | ||||
| 			"rect": {"x": 870, "y": 50, "w": 150, "h": 540} | ||||
| 		}, | ||||
| 		{ | ||||
| 			"type": "labelTitle", | ||||
| 			"position": {"x": 880, "y": 53}, | ||||
| 			"text" : "Player List" | ||||
| 		}, | ||||
| 		 | ||||
| 		{ | ||||
| 			"type": "button", | ||||
| 			"position": {"x": 940, "y": 10}, | ||||
| 			"image": "settingsWindow/button80", | ||||
| 			"help": "core.help.288", | ||||
| 			"callback": "closeWindow", | ||||
| 			"hotkey": "globalReturn", | ||||
| 			"items": | ||||
| 			[ | ||||
| 				{ | ||||
| 					"type": "label", | ||||
| 					"font": "medium", | ||||
| 					"alignment": "center", | ||||
| 					"color": "yellow", | ||||
| 					"text": "Exit" | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
| 		 | ||||
| 		{ | ||||
| 			"type": "button", | ||||
| 			"position": {"x": 828, "y": 565}, | ||||
| 			"image": "settingsWindow/button32", | ||||
| 			"help": "core.help.288", | ||||
| 			"callback": "closeWindow", | ||||
| 			"hotkey": "globalReturn", | ||||
| 			"items": | ||||
| 			[ | ||||
| 				{ | ||||
| 					"type": "label", | ||||
| 					"font": "medium", | ||||
| 					"alignment": "center", | ||||
| 					"color": "yellow", | ||||
| 					"text": ">" | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
| 		 | ||||
| 		{ | ||||
| 			"type": "button", | ||||
| 			"position": {"x": 10, "y": 520}, | ||||
| 			"image": "settingsWindow/button190", | ||||
| 			"help": "core.help.288", | ||||
| 			"callback": "closeWindow", | ||||
| 			"hotkey": "globalReturn", | ||||
| 			"items": | ||||
| 			[ | ||||
| 				{ | ||||
| 					"type": "label", | ||||
| 					"font": "medium", | ||||
| 					"alignment": "center", | ||||
| 					"color": "yellow", | ||||
| 					"text": "Start Public Game" | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
| 		 | ||||
| 		{ | ||||
| 			"type": "button", | ||||
| 			"position": {"x": 10, "y": 555}, | ||||
| 			"image": "settingsWindow/button190", | ||||
| 			"help": "core.help.288", | ||||
| 			"callback": "closeWindow", | ||||
| 			"hotkey": "globalReturn", | ||||
| 			"items": | ||||
| 			[ | ||||
| 				{ | ||||
| 					"type": "label", | ||||
| 					"font": "medium", | ||||
| 					"alignment": "center", | ||||
| 					"color": "yellow", | ||||
| 					"text": "Start Private Game" | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
|  | ||||
| 	] | ||||
| } | ||||
							
								
								
									
										47
									
								
								lib/network/NetworkClient.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								lib/network/NetworkClient.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| /* | ||||
|  * NetworkClient.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 "NetworkClient.h" | ||||
| #include "NetworkConnection.h" | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_BEGIN | ||||
|  | ||||
| NetworkClient::NetworkClient() | ||||
| 	: io(new NetworkService) | ||||
| 	, socket(new NetworkSocket(*io)) | ||||
| //	, timer(new NetworkTimer(*io)) | ||||
| { | ||||
| } | ||||
|  | ||||
| void NetworkClient::start(const std::string & host, uint16_t port) | ||||
| { | ||||
| 	boost::asio::ip::tcp::resolver resolver(*io); | ||||
| 	auto endpoints = resolver.resolve(host, std::to_string(port)); | ||||
|  | ||||
| 	boost::asio::async_connect(*socket, endpoints, std::bind(&NetworkClient::onConnected, this, _1)); | ||||
| } | ||||
|  | ||||
| void NetworkClient::onConnected(const boost::system::error_code & ec) | ||||
| { | ||||
| 	connection = std::make_shared<NetworkConnection>(socket); | ||||
| 	connection->start(); | ||||
| } | ||||
|  | ||||
| void NetworkClient::run() | ||||
| { | ||||
| 	io->run(); | ||||
| } | ||||
|  | ||||
| void NetworkClient::sendPacket(const std::vector<uint8_t> & message) | ||||
| { | ||||
| 	connection->sendPacket(message); | ||||
| } | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_END | ||||
							
								
								
									
										37
									
								
								lib/network/NetworkClient.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								lib/network/NetworkClient.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| /* | ||||
|  * NetworkClient.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 "NetworkDefines.h" | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_BEGIN | ||||
|  | ||||
| class NetworkConnection; | ||||
|  | ||||
| class DLL_LINKAGE NetworkClient : boost::noncopyable | ||||
| { | ||||
| 	std::shared_ptr<NetworkService> io; | ||||
| 	std::shared_ptr<NetworkSocket> socket; | ||||
| 	std::shared_ptr<NetworkConnection> connection; | ||||
| 	std::shared_ptr<NetworkTimer> timer; | ||||
|  | ||||
| 	void onConnected(const boost::system::error_code & ec); | ||||
| protected: | ||||
| 	virtual void onPacketReceived(const std::vector<uint8_t> & message) = 0; | ||||
| public: | ||||
| 	NetworkClient(); | ||||
| 	virtual ~NetworkClient() = default; | ||||
|  | ||||
| 	void start(const std::string & host, uint16_t port); | ||||
| 	void sendPacket(const std::vector<uint8_t> & message); | ||||
| 	void run(); | ||||
| }; | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_END | ||||
							
								
								
									
										97
									
								
								lib/network/NetworkConnection.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								lib/network/NetworkConnection.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,97 @@ | ||||
| /* | ||||
|  * NetworkConnection.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 "NetworkConnection.h" | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_BEGIN | ||||
|  | ||||
| NetworkConnection::NetworkConnection(const std::shared_ptr<NetworkSocket> & socket) | ||||
| 	: socket(socket) | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| void NetworkConnection::start() | ||||
| { | ||||
| 	boost::asio::async_read(*socket, | ||||
| 							readBuffer, | ||||
| 							boost::asio::transfer_exactly(messageHeaderSize), | ||||
| 							std::bind(&NetworkConnection::onHeaderReceived,this, _1)); | ||||
| } | ||||
|  | ||||
| void NetworkConnection::onHeaderReceived(const boost::system::error_code & ec) | ||||
| { | ||||
| 	uint32_t messageSize = readPacketSize(ec); | ||||
|  | ||||
| 	boost::asio::async_read(*socket, | ||||
| 							readBuffer, | ||||
| 							boost::asio::transfer_exactly(messageSize), | ||||
| 							std::bind(&NetworkConnection::onPacketReceived,this, _1, messageSize)); | ||||
| } | ||||
|  | ||||
| uint32_t NetworkConnection::readPacketSize(const boost::system::error_code & ec) | ||||
| { | ||||
| 	if (ec) | ||||
| 	{ | ||||
| 		throw std::runtime_error("Connection aborted!"); | ||||
| 	} | ||||
|  | ||||
| 	if (readBuffer.size() < messageHeaderSize) | ||||
| 	{ | ||||
| 		throw std::runtime_error("Failed to read header!"); | ||||
| 	} | ||||
|  | ||||
| 	std::istream istream(&readBuffer); | ||||
|  | ||||
| 	uint32_t messageSize; | ||||
| 	istream.read(reinterpret_cast<char *>(&messageSize), messageHeaderSize); | ||||
|  | ||||
| 	if (messageSize > messageMaxSize) | ||||
| 	{ | ||||
| 		throw std::runtime_error("Invalid packet size!"); | ||||
| 	} | ||||
|  | ||||
| 	return messageSize; | ||||
| } | ||||
|  | ||||
| void NetworkConnection::onPacketReceived(const boost::system::error_code & ec, uint32_t expectedPacketSize) | ||||
| { | ||||
| 	if (ec) | ||||
| 	{ | ||||
| 		throw std::runtime_error("Connection aborted!"); | ||||
| 	} | ||||
|  | ||||
| 	if (readBuffer.size() < expectedPacketSize) | ||||
| 	{ | ||||
| 		throw std::runtime_error("Failed to read header!"); | ||||
| 	} | ||||
|  | ||||
| 	std::vector<uint8_t> message; | ||||
|  | ||||
| 	message.resize(expectedPacketSize); | ||||
| 	std::istream istream(&readBuffer); | ||||
| 	istream.read(reinterpret_cast<char *>(message.data()), messageHeaderSize); | ||||
|  | ||||
| 	start(); | ||||
| } | ||||
|  | ||||
| void NetworkConnection::sendPacket(const std::vector<uint8_t> & message) | ||||
| { | ||||
| 	NetworkBuffer writeBuffer; | ||||
|  | ||||
| 	std::ostream ostream(&writeBuffer); | ||||
| 	uint32_t messageSize = message.size(); | ||||
| 	ostream.write(reinterpret_cast<const char *>(&messageSize), messageHeaderSize); | ||||
| 	ostream.write(reinterpret_cast<const char *>(message.data()), message.size()); | ||||
|  | ||||
| 	boost::asio::write(*socket, writeBuffer ); | ||||
| } | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_END | ||||
							
								
								
									
										36
									
								
								lib/network/NetworkConnection.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								lib/network/NetworkConnection.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| /* | ||||
|  * NetworkConnection.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 "NetworkDefines.h" | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_BEGIN | ||||
|  | ||||
| class DLL_LINKAGE NetworkConnection : boost::noncopyable | ||||
| { | ||||
| 	static const int messageHeaderSize = sizeof(uint32_t); | ||||
| 	static const int messageMaxSize = 1024; | ||||
|  | ||||
| 	std::shared_ptr<NetworkSocket> socket; | ||||
|  | ||||
| 	NetworkBuffer readBuffer; | ||||
|  | ||||
| 	void onHeaderReceived(const boost::system::error_code & ec); | ||||
| 	void onPacketReceived(const boost::system::error_code & ec, uint32_t expectedPacketSize); | ||||
| 	uint32_t readPacketSize(const boost::system::error_code & ec); | ||||
|  | ||||
| public: | ||||
| 	NetworkConnection(const std::shared_ptr<NetworkSocket> & socket); | ||||
|  | ||||
| 	void start(); | ||||
| 	void sendPacket(const std::vector<uint8_t> & message); | ||||
| }; | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_END | ||||
							
								
								
									
										22
									
								
								lib/network/NetworkDefines.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								lib/network/NetworkDefines.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| /* | ||||
|  * NetworkDefines.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 <boost/asio.hpp> | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_BEGIN | ||||
|  | ||||
| using NetworkService = boost::asio::io_service; | ||||
| using NetworkSocket = boost::asio::basic_stream_socket<boost::asio::ip::tcp>; | ||||
| using NetworkAcceptor = boost::asio::basic_socket_acceptor<boost::asio::ip::tcp>; | ||||
| using NetworkBuffer = boost::asio::streambuf; | ||||
| using NetworkTimer = boost::asio::steady_timer; | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_END | ||||
							
								
								
									
										63
									
								
								lib/network/NetworkServer.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								lib/network/NetworkServer.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | ||||
| /* | ||||
|  * NetworkServer.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 "NetworkServer.h" | ||||
| #include "NetworkConnection.h" | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_BEGIN | ||||
|  | ||||
| void NetworkServer::start(uint16_t port) | ||||
| { | ||||
| 	io = std::make_shared<boost::asio::io_service>(); | ||||
| 	acceptor = std::make_shared<NetworkAcceptor>(*io, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)); | ||||
|  | ||||
| 	startAsyncAccept(); | ||||
| } | ||||
|  | ||||
| void NetworkServer::startAsyncAccept() | ||||
| { | ||||
| 	std::shared_ptr<NetworkSocket> upcomingConnection = std::make_shared<NetworkSocket>(*io); | ||||
| 	acceptor->async_accept(*upcomingConnection, std::bind(&NetworkServer::connectionAccepted, this, upcomingConnection, _1)); | ||||
| } | ||||
|  | ||||
| void NetworkServer::run() | ||||
| { | ||||
| 	io->run(); | ||||
| } | ||||
|  | ||||
| void NetworkServer::connectionAccepted(std::shared_ptr<NetworkSocket> upcomingConnection, const boost::system::error_code & ec) | ||||
| { | ||||
| 	if(ec) | ||||
| 	{ | ||||
| 		logNetwork->info("Something wrong during accepting: %s", ec.message()); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	try | ||||
| 	{ | ||||
| 		logNetwork->info("We got a new connection! :)"); | ||||
| 		auto connection = std::make_shared<NetworkConnection>(upcomingConnection); | ||||
| 		connections.insert(connection); | ||||
| 		connection->start(); | ||||
| 	} | ||||
| 	catch(std::exception & e) | ||||
| 	{ | ||||
| 		logNetwork->error("Failure processing new connection! %s", e.what()); | ||||
| 	} | ||||
|  | ||||
| 	startAsyncAccept(); | ||||
| } | ||||
|  | ||||
| void NetworkServer::sendPacket(const std::shared_ptr<NetworkConnection> & connection, const std::vector<uint8_t> & message) | ||||
| { | ||||
| 	connection->sendPacket(message); | ||||
| } | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_END | ||||
							
								
								
									
										39
									
								
								lib/network/NetworkServer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								lib/network/NetworkServer.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| /* | ||||
|  * NetworkServer.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 "NetworkDefines.h" | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_BEGIN | ||||
|  | ||||
| class NetworkConnection; | ||||
|  | ||||
| class DLL_LINKAGE NetworkServer : boost::noncopyable | ||||
| { | ||||
| 	std::shared_ptr<NetworkService> io; | ||||
| 	std::shared_ptr<NetworkAcceptor> acceptor; | ||||
| 	std::set<std::shared_ptr<NetworkConnection>> connections; | ||||
|  | ||||
| 	void connectionAccepted(std::shared_ptr<NetworkSocket>, const boost::system::error_code & ec); | ||||
| 	void startAsyncAccept(); | ||||
| protected: | ||||
| 	virtual void onNewConnection(std::shared_ptr<NetworkConnection>) = 0; | ||||
| 	virtual void onPacketReceived(std::shared_ptr<NetworkConnection>, const std::vector<uint8_t> & message) = 0; | ||||
|  | ||||
| 	void sendPacket(const std::shared_ptr<NetworkConnection> &, const std::vector<uint8_t> & message); | ||||
|  | ||||
| public: | ||||
| 	virtual ~NetworkServer() = default; | ||||
|  | ||||
| 	void start(uint16_t port); | ||||
| 	void run(); | ||||
| }; | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_END | ||||
							
								
								
									
										39
									
								
								lobby/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								lobby/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| set(lobby_SRCS | ||||
| 		StdInc.cpp | ||||
| 		LobbyServer.cpp | ||||
| 		SQLiteConnection.cpp | ||||
| ) | ||||
|  | ||||
| set(lobby_HEADERS | ||||
| 		StdInc.h | ||||
| 		LobbyServer.h | ||||
| 		SQLiteConnection.h | ||||
| ) | ||||
|  | ||||
| assign_source_group(${lobby_SRCS} ${lobby_HEADERS}) | ||||
|  | ||||
| add_executable(vcmilobby ${lobby_SRCS} ${lobby_HEADERS}) | ||||
| set(lobby_LIBS vcmi) | ||||
|  | ||||
| if(CMAKE_SYSTEM_NAME MATCHES FreeBSD OR HAIKU) | ||||
| 	set(lobby_LIBS execinfo ${lobby_LIBS}) | ||||
| endif() | ||||
|  | ||||
| target_link_libraries(vcmilobby PRIVATE ${lobby_LIBS} ${SQLite3_LIBRARIES}) | ||||
|  | ||||
| target_include_directories(vcmilobby PRIVATE ${SQLite3_INCLUDE_DIRS}) | ||||
| target_include_directories(vcmilobby PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) | ||||
|  | ||||
| if(WIN32) | ||||
| 	set_target_properties(vcmilobby | ||||
| 		PROPERTIES | ||||
| 			OUTPUT_NAME "VCMI_lobby" | ||||
| 			PROJECT_LABEL "VCMI_lobby" | ||||
| 	) | ||||
| endif() | ||||
|  | ||||
| vcmi_set_output_dir(vcmilobby "") | ||||
| enable_pch(vcmilobby) | ||||
|  | ||||
| install(TARGETS vcmilobby DESTINATION ${BIN_DIR}) | ||||
|  | ||||
							
								
								
									
										45
									
								
								lobby/LobbyServer.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								lobby/LobbyServer.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| /* | ||||
|  * LobbyServer.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 "LobbyServer.h" | ||||
|  | ||||
| #include "SQLiteConnection.h" | ||||
|  | ||||
| #include <boost/uuid/uuid_generators.hpp> | ||||
| #include <boost/uuid/uuid_io.hpp> | ||||
|  | ||||
| static const std::string DATABASE_PATH = "~/vcmi.db"; | ||||
| static const int LISTENING_PORT = 30303; | ||||
| //static const std::string SERVER_NAME = GameConstants::VCMI_VERSION + " (server)"; | ||||
| //static const std::string SERVER_UUID = boost::uuids::to_string(boost::uuids::random_generator()()); | ||||
|  | ||||
| void LobbyServer::onNewConnection(std::shared_ptr<NetworkConnection>) | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| void LobbyServer::onPacketReceived(std::shared_ptr<NetworkConnection>, const std::vector<uint8_t> & message) | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| LobbyServer::LobbyServer() | ||||
| { | ||||
| 	database = SQLiteInstance::open(DATABASE_PATH, true); | ||||
|  | ||||
| } | ||||
|  | ||||
| int main(int argc, const char * argv[]) | ||||
| { | ||||
| 	LobbyServer server; | ||||
|  | ||||
| 	server.start(LISTENING_PORT); | ||||
| 	server.run(); | ||||
| } | ||||
							
								
								
									
										24
									
								
								lobby/LobbyServer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								lobby/LobbyServer.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| /* | ||||
|  * LobbyServer.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/NetworkServer.h" | ||||
|  | ||||
| class SQLiteInstance; | ||||
|  | ||||
| class LobbyServer : public NetworkServer | ||||
| { | ||||
| 	std::unique_ptr<SQLiteInstance> database; | ||||
|  | ||||
| 	void onNewConnection(std::shared_ptr<NetworkConnection>) override; | ||||
| 	void onPacketReceived(std::shared_ptr<NetworkConnection>, const std::vector<uint8_t> & message) override; | ||||
| public: | ||||
| 	LobbyServer(); | ||||
| }; | ||||
							
								
								
									
										197
									
								
								lobby/SQLiteConnection.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										197
									
								
								lobby/SQLiteConnection.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,197 @@ | ||||
| /* | ||||
|  * SQLiteConnection.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 "SQLiteConnection.h" | ||||
|  | ||||
| #include <sqlite3.h> | ||||
|  | ||||
| static void on_sqlite_error( sqlite3 * connection, [[maybe_unused]] int result ) | ||||
| { | ||||
| 	if ( result != SQLITE_OK ) | ||||
| 	{ | ||||
| 		printf( "sqlite error: %s\n", sqlite3_errmsg( connection ) ); | ||||
| 	} | ||||
|  | ||||
| 	assert( result == SQLITE_OK ); | ||||
| } | ||||
|  | ||||
| SQLiteStatement::SQLiteStatement( SQLiteInstance & instance, sqlite3_stmt * statement ): | ||||
| 	m_instance( instance ), | ||||
| 	m_statement( statement ) | ||||
| { } | ||||
|  | ||||
| SQLiteStatement::~SQLiteStatement( ) | ||||
| {  | ||||
| 	int result = sqlite3_finalize( m_statement ); | ||||
| 	on_sqlite_error( m_instance.m_connection, result ); | ||||
| } | ||||
|  | ||||
| bool SQLiteStatement::execute( ) | ||||
| {  | ||||
| 	int result = sqlite3_step( m_statement ); | ||||
|  | ||||
| 	switch ( result ) | ||||
| 	{ | ||||
| 		case SQLITE_DONE: | ||||
| 			return false; | ||||
| 		case SQLITE_ROW: | ||||
| 			return true; | ||||
| 		default: | ||||
| 			on_sqlite_error( m_instance.m_connection, result ); | ||||
| 			return false; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void SQLiteStatement::reset( ) | ||||
| { | ||||
| 	int result = sqlite3_reset( m_statement ); | ||||
| 	on_sqlite_error( m_instance.m_connection, result ); | ||||
| } | ||||
|  | ||||
| void SQLiteStatement::clear() | ||||
| { | ||||
| 	int result = sqlite3_clear_bindings(m_statement); | ||||
| 	on_sqlite_error(m_instance.m_connection, result); | ||||
| } | ||||
|  | ||||
| void SQLiteStatement::setBindSingle( size_t index, double const & value ) | ||||
| { | ||||
| 	int result = sqlite3_bind_double( m_statement, static_cast<int>(index), value ); | ||||
| 	on_sqlite_error( m_instance.m_connection, result ); | ||||
| } | ||||
|  | ||||
| void SQLiteStatement::setBindSingle(size_t index, uint8_t const & value) | ||||
| { | ||||
| 	int result = sqlite3_bind_int(m_statement, static_cast<int>(index), value); | ||||
| 	on_sqlite_error(m_instance.m_connection, result); | ||||
| } | ||||
|  | ||||
| void SQLiteStatement::setBindSingle(size_t index, uint16_t const & value) | ||||
| { | ||||
| 	int result = sqlite3_bind_int(m_statement, static_cast<int>(index), value); | ||||
| 	on_sqlite_error(m_instance.m_connection, result); | ||||
| } | ||||
| void SQLiteStatement::setBindSingle(size_t index, uint32_t const & value) | ||||
| { | ||||
| 	int result = sqlite3_bind_int(m_statement, static_cast<int>(index), value); | ||||
| 	on_sqlite_error(m_instance.m_connection, result); | ||||
| } | ||||
|  | ||||
| void SQLiteStatement::setBindSingle( size_t index, int32_t const & value ) | ||||
| { | ||||
| 	int result = sqlite3_bind_int( m_statement, static_cast<int>( index ), value ); | ||||
| 	on_sqlite_error( m_instance.m_connection, result ); | ||||
| } | ||||
|  | ||||
| void SQLiteStatement::setBindSingle( size_t index, int64_t const & value ) | ||||
| { | ||||
| 	int result = sqlite3_bind_int64( m_statement, static_cast<int>( index ), value ); | ||||
| 	on_sqlite_error( m_instance.m_connection, result ); | ||||
| } | ||||
|  | ||||
| void SQLiteStatement::setBindSingle( size_t index, std::string const & value ) | ||||
| { | ||||
| 	int result = sqlite3_bind_text( m_statement, static_cast<int>( index ), value.data(), static_cast<int>( value.size() ), SQLITE_STATIC ); | ||||
| 	on_sqlite_error( m_instance.m_connection, result ); | ||||
| } | ||||
|  | ||||
| void SQLiteStatement::setBindSingle( size_t index, char const * value ) | ||||
| { | ||||
| 	int result = sqlite3_bind_text( m_statement, static_cast<int>( index ), value, -1, SQLITE_STATIC ); | ||||
| 	on_sqlite_error( m_instance.m_connection, result ); | ||||
| } | ||||
|  | ||||
| void SQLiteStatement::getColumnSingle( size_t index, double & value ) | ||||
| { | ||||
| 	value = sqlite3_column_double( m_statement, static_cast<int>( index ) ); | ||||
| } | ||||
|  | ||||
| void SQLiteStatement::getColumnSingle( size_t index, uint8_t & value ) | ||||
| { | ||||
| 	value = static_cast<uint8_t>(sqlite3_column_int( m_statement, static_cast<int>( index ) )); | ||||
| } | ||||
|  | ||||
| void SQLiteStatement::getColumnSingle(size_t index, uint16_t & value) | ||||
| { | ||||
| 	value = static_cast<uint16_t>(sqlite3_column_int(m_statement, static_cast<int>(index))); | ||||
| } | ||||
|  | ||||
| void SQLiteStatement::getColumnSingle( size_t index, int32_t & value ) | ||||
| { | ||||
| 	value = sqlite3_column_int( m_statement, static_cast<int>( index ) ); | ||||
| } | ||||
|  | ||||
| void SQLiteStatement::getColumnSingle(size_t index, uint32_t & value) | ||||
| { | ||||
| 	value = sqlite3_column_int(m_statement, static_cast<int>(index)); | ||||
| } | ||||
|  | ||||
| void SQLiteStatement::getColumnSingle( size_t index, int64_t & value ) | ||||
| { | ||||
| 	value = sqlite3_column_int64( m_statement, static_cast<int>( index ) ); | ||||
| } | ||||
|  | ||||
| void SQLiteStatement::getColumnSingle( size_t index, std::string & value ) | ||||
| { | ||||
| 	auto value_raw = sqlite3_column_text(m_statement, static_cast<int>(index)); | ||||
| 	value = reinterpret_cast<char const*>( value_raw ); | ||||
| } | ||||
|  | ||||
| void SQLiteStatement::getColumnBlob(size_t index, std::byte * value, [[maybe_unused]] size_t capacity) | ||||
| { | ||||
| 	auto * blob_data = sqlite3_column_blob(m_statement, static_cast<int>(index)); | ||||
| 	size_t blob_size = sqlite3_column_bytes(m_statement, static_cast<int>(index)); | ||||
|  | ||||
| 	assert(blob_size < capacity); | ||||
|  | ||||
| 	std::copy_n(static_cast<std::byte const*>(blob_data), blob_size, value); | ||||
| 	value[blob_size] = std::byte(0); | ||||
| } | ||||
|  | ||||
| SQLiteInstancePtr SQLiteInstance::open( std::string const & db_path, bool allow_write) | ||||
| { | ||||
| 	int flags = allow_write ? (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE) : SQLITE_OPEN_READONLY; | ||||
|  | ||||
| 	sqlite3 * connection; | ||||
| 	int result = sqlite3_open_v2( db_path.c_str( ), &connection, flags, nullptr ); | ||||
|  | ||||
| 	on_sqlite_error( connection, result ); | ||||
|  | ||||
| 	assert(result == SQLITE_OK); | ||||
|  | ||||
| 	if ( result == SQLITE_OK ) | ||||
| 		return SQLiteInstancePtr( new SQLiteInstance( connection ) ); | ||||
|  | ||||
| 	sqlite3_close( connection ); | ||||
| 	return SQLiteInstancePtr( ); | ||||
| } | ||||
|  | ||||
| SQLiteInstance::SQLiteInstance( sqlite3 * connection ): | ||||
| 	m_connection( connection ) | ||||
| { } | ||||
|  | ||||
| SQLiteInstance::~SQLiteInstance( ) | ||||
| { | ||||
| 	int result = sqlite3_close( m_connection ); | ||||
| 	on_sqlite_error( m_connection, result ); | ||||
| } | ||||
|  | ||||
| SQLiteStatementPtr SQLiteInstance::prepare( std::string const & sql_text ) | ||||
| { | ||||
| 	sqlite3_stmt * statement; | ||||
| 	int result = sqlite3_prepare_v2( m_connection, sql_text.data(), static_cast<int>( sql_text.size()), &statement, nullptr ); | ||||
| 	 | ||||
| 	on_sqlite_error( m_connection, result ); | ||||
|  | ||||
| 	if ( result == SQLITE_OK ) | ||||
| 		return SQLiteStatementPtr( new SQLiteStatement( *this, statement ) ); | ||||
| 	sqlite3_finalize( statement ); | ||||
| 	return SQLiteStatementPtr( ); | ||||
| } | ||||
							
								
								
									
										99
									
								
								lobby/SQLiteConnection.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								lobby/SQLiteConnection.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,99 @@ | ||||
| /* | ||||
|  * SQLiteConnection.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 | ||||
|  | ||||
| typedef struct sqlite3 sqlite3; | ||||
| typedef struct sqlite3_stmt sqlite3_stmt; | ||||
|  | ||||
| class SQLiteInstance; | ||||
| class SQLiteStatement; | ||||
|  | ||||
| using SQLiteInstancePtr = std::unique_ptr< SQLiteInstance >; | ||||
| using SQLiteStatementPtr = std::unique_ptr< SQLiteStatement >; | ||||
|  | ||||
| class SQLiteStatement : boost::noncopyable | ||||
| { | ||||
| public: | ||||
| 	friend class SQLiteInstance; | ||||
|  | ||||
| 	bool execute( ); | ||||
| 	void reset( ); | ||||
| 	void clear( ); | ||||
|  | ||||
| 	~SQLiteStatement(); | ||||
|  | ||||
| 	template<typename ... Args > | ||||
| 	void setBinds( Args const & ... args ) | ||||
| 	{ | ||||
| 		setBindSingle( 1, args... ); // The leftmost SQL parameter has an index of 1 | ||||
| 	} | ||||
|  | ||||
| 	template<typename ... Args > | ||||
| 	void getColumns( Args & ... args ) | ||||
| 	{ | ||||
| 		getColumnSingle( 0, args... ); // The leftmost column of the result set has the index 0 | ||||
| 	} | ||||
|  | ||||
| private: | ||||
| 	void setBindSingle( size_t index, double const & value ); | ||||
| 	void setBindSingle( size_t index, uint8_t const & value ); | ||||
| 	void setBindSingle( size_t index, uint16_t const & value ); | ||||
| 	void setBindSingle( size_t index, uint32_t const & value ); | ||||
| 	void setBindSingle( size_t index, int32_t const & value ); | ||||
| 	void setBindSingle( size_t index, int64_t const & value ); | ||||
| 	void setBindSingle( size_t index, std::string const & value ); | ||||
| 	void setBindSingle( size_t index, char const * value ); | ||||
|  | ||||
| 	void getColumnSingle( size_t index, double & value ); | ||||
| 	void getColumnSingle( size_t index, uint8_t & value ); | ||||
| 	void getColumnSingle( size_t index, uint16_t & value ); | ||||
| 	void getColumnSingle( size_t index, uint32_t & value ); | ||||
| 	void getColumnSingle( size_t index, int32_t & value ); | ||||
| 	void getColumnSingle( size_t index, int64_t & value ); | ||||
| 	void getColumnSingle( size_t index, std::string & value ); | ||||
|  | ||||
| 	SQLiteStatement( SQLiteInstance & instance, sqlite3_stmt * statement ); | ||||
|  | ||||
| 	template<typename T, typename ... Args > | ||||
| 	void setBindSingle( size_t index, T const & arg, Args const & ... args ) | ||||
| 	{ | ||||
| 		setBindSingle( index, arg ); | ||||
| 		setBindSingle( index + 1, args... ); | ||||
| 	} | ||||
|  | ||||
| 	template<typename T, typename ... Args > | ||||
| 	void getColumnSingle( size_t index, T & arg, Args & ... args ) | ||||
| 	{ | ||||
| 		getColumnSingle( index, arg ); | ||||
| 		getColumnSingle( index + 1, args... ); | ||||
| 	} | ||||
|  | ||||
| 	void getColumnBlob(size_t index, std::byte * value, size_t capacity); | ||||
|  | ||||
| 	SQLiteInstance & m_instance; | ||||
| 	sqlite3_stmt * m_statement; | ||||
| }; | ||||
|  | ||||
| class SQLiteInstance : boost::noncopyable | ||||
| { | ||||
| public: | ||||
| 	friend class SQLiteStatement; | ||||
|  | ||||
| 	static SQLiteInstancePtr open(std::string const & db_path, bool allow_write ); | ||||
|  | ||||
| 	~SQLiteInstance( ); | ||||
|  | ||||
| 	SQLiteStatementPtr prepare( std::string const & statement ); | ||||
|  | ||||
| private: | ||||
| 	SQLiteInstance( sqlite3 * connection ); | ||||
|  | ||||
| 	sqlite3 * m_connection; | ||||
| }; | ||||
							
								
								
									
										2
									
								
								lobby/StdInc.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								lobby/StdInc.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| // Creates the precompiled header | ||||
| #include "StdInc.h" | ||||
							
								
								
									
										14
									
								
								lobby/StdInc.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								lobby/StdInc.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| /* | ||||
|  * StdInc.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 "../Global.h" | ||||
|  | ||||
| VCMI_LIB_USING_NAMESPACE | ||||
		Reference in New Issue
	
	Block a user