From 0d263c557111e9f69f53c912ab5a4b7bc3905ce6 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Sat, 10 Feb 2024 23:56:02 +0200 Subject: [PATCH] Implemented option to run server as a thread with shared VLC --- CMakeLists.txt | 9 ++- client/CMakeLists.txt | 12 +-- client/CServerHandler.cpp | 144 ++++----------------------------- client/CServerHandler.h | 4 +- client/Client.cpp | 20 ----- client/ServerRunner.cpp | 96 ++++++++++++++++++++++ client/ServerRunner.h | 57 +++++++++++++ client/mainmenu/CMainMenu.cpp | 12 --- lib/CMakeLists.txt | 6 +- lib/VCMIDirs.cpp | 4 - server/CMakeLists.txt | 26 +++--- server/CVCMIServer.cpp | 23 +++--- server/CVCMIServer.h | 21 +---- server/NetPacksLobbyServer.cpp | 2 +- serverapp/CMakeLists.txt | 14 ++-- serverapp/EntryPoint.cpp | 77 ++---------------- 16 files changed, 229 insertions(+), 298 deletions(-) create mode 100644 client/ServerRunner.cpp create mode 100644 client/ServerRunner.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 489aa24fc..2b853427d 100644 --- a/CMakeLists.txt +++ b/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) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index bd5791476..195843198 100644 --- a/client/CMakeLists.txt +++ b/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 ) diff --git a/client/CServerHandler.cpp b/client/CServerHandler.cpp index 2899906a9..fdb4f6292 100644 --- a/client/CServerHandler.cpp +++ b/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 -#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 -#ifdef VCMI_WINDOWS -#include -#endif - template 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 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(); - }); + if (settings["server"]["useProcess"].Bool()) + serverRunner.reset(new ServerProcessRunner()); + else + serverRunner.reset(new ServerThreadRunner()); #endif - boost::mutex m; - boost::unique_lock 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; -#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(epilogue, finisher); @@ -899,6 +830,12 @@ void CServerHandler::onPacketReceived(const std::shared_ptr void CServerHandler::onDisconnected(const std::shared_ptr & 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 { diff --git a/client/CServerHandler.h b/client/CServerHandler.h index 59573676d..7b883de22 100644 --- a/client/CServerHandler.h +++ b/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 networkConnection; std::unique_ptr lobbyClient; std::unique_ptr> applier; + std::unique_ptr serverRunner; std::shared_ptr mapToStart; std::vector myNames; std::shared_ptr highScoreCalc; - boost::thread threadRunLocalServer; boost::thread threadNetwork; std::atomic state; void threadRunNetwork(); - void threadRunServer(bool connectToLobby); void sendLobbyPack(const CPackForLobby & pack) const override; diff --git a/client/Client.cpp b/client/Client.cpp index 9ff148e9e..00cbcbe9a 100644 --- a/client/Client.cpp +++ b/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 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"); diff --git a/client/ServerRunner.cpp b/client/ServerRunner.cpp new file mode 100644 index 000000000..891c0b134 --- /dev/null +++ b/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 +#include +#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(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 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(serverPath, args, ec, boost::process::std_out > logPath); + + if (ec) + throw std::runtime_error("Failed to start server! Reason: " + ec.message()); +} + + diff --git a/client/ServerRunner.h b/client/ServerRunner.h new file mode 100644 index 000000000..19b73191e --- /dev/null +++ b/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 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 child; + +public: + void start(uint16_t port, bool connectToLobby) override; + void stop() override; + int wait() override; + + ServerProcessRunner(); + ~ServerProcessRunner(); +}; +#endif diff --git a/client/mainmenu/CMainMenu.cpp b/client/mainmenu/CMainMenu.cpp index 4ff244b9b..e4d8fd207 100644 --- a/client/mainmenu/CMainMenu.cpp +++ b/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 -#endif - std::shared_ptr 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 diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index fc2f75b3c..2e66e204b 100644 --- a/lib/CMakeLists.txt +++ b/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() diff --git a/lib/VCMIDirs.cpp b/lib/VCMIDirs.cpp index 3c0692885..83bf7ee68 100644 --- a/lib/VCMIDirs.cpp +++ b/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"; } diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index 44d363f7a..6f7093ea4 100644 --- a/server/CMakeLists.txt +++ b/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) diff --git a/server/CVCMIServer.cpp b/server/CVCMIServer.cpp index 1ec3d3299..3af26c254 100644 --- a/server/CVCMIServer.cpp +++ b/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(*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(); logNetwork->info("Port %d will be used", port); networkServer = networkHandler->createServerTCP(*this); @@ -197,15 +194,13 @@ std::shared_ptr CVCMIServer::findConnection(const std::shared_ptrrun(); } diff --git a/server/CVCMIServer.h b/server/CVCMIServer.h index 63da18f76..bc19a097b 100644 --- a/server/CVCMIServer.h +++ b/server/CVCMIServer.h @@ -12,12 +12,6 @@ #include "../lib/network/NetworkInterface.h" #include "../lib/StartInfo.h" -#include - -#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 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 & args); -# ifdef VCMI_ANDROID - static void reuseClientJNIEnv(void * jniEnv); -# endif // VCMI_ANDROID -#endif // VCMI_ANDROID_DUAL_PROCESS }; diff --git a/server/NetPacksLobbyServer.cpp b/server/NetPacksLobbyServer.cpp index d312befdd..3695add5c 100644 --- a/server/NetPacksLobbyServer.cpp +++ b/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; diff --git a/serverapp/CMakeLists.txt b/serverapp/CMakeLists.txt index f3716198a..059e6132d 100644 --- a/serverapp/CMakeLists.txt +++ b/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} diff --git a/serverapp/EntryPoint.cpp b/serverapp/EntryPoint.cpp index 306706189..d1b937f87 100644 --- a/serverapp/EntryPoint.cpp +++ b/serverapp/EntryPoint.cpp @@ -16,12 +16,6 @@ #include "../lib/VCMIDirs.h" #include "../lib/VCMI_Lib.h" -#ifdef VCMI_ANDROID -#include -#include -#include "lib/CAndroidVMHelper.h" -#endif - #include 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(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(); -#ifdef SINGLE_PROCESS_APP - boost::condition_variable * cond = reinterpret_cast(const_cast(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 & args) -{ - std::vector argv = {cond}; - for(auto & a : args) - argv.push_back(a.c_str()); - main(argv.size(), reinterpret_cast(&*argv.begin())); -} - -#ifdef VCMI_ANDROID -void CVCMIServer::reuseClientJNIEnv(void * jniEnv) -{ - CAndroidVMHelper::initClassloader(jniEnv); - CAndroidVMHelper::alwaysUseLoadedClass = true; -} -#endif // VCMI_ANDROID -#endif // VCMI_ANDROID_DUAL_PROCESS