1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-22 03:39:45 +02:00

Implemented option to run server as a thread with shared VLC

This commit is contained in:
Ivan Savenko 2024-02-10 23:56:02 +02:00
parent c2286e5126
commit 0d263c5571
16 changed files with 229 additions and 298 deletions

View File

@ -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)

View File

@ -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
)

View File

@ -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();
});
if (settings["server"]["useProcess"].Bool())
serverRunner.reset(new ServerProcessRunner());
else
serverRunner.reset(new ServerThreadRunner());
#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;
#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
{

View File

@ -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;

View File

@ -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
client/ServerRunner.cpp Normal file
View File

@ -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
client/ServerRunner.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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"; }

View File

@ -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)

View File

@ -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();
}

View File

@ -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
};

View File

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

View File

@ -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}

View File

@ -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