瀏覽代碼

Implemented option to run server as a thread with shared VLC

Ivan Savenko 1 年之前
父節點
當前提交
0d263c5571

+ 6 - 3
CMakeLists.txt

@@ -63,8 +63,9 @@ option(ENABLE_CCACHE "Speed up recompilation by caching previous compilations" O
 
 if(ANDROID)
 	set(ENABLE_STATIC_AI_LIBS ON)
+	set(ENABLE_LAUNCHER OFF)
 else()
-	option(ENABLE_STATIC_AI_LIBS "Add AI code into VCMI lib directly" ON)
+	option(ENABLE_STATIC_AI_LIBS "Build all libraries statically (NOT only AI)" OFF)
 	option(ENABLE_LAUNCHER "Enable compilation of launcher" ON)
 endif()
 
@@ -75,15 +76,17 @@ endif()
 
 if(APPLE_IOS OR ANDROID)
 	option(ENABLE_MONOLITHIC_INSTALL "Install everything in single directory on Linux and Mac" OFF) # Used for Snap packages and also useful for debugging
-	option(ENABLE_LOBBY "Enable compilation of lobby server" OFF)
 	set(ENABLE_SINGLE_APP_BUILD ON)
 	set(ENABLE_EDITOR OFF)
+	set(ENABLE_TEST OFF)
+	set(ENABLE_LOBBY OFF)
 	set(COPY_CONFIG_ON_BUILD OFF)
 else()
 	option(COPY_CONFIG_ON_BUILD "Copies config folder into output directory at building phase" ON)
 	option(ENABLE_EDITOR "Enable compilation of map editor" ON)
 	option(ENABLE_SINGLE_APP_BUILD "Builds client and launcher as single executable" OFF)
 	option(ENABLE_TEST "Enable compilation of unit tests" OFF)
+	option(ENABLE_LOBBY "Enable compilation of lobby server" OFF)
 endif()
 
 if(ENABLE_COLORIZED_COMPILER_OUTPUT)
@@ -240,7 +243,7 @@ if(ENABLE_EDITOR)
 endif()
 
 if(ENABLE_SINGLE_APP_BUILD)
-	add_definitions(-DSINGLE_PROCESS_APP=1)
+	add_definitions(-DENABLE_SINGLE_APP_BUILD)
 endif()
 
 if(APPLE_IOS)

+ 7 - 5
client/CMakeLists.txt

@@ -164,6 +164,7 @@ set(client_SRCS
 	HeroMovementController.cpp
 	NetPacksClient.cpp
 	NetPacksLobbyClient.cpp
+	ServerRunner.cpp
 )
 
 set(client_HEADERS
@@ -346,6 +347,7 @@ set(client_HEADERS
 	ClientNetPackVisitors.h
 	HeroMovementController.h
 	LobbyClientNetPackVisitors.h
+	ServerRunner.h
 	resource.h
 )
 
@@ -451,12 +453,12 @@ elseif(APPLE_IOS)
 	set(CMAKE_EXE_LINKER_FLAGS "-Wl,-e,_client_main")
 endif()
 
-if(ENABLE_SINGLE_APP_BUILD)
-	target_link_libraries(vcmiclient PRIVATE vcmiserver)
-	if(ENABLE_LAUNCHER)
-		target_link_libraries(vcmiclient PRIVATE vcmilauncher)
-	endif()
+target_link_libraries(vcmiclient PRIVATE vcmiservercommon)
+
+if(ENABLE_SINGLE_APP_BUILD AND ENABLE_LAUNCHER)
+	target_link_libraries(vcmiclient PRIVATE vcmilauncher)
 endif()
+
 target_link_libraries(vcmiclient PRIVATE
 		${VCMI_LIB_TARGET} SDL2::SDL2 SDL2::Image SDL2::Mixer SDL2::TTF
 )

+ 16 - 128
client/CServerHandler.cpp

@@ -12,6 +12,7 @@
 #include "CServerHandler.h"
 #include "Client.h"
 #include "CGameInfo.h"
+#include "ServerRunner.h"
 #include "CPlayerInterface.h"
 #include "gui/CGuiHandler.h"
 #include "gui/WindowHandler.h"
@@ -25,17 +26,6 @@
 #include "mainmenu/CPrologEpilogVideo.h"
 #include "mainmenu/CHighScoreScreen.h"
 
-#ifdef VCMI_ANDROID
-#include "../lib/CAndroidVMHelper.h"
-#elif defined(VCMI_IOS)
-#include "ios/utils.h"
-#include <dispatch/dispatch.h>
-#endif
-
-#ifdef SINGLE_PROCESS_APP
-#include "../server/CVCMIServer.h"
-#endif
-
 #include "../lib/CConfigHandler.h"
 #include "../lib/CGeneralTextHandler.h"
 #include "../lib/CThreadHelper.h"
@@ -61,16 +51,8 @@
 
 #include <vcmi/events/EventBus.h>
 
-#ifdef VCMI_WINDOWS
-#include <windows.h>
-#endif
-
 template<typename T> class CApplyOnLobby;
 
-#if defined(VCMI_ANDROID) && !defined(SINGLE_PROCESS_APP)
-extern std::atomic_bool androidTestServerReadyFlag;
-#endif
-
 class CBaseForLobbyApply
 {
 public:
@@ -195,67 +177,17 @@ INetworkHandler & CServerHandler::getNetworkHandler()
 
 void CServerHandler::startLocalServerAndConnect(bool connectToLobby)
 {
-	if(threadRunLocalServer.joinable())
-		threadRunLocalServer.join();
-
-	th->update();
-
-#if defined(SINGLE_PROCESS_APP)
-	boost::condition_variable cond;
-	std::vector<std::string> args{"--port=" + std::to_string(getLocalPort())};
-	if(connectToLobby)
-		args.push_back("--lobby");
-
-	threadRunLocalServer = boost::thread([&cond, args] {
-		setThreadName("CVCMIServer");
-		CVCMIServer::create(&cond, args);
-	});
-#elif defined(VCMI_ANDROID)
-	{
-		CAndroidVMHelper envHelper;
-		envHelper.callStaticVoidMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "startServer", true);
-	}
+#ifdef VCMI_MOBILE
+	// mobile apps can't spawn separate processes - only thread mode is available
+	serverRunner.reset(new ServerThreadRunner());
 #else
-	threadRunLocalServer = boost::thread(&CServerHandler::threadRunServer, this, connectToLobby); //runs server executable;
-#endif
-	logNetwork->trace("Setting up thread calling server: %d ms", th->getDiff());
-
-	th->update();
-
-#ifdef SINGLE_PROCESS_APP
-	{
-#ifdef VCMI_IOS
-		dispatch_sync(dispatch_get_main_queue(), ^{
-			iOS_utils::showLoadingIndicator();
-		});
-#endif
-
-		boost::mutex m;
-		boost::unique_lock<boost::mutex> lock{m};
-		logNetwork->info("waiting for server");
-		cond.wait(lock);
-		logNetwork->info("server is ready");
-
-#ifdef VCMI_IOS
-		dispatch_sync(dispatch_get_main_queue(), ^{
-			iOS_utils::hideLoadingIndicator();
-		});
-#endif
-	}
-#elif defined(VCMI_ANDROID)
-	logNetwork->info("waiting for server");
-	while(!androidTestServerReadyFlag.load())
-	{
-		logNetwork->info("still waiting...");
-		boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
-	}
-	logNetwork->info("waiting for server finished...");
-	androidTestServerReadyFlag = false;
+	if (settings["server"]["useProcess"].Bool())
+		serverRunner.reset(new ServerProcessRunner());
+	else
+		serverRunner.reset(new ServerThreadRunner());
 #endif
-	logNetwork->trace("Waiting for server: %d ms", th->getDiff());
-
-	th->update(); //put breakpoint here to attach to server before it does something stupid
 
+	serverRunner->start(getLocalPort(), connectToLobby);
 	connectToServer(getLocalHostname(), getLocalPort());
 
 	logNetwork->trace("\tConnecting to the server: %d ms", th->getDiff());
@@ -374,7 +306,7 @@ void CServerHandler::setState(EClientState newState)
 
 bool CServerHandler::isServerLocal() const
 {
-	return threadRunLocalServer.joinable();
+	return serverRunner != nullptr;
 }
 
 bool CServerHandler::isHost() const
@@ -758,7 +690,6 @@ void CServerHandler::startCampaignScenario(HighScoreParameter param, std::shared
 			}
 		};
 
-		threadRunLocalServer.join();
 		if(epilogue.hasPrologEpilog)
 		{
 			GH.windows().createAndPushWindow<CPrologEpilogVideo>(epilogue, finisher);
@@ -899,6 +830,12 @@ void CServerHandler::onPacketReceived(const std::shared_ptr<INetworkConnection>
 
 void CServerHandler::onDisconnected(const std::shared_ptr<INetworkConnection> & connection, const std::string & errorMessage)
 {
+	if (serverRunner)
+	{
+		serverRunner->wait();
+		serverRunner.reset();
+	}
+
 	if(getState() == EClientState::DISCONNECTING)
 	{
 		assert(networkConnection == nullptr);
@@ -942,55 +879,6 @@ void CServerHandler::visitForClient(CPackForClient & clientPack)
 	client->handlePack(&clientPack);
 }
 
-void CServerHandler::threadRunServer(bool connectToLobby)
-{
-#if !defined(VCMI_MOBILE)
-	setThreadName("runServer");
-	const std::string logName = (VCMIDirs::get().userLogsPath() / "server_log.txt").string();
-	std::string comm = VCMIDirs::get().serverPath().string()
-		+ " --port=" + std::to_string(getLocalPort())
-		+ " --run-by-client";
-	if(connectToLobby)
-		comm += " --lobby";
-
-	comm += " > \"" + logName + '\"';
-	logGlobal->info("Server command line: %s", comm);
-
-#ifdef VCMI_WINDOWS
-	int result = -1;
-	const auto bufSize = ::MultiByteToWideChar(CP_UTF8, 0, comm.c_str(), comm.size(), nullptr, 0);
-	if(bufSize > 0)
-	{
-		std::wstring wComm(bufSize, {});
-		const auto convertResult = ::MultiByteToWideChar(CP_UTF8, 0, comm.c_str(), comm.size(), &wComm[0], bufSize);
-		if(convertResult > 0)
-			result = ::_wsystem(wComm.c_str());
-		else
-			logNetwork->error("Error " + std::to_string(GetLastError()) + ": failed to convert server launch command to wide string: " + comm);
-	}
-	else
-		logNetwork->error("Error " + std::to_string(GetLastError()) + ": failed to obtain buffer length to convert server launch command to wide string : " + comm);
-#else
-	int result = std::system(comm.c_str());
-#endif
-	if (result == 0)
-	{
-		logNetwork->info("Server closed correctly");
-	}
-	else
-	{
-		boost::mutex::scoped_lock interfaceLock(GH.interfaceMutex);
-
-		if (getState() == EClientState::CONNECTING)
-		{
-			showServerError(CGI->generaltexth->translate("vcmi.server.errors.existingProcess"));
-			setState(EClientState::CONNECTION_CANCELLED); // stop attempts to reconnect
-		}
-		logNetwork->error("Error: server failed to close correctly or crashed!");
-		logNetwork->error("Check %s for more info", logName);
-	}
-#endif
-}
 
 void CServerHandler::sendLobbyPack(const CPackForLobby & pack) const
 {

+ 2 - 2
client/CServerHandler.h

@@ -36,6 +36,7 @@ VCMI_LIB_NAMESPACE_END
 class CClient;
 class CBaseForLobbyApply;
 class GlobalLobbyClient;
+class IServerRunner;
 
 class HighScoreCalculation;
 class HighScoreParameter;
@@ -100,17 +101,16 @@ class CServerHandler final : public IServerAPI, public LobbyInfo, public INetwor
 	std::shared_ptr<INetworkConnection> networkConnection;
 	std::unique_ptr<GlobalLobbyClient> lobbyClient;
 	std::unique_ptr<CApplier<CBaseForLobbyApply>> applier;
+	std::unique_ptr<IServerRunner> serverRunner;
 	std::shared_ptr<CMapInfo> mapToStart;
 	std::vector<std::string> myNames;
 	std::shared_ptr<HighScoreCalculation> highScoreCalc;
 
-	boost::thread threadRunLocalServer;
 	boost::thread threadNetwork;
 
 	std::atomic<EClientState> state;
 
 	void threadRunNetwork();
-	void threadRunServer(bool connectToLobby);
 
 	void sendLobbyPack(const CPackForLobby & pack) const override;
 

+ 0 - 20
client/Client.cpp

@@ -46,10 +46,6 @@
 
 #ifdef VCMI_ANDROID
 #include "lib/CAndroidVMHelper.h"
-
-#ifndef SINGLE_PROCESS_APP
-std::atomic_bool androidTestServerReadyFlag;
-#endif
 #endif
 
 ThreadSafeVector<int> CClient::waitingRequest;
@@ -718,22 +714,6 @@ void CClient::removeGUI() const
 }
 
 #ifdef VCMI_ANDROID
-#ifndef SINGLE_PROCESS_APP
-extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_notifyServerClosed(JNIEnv * env, jclass cls)
-{
-	logNetwork->info("Received server closed signal");
-	if (CSH) {
-		CSH->campaignServerRestartLock.setn(false);
-	}
-}
-
-extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_notifyServerReady(JNIEnv * env, jclass cls)
-{
-	logNetwork->info("Received server ready signal");
-	androidTestServerReadyFlag.store(true);
-}
-#endif
-
 extern "C" JNIEXPORT jboolean JNICALL Java_eu_vcmi_vcmi_NativeMethods_tryToSaveTheGame(JNIEnv * env, jclass cls)
 {
 	logGlobal->info("Received emergency save game request");

+ 96 - 0
client/ServerRunner.cpp

@@ -0,0 +1,96 @@
+/*
+ * ServerRunner.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 "ServerRunner.h"
+
+#include "../lib/VCMIDirs.h"
+#include "../lib/CThreadHelper.h"
+#include "../server/CVCMIServer.h"
+
+#ifndef VCMI_MOBILE
+#include <boost/process/child.hpp>
+#include <boost/process/io.hpp>
+#endif
+
+ServerThreadRunner::ServerThreadRunner() = default;
+ServerThreadRunner::~ServerThreadRunner() = default;
+ServerProcessRunner::ServerProcessRunner() = default;
+ServerProcessRunner::~ServerProcessRunner() = default;
+
+void ServerThreadRunner::start(uint16_t port, bool connectToLobby)
+{
+	setThreadName("runServer");
+
+	server = std::make_unique<CVCMIServer>(port, connectToLobby, true);
+
+	threadRunLocalServer = boost::thread([this]{
+		server->run();
+	});
+}
+
+void ServerThreadRunner::stop()
+{
+	server->setState(EServerState::SHUTDOWN);
+}
+
+int ServerThreadRunner::wait()
+{
+	threadRunLocalServer.join();
+	return 0;
+}
+
+void ServerProcessRunner::stop()
+{
+	child->terminate();
+}
+
+int ServerProcessRunner::wait()
+{
+	child->wait();
+
+	return child->exit_code();
+
+//	if (child->exit_code() == 0)
+//	{
+//		logNetwork->info("Server closed correctly");
+//	}
+//	else
+//	{
+//		boost::mutex::scoped_lock interfaceLock(GH.interfaceMutex);
+//
+//		if (getState() == EClientState::CONNECTING)
+//		{
+//			showServerError(CGI->generaltexth->translate("vcmi.server.errors.existingProcess"));
+//			setState(EClientState::CONNECTION_CANCELLED); // stop attempts to reconnect
+//		}
+//		logNetwork->error("Error: server failed to close correctly or crashed!");
+//		logNetwork->error("Check %s for more info", logName);
+//	}
+}
+
+void ServerProcessRunner::start(uint16_t port, bool connectToLobby)
+{
+	boost::filesystem::path serverPath = VCMIDirs::get().serverPath();
+	boost::filesystem::path logPath = VCMIDirs::get().userLogsPath() / "server_log.txt";
+	std::vector<std::string> args;
+	args.push_back("--port=" + std::to_string(port));
+	args.push_back("--run-by-client");
+	if(connectToLobby)
+		args.push_back("--lobby");
+
+	std::error_code ec;
+	child = std::make_unique<boost::process::child>(serverPath, args, ec, boost::process::std_out > logPath);
+
+	if (ec)
+		throw std::runtime_error("Failed to start server! Reason: " + ec.message());
+}
+
+

+ 57 - 0
client/ServerRunner.h

@@ -0,0 +1,57 @@
+/*
+ * ServerRunner.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
+
+class CVCMIServer;
+
+class IServerRunner
+{
+public:
+	virtual void start(uint16_t port, bool connectToLobby) = 0;
+	virtual void stop() = 0;
+	virtual int wait() = 0;
+
+	virtual ~IServerRunner() = default;
+};
+
+/// Server instance will run as a thread of client process
+class ServerThreadRunner : public IServerRunner, boost::noncopyable
+{
+	std::unique_ptr<CVCMIServer> server;
+	boost::thread threadRunLocalServer;
+public:
+	void start(uint16_t port, bool connectToLobby) override;
+	void stop() override;
+	int wait() override;
+
+	ServerThreadRunner();
+	~ServerThreadRunner();
+};
+
+#ifndef VCMI_MOBILE
+
+namespace boost::process {
+class child;
+}
+
+/// Server instance will run as a separate process
+class ServerProcessRunner : public IServerRunner, boost::noncopyable
+{
+	std::unique_ptr<boost::process::child> child;
+
+public:
+	void start(uint16_t port, bool connectToLobby) override;
+	void stop() override;
+	int wait() override;
+
+	ServerProcessRunner();
+	~ServerProcessRunner();
+};
+#endif

+ 0 - 12
client/mainmenu/CMainMenu.cpp

@@ -60,11 +60,6 @@
 #include "../../lib/CRandomGenerator.h"
 #include "../../lib/CondSh.h"
 
-#if defined(SINGLE_PROCESS_APP) && defined(VCMI_ANDROID)
-#include "../../server/CVCMIServer.h"
-#include <SDL.h>
-#endif
-
 std::shared_ptr<CMainMenu> CMM;
 ISelectionScreenInfo * SEL;
 
@@ -599,13 +594,6 @@ void CSimpleJoinScreen::onChange(const std::string & newText)
 
 void CSimpleJoinScreen::startConnection(const std::string & addr, ui16 port)
 {
-#if defined(SINGLE_PROCESS_APP) && defined(VCMI_ANDROID)
-	// in single process build server must use same JNIEnv as client
-	// as server runs in a separate thread, it must not attempt to search for Java classes (and they're already cached anyway)
-	// https://github.com/libsdl-org/SDL/blob/main/docs/README-android.md#threads-and-the-java-vm
-	CVCMIServer::reuseClientJNIEnv(SDL_AndroidGetJNIEnv());
-#endif
-
 	if(addr.empty())
 		CSH->startLocalServerAndConnect(false);
 	else

+ 5 - 1
lib/CMakeLists.txt

@@ -14,5 +14,9 @@ else()
 	add_main_lib(${VCMI_LIB_TARGET} SHARED)
 endif()
 
-target_compile_definitions(${VCMI_LIB_TARGET} PUBLIC VCMI_LIB_NAMESPACE=VCMI)
+# no longer necessary, but might be useful to keep in future
+# unfortunately at the moment tests do not support namespaced build, so enable only on some systems
+if(APPLE_IOS OR ANDROID)
+	target_compile_definitions(${VCMI_LIB_TARGET} PUBLIC VCMI_LIB_NAMESPACE=VCMI)
+endif()
 

+ 0 - 4
lib/VCMIDirs.cpp

@@ -368,11 +368,7 @@ bool IVCMIDirsUNIX::developmentMode() const
 {
 	// We want to be able to run VCMI from single directory. E.g to run from build output directory
 	const bool result = bfs::exists("AI") && bfs::exists("config") && bfs::exists("Mods") && bfs::exists("vcmiclient");
-#if SINGLE_PROCESS_APP
 	return result;
-#else
-	return result && bfs::exists("vcmiserver");
-#endif
 }
 
 bfs::path IVCMIDirsUNIX::clientPath() const { return binaryPath() / "vcmiclient"; }

+ 13 - 13
server/CMakeLists.txt

@@ -1,4 +1,4 @@
-set(libserver_SRCS
+set(vcmiservercommon_SRCS
 		StdInc.cpp
 
 		battles/BattleActionProcessor.cpp
@@ -24,7 +24,7 @@ set(libserver_SRCS
 		TurnTimerHandler.cpp
 )
 
-set(libserver_HEADERS
+set(vcmiservercommon_HEADERS
 		StdInc.h
 
 		battles/BattleActionProcessor.h
@@ -50,28 +50,28 @@ set(libserver_HEADERS
 		TurnTimerHandler.h
 )
 
-assign_source_group(${libserver_SRCS} ${libserver_HEADERS})
+assign_source_group(${vcmiservercommon_SRCS} ${vcmiservercommon_HEADERS})
 
-add_library(libserver STATIC ${libserver_SRCS} ${libserver_HEADERS})
-set(libserver_LIBS vcmi)
+add_library(vcmiservercommon STATIC ${vcmiservercommon_SRCS} ${vcmiservercommon_HEADERS})
+set(vcmiservercommon_LIBS vcmi)
 
 if(CMAKE_SYSTEM_NAME MATCHES FreeBSD OR HAIKU)
-	set(libserver_LIBS execinfo ${libserver_LIBS})
+	set(vcmiservercommon_LIBS execinfo ${vcmiservercommon_LIBS})
 endif()
 
-target_link_libraries(libserver PRIVATE ${libserver_LIBS} minizip::minizip)
+target_link_libraries(vcmiservercommon PRIVATE ${vcmiservercommon_LIBS} minizip::minizip)
 
-target_include_directories(libserver
+target_include_directories(vcmiservercommon
 	PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
 )
 
 if(WIN32)
-	set_target_properties(vcmiserver
+	set_target_properties(vcmiservercommon
 		PROPERTIES
-			OUTPUT_NAME "VCMI_libserver"
-			PROJECT_LABEL "VCMI_libserver"
+			OUTPUT_NAME "VCMI_vcmiservercommon"
+			PROJECT_LABEL "VCMI_vcmiservercommon"
 	)
 endif()
 
-vcmi_set_output_dir(libserver "")
-enable_pch(libserver)
+vcmi_set_output_dir(vcmiservercommon "")
+enable_pch(vcmiservercommon)

+ 9 - 14
server/CVCMIServer.cpp

@@ -116,10 +116,11 @@ public:
 	}
 };
 
-CVCMIServer::CVCMIServer(boost::program_options::variables_map & opts)
+CVCMIServer::CVCMIServer(uint16_t port, bool connectToLobby, bool runByClient)
 	: currentClientId(1)
 	, currentPlayerId(1)
-	, cmdLineOptions(opts)
+	, port(port)
+	, runByClient(runByClient)
 {
 	uuid = boost::uuids::to_string(boost::uuids::random_generator()());
 	logNetwork->trace("CVCMIServer created! UUID: %s", uuid);
@@ -128,7 +129,7 @@ CVCMIServer::CVCMIServer(boost::program_options::variables_map & opts)
 
 	networkHandler = INetworkHandler::createHandler();
 
-	if(cmdLineOptions.count("lobby"))
+	if(connectToLobby)
 		lobbyProcessor = std::make_unique<GlobalLobbyProcessor>(*this);
 	else
 		startAcceptingIncomingConnections();
@@ -138,10 +139,6 @@ 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);
 
 	networkServer = networkHandler->createServerTCP(*this);
@@ -197,15 +194,13 @@ std::shared_ptr<CConnection> CVCMIServer::findConnection(const std::shared_ptr<I
 	throw std::runtime_error("Unknown connection received in CVCMIServer::findConnection");
 }
 
+bool CVCMIServer::wasStartedByClient() const
+{
+	return runByClient;
+}
+
 void CVCMIServer::run()
 {
-#if defined(VCMI_ANDROID) && !defined(SINGLE_PROCESS_APP)
-	if(!restartGameplay)
-	{
-		CAndroidVMHelper vmHelper;
-		vmHelper.callStaticVoidMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "onServerReady");
-	}
-#endif
 	networkHandler->run();
 }
 

+ 4 - 17
server/CVCMIServer.h

@@ -12,12 +12,6 @@
 #include "../lib/network/NetworkInterface.h"
 #include "../lib/StartInfo.h"
 
-#include <boost/program_options/variables_map.hpp>
-
-#if defined(VCMI_ANDROID) && !defined(SINGLE_PROCESS_APP)
-#define VCMI_ANDROID_DUAL_PROCESS 1
-#endif
-
 VCMI_LIB_NAMESPACE_BEGIN
 
 class CMapInfo;
@@ -64,6 +58,8 @@ class CVCMIServer : public LobbyInfo, public INetworkServerListener, public INet
 
 	int currentClientId;
 	ui8 currentPlayerId;
+	uint16_t port;
+	bool runByClient;
 
 public:
 	/// List of all active connections
@@ -76,13 +72,13 @@ public:
 	void onTimer() override;
 
 	std::shared_ptr<CGameHandler> gh;
-	boost::program_options::variables_map cmdLineOptions;
 
-	CVCMIServer(boost::program_options::variables_map & opts);
+	CVCMIServer(uint16_t port, bool connectToLobby, bool runByClient);
 	~CVCMIServer();
 
 	void run();
 
+	bool wasStartedByClient() const;
 	bool prepareToStartGame();
 	void prepareToRestart();
 	void startGameImmediately();
@@ -131,13 +127,4 @@ public:
 	void setCampaignBonus(int bonusId);
 
 	ui8 getIdOfFirstUnallocatedPlayer() const;
-
-#if VCMI_ANDROID_DUAL_PROCESS
-	static void create();
-#elif defined(SINGLE_PROCESS_APP)
-	static void create(boost::condition_variable * cond, const std::vector<std::string> & args);
-# ifdef VCMI_ANDROID
-	static void reuseClientJNIEnv(void * jniEnv);
-# endif // VCMI_ANDROID
-#endif // VCMI_ANDROID_DUAL_PROCESS
 };

+ 1 - 1
server/NetPacksLobbyServer.cpp

@@ -81,7 +81,7 @@ void ClientPermissionsCheckerNetPackVisitor::visitLobbyClientDisconnected(LobbyC
 
 	if(pack.shutdownServer)
 	{
-		if(!srv.cmdLineOptions.count("run-by-client"))
+		if(!srv.wasStartedByClient())
 		{
 			result = false;
 			return;

+ 7 - 7
serverapp/CMakeLists.txt

@@ -1,20 +1,20 @@
-set(appserver_SRCS
+set(serverapp_SRCS
 		StdInc.cpp
 		EntryPoint.cpp
 )
 
-set(appserver_HEADERS
+set(serverapp_HEADERS
 		StdInc.h
 )
 
-assign_source_group(${appserver_SRCS} ${appserver_HEADERS})
-add_executable(vcmiserver ${appserver_SRCS} ${appserver_HEADERS})
-set(appserver_LIBS vcmi)
+assign_source_group(${serverapp_SRCS} ${serverapp_HEADERS})
+add_executable(vcmiserver ${serverapp_SRCS} ${serverapp_HEADERS})
+set(serverapp_LIBS vcmi)
 
 if(CMAKE_SYSTEM_NAME MATCHES FreeBSD OR HAIKU)
-	set(appserver_LIBS execinfo ${appserver_LIBS})
+	set(serverapp_LIBS execinfo ${serverapp_LIBS})
 endif()
-target_link_libraries(vcmiserver PRIVATE ${appserver_LIBS} minizip::minizip libserver)
+target_link_libraries(vcmiserver PRIVATE ${serverapp_LIBS} minizip::minizip vcmiservercommon)
 
 target_include_directories(vcmiserver
 	PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}

+ 6 - 71
serverapp/EntryPoint.cpp

@@ -16,12 +16,6 @@
 #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>
 
 const std::string SERVER_NAME_AFFIX = "server";
@@ -50,13 +44,8 @@ static void handleCommandOptions(int argc, const char * argv[], boost::program_o
 		}
 	}
 
-#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);
@@ -75,31 +64,14 @@ static void handleCommandOptions(int argc, const char * argv[], boost::program_o
 		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);
@@ -113,58 +85,21 @@ int main(int argc, const char * argv[])
 	std::srand(static_cast<uint32_t>(time(nullptr)));
 
 	{
-		CVCMIServer server(opts);
+		bool connectToLobby = opts.count("lobby");
+		bool runByClient = opts.count("runByClient");
+		uint16_t port = 3030;
+		if(opts.count("port"))
+			port = opts["port"].as<uint16_t>();
 
-#ifdef SINGLE_PROCESS_APP
-		boost::condition_variable * cond = reinterpret_cast<boost::condition_variable *>(const_cast<char *>(argv[0]));
-		cond->notify_one();
-#endif
+		CVCMIServer server(port, connectToLobby, runByClient);
 
 		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