diff --git a/client/CMT.cpp b/client/CMT.cpp index 4c9fcff27..d5727bd97 100644 --- a/client/CMT.cpp +++ b/client/CMT.cpp @@ -11,7 +11,6 @@ // #include "StdInc.h" -#include #include #include @@ -251,11 +250,6 @@ int main(int argc, char * argv[]) *console->cb = processCommand; console->start(); #endif - - if(enet_initialize() != 0) - { - return EXIT_FAILURE; - } const bfs::path logPath = VCMIDirs::get().userLogsPath() / "VCMI_Client_log.txt"; logConfig = new CBasicLogConfigurator(logPath, console); diff --git a/client/CServerHandler.cpp b/client/CServerHandler.cpp index 61ecf52a2..499067e72 100644 --- a/client/CServerHandler.cpp +++ b/client/CServerHandler.cpp @@ -55,7 +55,6 @@ #include "../lib/serializer/Cast.h" #include -#include #ifdef VCMI_WINDOWS #include @@ -121,21 +120,27 @@ extern std::string NAME; CServerHandler::CServerHandler() : state(EClientState::NONE), mx(std::make_shared()), client(nullptr), loadMode(0), campaignStateToSend(nullptr), campaignServerRestartLock(false) { - enetClient = enet_host_create(NULL, 1, 2, 0, 0); uuid = boost::uuids::to_string(boost::uuids::random_generator()()); //read from file to restore last session if(!settings["server"]["uuid"].isNull() && !settings["server"]["uuid"].String().empty()) uuid = settings["server"]["uuid"].String(); applier = std::make_shared>(); registerTypesLobbyPacks(*applier); - - threadPollClient = std::make_shared(&CServerHandler::threadPoll, this); - threadPollClient->detach(); } CServerHandler::~CServerHandler() { - enet_host_destroy(enetClient); +} + +void CServerHandler::handleConnection(std::shared_ptr _c) +{ + c = std::make_shared(_c, NAME, uuid); + c->handler = std::make_shared(&CServerHandler::threadHandleConnection, this); +} + +void CServerHandler::handleDisconnection(std::shared_ptr _c) +{ + state = EClientState::DISCONNECTING; } void CServerHandler::resetStateForLobby(const StartInfo::EMode mode, const std::vector * names) @@ -179,50 +184,6 @@ void CServerHandler::resetStateForLobby(const StartInfo::EMode mode, const std:: #endif } -void CServerHandler::threadPoll() -{ - ENetEvent event; - while(true) - { - if(enet_host_service(enetClient, &event, 2) > 0) - { - switch(event.type) - { - case ENET_EVENT_TYPE_CONNECT: { - enet_packet_destroy(event.packet); - if(c && c->getPeer() == event.peer) - { - state = EClientState::CONNECTING; - } - break; - } - - case ENET_EVENT_TYPE_RECEIVE: { - if(c && c->getPeer() == event.peer) - { - c->dispatch(event.packet); - } - else - { - enet_packet_destroy(event.packet); - } - break; - } - - case ENET_EVENT_TYPE_DISCONNECT: - { - enet_packet_destroy(event.packet); - if(c && c->getPeer() == event.peer) - { - c.reset(); - } - break; - } - } - } - } -} - void CServerHandler::startLocalServerAndConnect() { /*auto errorMsg = CGI->generaltexth->localizedTexts["server"]["errors"]["existingProcess"].String(); @@ -320,21 +281,11 @@ void CServerHandler::startLocalServerAndConnect() void CServerHandler::justConnectToServer(const std::string & addr, const ui16 port) { - while(!c && state != EClientState::CONNECTION_CANCELLED) + while(!valid() && state != EClientState::CONNECTION_CANCELLED) { - try - { - logNetwork->info("Establishing connection..."); - c = std::make_shared(enetClient, - addr.size() ? addr : getHostAddress(), - port ? port : getHostPort(), - NAME, uuid); - } - catch(...) - { - logNetwork->error("\nCannot establish connection! Retrying within 1 second"); - boost::this_thread::sleep(boost::posix_time::seconds(1)); - } + logNetwork->info("Establishing connection..."); + init(port ? port : getHostPort(), addr.size() ? addr : getHostAddress()); + boost::this_thread::sleep(boost::posix_time::seconds(1)); } while(state != EClientState::CONNECTING) @@ -346,9 +297,6 @@ void CServerHandler::justConnectToServer(const std::string & addr, const ui16 po } boost::this_thread::sleep(boost::posix_time::milliseconds(100)); } - - c->init(); - c->handler = std::make_shared(&CServerHandler::threadHandleConnection, this); if(!addr.empty() && addr != getHostAddress()) { diff --git a/client/CServerHandler.h b/client/CServerHandler.h index 710db44d8..eb160578f 100644 --- a/client/CServerHandler.h +++ b/client/CServerHandler.h @@ -9,12 +9,11 @@ */ #pragma once -#include - #include "../lib/CStopWatch.h" #include "../lib/StartInfo.h" #include "../lib/CondSh.h" +#include "../lib/EnetService.h" VCMI_LIB_NAMESPACE_BEGIN @@ -74,7 +73,7 @@ public: }; /// structure to handle running server and connecting to it -class CServerHandler : public IServerAPI, public LobbyInfo +class CServerHandler : public IServerAPI, public LobbyInfo, public EnetService { std::shared_ptr> applier; @@ -82,15 +81,17 @@ class CServerHandler : public IServerAPI, public LobbyInfo std::list packsForLobbyScreen; //protected by mx std::vector myNames; - ENetHost * enetClient; void threadHandleConnection(); void threadRunServer(); - void threadPoll(); + void onServerFinished(); void sendLobbyPack(const CPackForLobby & pack) const override; public: + void handleDisconnection(std::shared_ptr) override; + void handleConnection(std::shared_ptr) override; + std::atomic state; //////////////////// // FIXME: Bunch of crutches to glue it all together @@ -104,8 +105,6 @@ public: std::unique_ptr th; std::shared_ptr threadRunLocalServer; - std::shared_ptr threadPollClient; - std::shared_ptr c; CClient * client; diff --git a/cmake_modules/VCMI_lib.cmake b/cmake_modules/VCMI_lib.cmake index 0c3266f48..483a7437f 100644 --- a/cmake_modules/VCMI_lib.cmake +++ b/cmake_modules/VCMI_lib.cmake @@ -179,6 +179,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE) ${MAIN_LIB_DIR}/CStack.cpp ${MAIN_LIB_DIR}/CThreadHelper.cpp ${MAIN_LIB_DIR}/CTownHandler.cpp + ${MAIN_LIB_DIR}/EnetService.cpp ${MAIN_LIB_DIR}/GameConstants.cpp ${MAIN_LIB_DIR}/HeroBonus.cpp ${MAIN_LIB_DIR}/IGameCallback.cpp @@ -420,6 +421,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE) ${MAIN_LIB_DIR}/CStopWatch.h ${MAIN_LIB_DIR}/CThreadHelper.h ${MAIN_LIB_DIR}/CTownHandler.h + ${MAIN_LIB_DIR}/EnetService.h ${MAIN_LIB_DIR}/FunctionList.h ${MAIN_LIB_DIR}/GameConstants.h ${MAIN_LIB_DIR}/HeroBonus.h diff --git a/lib/EnetService.cpp b/lib/EnetService.cpp new file mode 100644 index 000000000..105514017 --- /dev/null +++ b/lib/EnetService.cpp @@ -0,0 +1,270 @@ +// +// EnetService.cpp +// vcmi +// +// Created by nordsoft on 17.01.2023. +// + +#include "EnetService.h" +#include "StdInc.h" +#include "CThreadHelper.h" +#include + +EnetConnection::EnetConnection(ENetPeer * _peer): + peer(_peer) +{ + connected = false; +} + +EnetConnection::EnetConnection(ENetHost * client, const std::string & host, ui16 port) +{ + connected = false; + ENetAddress address; + enet_address_set_host(&address, host.c_str()); + address.port = port; + + peer = enet_host_connect(client, &address, 2, 0); + if(!peer) + { + throw std::runtime_error("Can't establish connection :("); + } +} + +EnetConnection::~EnetConnection() +{ + close(); + kill(); +} + +bool EnetConnection::isOpen() const +{ + return connected; +} + +void EnetConnection::open() +{ + connected = true; +} + +void EnetConnection::close() +{ + std::lock_guard guard(mutexWrite); + connected = false; + enet_peer_disconnect(peer, 0); +} + +void EnetConnection::kill() +{ + connected = false; + if(peer) + enet_peer_reset(peer); + peer = nullptr; +} + +const ENetPeer * EnetConnection::getPeer() const +{ + return peer; +} + +void EnetConnection::dispatch(ENetPacket * packet) +{ + std::lock_guard guard(mutexRead); + packets.push_back(packet); +} + +void EnetConnection::write(const void * data, unsigned size) +{ + if(size == 0 || !isOpen()) + return; + + std::lock_guard guard(mutexWrite); + ENetPacket * packet = enet_packet_create(data, size, ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, channel, packet); +} + +void EnetConnection::read(void * data, unsigned size) +{ + if(!size) + return; + + while(packets.empty()) + { + if(!isOpen()) + return; + + std::this_thread::sleep_for(std::chrono::milliseconds(READ_REFRESH)); + } + + std::lock_guard guard(mutexRead); + auto * packet = packets.front(); + packets.pop_front(); + + if(packet->dataLength > 0) + memcpy(data, packet->data, packet->dataLength); + + assert(size == packet->dataLength); + enet_packet_destroy(packet); +} + +EnetService::EnetService(): + service(nullptr), flagValid(false) +{ + if(enet_initialize() != 0) + throw std::runtime_error("Cannot initialize enet"); + + doMonitoring = true; + threadMonitoring = std::make_unique(&EnetService::monitor, this); + threadMonitoring->detach(); +} + +EnetService::~EnetService() +{ + stop(); + doMonitoring = false; + if(threadMonitoring) + threadMonitoring->join(); + + enet_deinitialize(); +} + +void EnetService::init(short port, const std::string & host) +{ + init(0); + active.insert(std::make_shared(service, host, port)); +} + +void EnetService::init(short port) +{ + ENetAddress address; + address.host = ENET_HOST_ANY; + address.port = port; + + service = enet_host_create(port ? &address : nullptr, port ? CONNECTIONS : 1, CHANNELS, 0, 0); + if(service) + flagValid = true; + + start(); +} + +void EnetService::start() +{ + stop(); + doPolling = true; + + if(service) + { + threadPolling = std::make_unique(&EnetService::poll, this); + threadPolling->detach(); + } +} + +void EnetService::monitor() +{ + setThreadName("EnetService::monitor"); + while(doMonitoring) + { + while(!disconnecting.empty()) + { + std::lock_guard guard(mutex); + if(disconnecting.front()->isOpen()) + disconnecting.front()->kill(); + handleDisconnection(disconnecting.front()); + disconnecting.pop_front(); + } + while(!connecting.empty()) + { + std::lock_guard guard(mutex); + connecting.front()->open(); + handleConnection(connecting.front()); + connecting.pop_front(); + } + if(service) + enet_host_flush(service); + std::this_thread::sleep_for(std::chrono::milliseconds(MONITOR_INTERVAL)); + } +} + +void EnetService::stop() +{ + doPolling = false; + if(threadPolling) + threadPolling->join(); + threadPolling.reset(); +} + +bool EnetService::valid() const +{ + return flagValid; +} + +void EnetService::poll() +{ + setThreadName("EnetService::poll"); + ENetEvent event; + while(doPolling) + { + if(enet_host_service(service, &event, POLL_INTERVAL) > 0) + { + switch(event.type) + { + case ENET_EVENT_TYPE_CONNECT: { + bool receiverFound = false; + for(auto & c : active) + { + if(c->getPeer() == event.peer) + { + std::lock_guard guard(mutex); + connecting.push_back(c); + receiverFound = true; + break; + } + } + + if(!receiverFound) + { + auto c = std::make_shared(event.peer); + active.insert(c); + std::lock_guard guard(mutex); + connecting.push_back(c); + } + + enet_packet_destroy(event.packet); + break; + } + + case ENET_EVENT_TYPE_RECEIVE: { + bool receiverFound = false; + for(auto & c : active) + { + if(c->getPeer() == event.peer) + { + c->dispatch(event.packet); + receiverFound = true; + break; + } + } + + if(!receiverFound) + enet_packet_destroy(event.packet); + + break; + } + + case ENET_EVENT_TYPE_DISCONNECT: { + for(auto c : active) + { + if(c->getPeer() == event.peer) + { + std::lock_guard guard(mutex); + disconnecting.push_back(c); + active.erase(c); + break; + } + } + enet_packet_destroy(event.packet); + break; + } + } + } + } +} diff --git a/lib/EnetService.h b/lib/EnetService.h new file mode 100644 index 000000000..3734400ec --- /dev/null +++ b/lib/EnetService.h @@ -0,0 +1,82 @@ +// +// EnetService.hpp +// vcmi +// +// Created by nordsoft on 17.01.2023. +// + +#pragma once +#include + +VCMI_LIB_NAMESPACE_BEGIN + +class DLL_LINKAGE EnetConnection +{ +private: + + const unsigned int READ_REFRESH = 20; //ms + + std::list packets; + int channel = 0; + ENetPeer * peer = nullptr; + std::atomic connected; + + std::mutex mutexRead, mutexWrite; + +public: + EnetConnection(ENetPeer * peer); + EnetConnection(ENetHost * client, const std::string & host, ui16 port); + virtual ~EnetConnection(); + + bool isOpen() const; + void open(); + void close(); + void kill(); + const ENetPeer * getPeer() const; + void dispatch(ENetPacket * packet); + + void write(const void * data, unsigned size); + void read(void * data, unsigned size); +}; + +class DLL_LINKAGE EnetService +{ +private: + + const unsigned int CHANNELS = 2; + const unsigned int CONNECTIONS = 16; + const unsigned int POLL_INTERVAL = 4; //ms + const unsigned int MONITOR_INTERVAL = 50; //ms + + ENetHost * service; + + std::set> active; + std::list> connecting, disconnecting; + + std::atomic doPolling, doMonitoring; + bool flagValid; + + std::unique_ptr threadPolling, threadMonitoring; + std::mutex mutex; + + void poll(); + void monitor(); + void start(); + +public: + + EnetService(); + virtual ~EnetService(); + + void init(short port); + void init(short port, const std::string & host); + + void stop(); + + bool valid() const; + + virtual void handleDisconnection(std::shared_ptr) = 0; + virtual void handleConnection(std::shared_ptr) = 0; +}; + +VCMI_LIB_NAMESPACE_END diff --git a/lib/serializer/Connection.cpp b/lib/serializer/Connection.cpp index a6c3873f5..194f56cd6 100644 --- a/lib/serializer/Connection.cpp +++ b/lib/serializer/Connection.cpp @@ -51,76 +51,30 @@ void CConnection::init() iser.fileVersion = SERIALIZATION_VERSION; } -CConnection::CConnection(ENetHost * _client, ENetPeer * _peer, std::string Name, std::string UUID) - : client(_client), peer(_peer), iser(this), oser(this), name(Name), uuid(UUID), connectionID(0), connected(false), channel(1) +CConnection::CConnection(std::shared_ptr _c, std::string Name, std::string UUID) + : enetConnection(_c), iser(this), oser(this), name(Name), uuid(UUID), connectionID(0), connected(false) { - //init(); -} - -CConnection::CConnection(ENetHost * _client, std::string host, ui16 port, std::string Name, std::string UUID) - : client(_client), iser(this), oser(this), name(Name), uuid(UUID), connectionID(0), connected(false), channel(0) -{ - ENetAddress address; - enet_address_set_host(&address, host.c_str()); - address.port = port; - - peer = enet_host_connect(client, &address, 2, 0); - if(peer == NULL) - { - throw std::runtime_error("Can't establish connection :("); - } -} - -void CConnection::dispatch(ENetPacket * packet) -{ - boost::unique_lock lock(mutexRead); - packets.push_back(packet); -} - -const ENetPeer * CConnection::getPeer() const -{ - return peer; + init(); } int CConnection::write(const void * data, unsigned size) { - if(size == 0) - return 0; - boost::unique_lock lock(mutexWrite); - ENetPacket * packet = enet_packet_create(data, size, ENET_PACKET_FLAG_RELIABLE); - enet_peer_send(peer, channel, packet); + if(connected) + enetConnection->write(data, size); return size; } int CConnection::read(void * data, unsigned size) { - const int timout = 1000; - if(size == 0) - return 0; - for(int i = 0; packets.empty() && (i < timout || connected); ++i) - { - boost::this_thread::sleep(boost::posix_time::milliseconds(10)); - } - boost::unique_lock lock(mutexRead); - auto * packet = packets.front(); - packets.pop_front(); - - if(packet->dataLength > 0) - memcpy(data, packet->data, packet->dataLength); - int ret = packet->dataLength; - assert(ret == size); - enet_packet_destroy(packet); - - return ret; + if(connected) + enetConnection->read(data, size); + return size; } CConnection::~CConnection() { if(handler) handler->join(); - - for(auto * packet : packets) - enet_packet_destroy(packet); close(); } @@ -134,11 +88,18 @@ CConnection & CConnection::operator&(const T &t) { return *this; } +const std::shared_ptr CConnection::getEnetConnection() const +{ + return enetConnection; +} + void CConnection::close() { - boost::unique_lock lock(mutexWrite); - enet_peer_disconnect(peer, 0); - enet_peer_reset(peer); + connected = false; + if(enetConnection->isOpen()) + enetConnection->close(); + else + enetConnection->kill(); } bool CConnection::isOpen() const @@ -179,9 +140,7 @@ void CConnection::sendPack(const CPack * pack) { logNetwork->trace("Sending a pack of type %s", typeid(*pack).name()); - oser & pack; - } void CConnection::disableStackSendingByID() diff --git a/lib/serializer/Connection.h b/lib/serializer/Connection.h index 6d26a925f..e38749785 100644 --- a/lib/serializer/Connection.h +++ b/lib/serializer/Connection.h @@ -9,10 +9,9 @@ */ #pragma once -#include - #include "BinaryDeserializer.h" #include "BinarySerializer.h" +#include "../EnetService.h" VCMI_LIB_NAMESPACE_BEGIN @@ -24,16 +23,13 @@ struct ConnectionBuffers; class DLL_LINKAGE CConnection : public IBinaryReader, public IBinaryWriter, public std::enable_shared_from_this { + std::shared_ptr enetConnection; + void reportState(vstd::CLoggerBase * out) override; int write(const void * data, unsigned size) override; int read(void * data, unsigned size) override; - std::list packets; - int channel; - ENetPeer * peer = nullptr; - ENetHost * client = nullptr; - BinaryDeserializer iser; BinarySerializer oser; @@ -51,12 +47,11 @@ public: int connectionID; std::shared_ptr handler; - CConnection(ENetHost * client, ENetPeer * peer, std::string Name, std::string UUID); - CConnection(ENetHost * client, std::string host, ui16 port, std::string Name, std::string UUID); - void init(); //must be called from outside after connection message received - void dispatch(ENetPacket * packet); - const ENetPeer * getPeer() const; + CConnection(std::shared_ptr, std::string Name, std::string UUID); + + const std::shared_ptr getEnetConnection() const; + void init(); void close(); bool isOpen() const; template diff --git a/server/CVCMIServer.cpp b/server/CVCMIServer.cpp index c9a47fbbc..9035128ab 100644 --- a/server/CVCMIServer.cpp +++ b/server/CVCMIServer.cpp @@ -127,18 +127,9 @@ CVCMIServer::CVCMIServer(boost::program_options::variables_map & opts) port = cmdLineOptions["port"].as(); logNetwork->info("Port %d will be used", port); - const int maxConnections = 8; - const int maxChannels = 2; - - ENetAddress address; - address.host = ENET_HOST_ANY; - address.port = port; - server = enet_host_create(&address, maxConnections, maxChannels, 0, 0); - if(!server) - { - logNetwork->error("Can't create host at port %d", port); - exit(0); - } + init(port); + if(!valid()) + state = EServerState::SHUTDOWN; logNetwork->info("Listening for connections at port %d", port); } @@ -151,8 +142,68 @@ CVCMIServer::~CVCMIServer() announceLobbyThread->join(); if(lobbyConnectionsThread) lobbyConnectionsThread->join(); +} + +void CVCMIServer::handleConnection(std::shared_ptr _c) +{ + auto c = *connections.insert(std::make_shared(_c, SERVER_NAME, uuid)).first; + c->handler = std::make_shared(&CVCMIServer::threadHandleClient, this, c); +} + +void CVCMIServer::handleDisconnection(std::shared_ptr _c) +{ + std::shared_ptr c; + for(auto cc : connections) + { + if(cc->getEnetConnection() == _c) + { + c = cc; + break; + } + } + assert(c); + c->close(); + connections -= c; + if(connections.empty() || hostClient == c) + { + state = EServerState::SHUTDOWN; + return; + } - enet_host_destroy(server); + PlayerReinitInterface startAiPack; + startAiPack.playerConnectionId = PlayerSettings::PLAYER_AI; + + for(auto it = playerNames.begin(); it != playerNames.end();) + { + if(it->second.connection != c->connectionID) + { + ++it; + continue; + } + + int id = it->first; + std::string playerLeftMsgText = boost::str(boost::format("%s (pid %d cid %d) left the game") % id % playerNames[id].name % c->connectionID); + announceTxt(playerLeftMsgText); //send lobby text, it will be ignored for non-lobby clients + auto * playerSettings = si->getPlayersSettings(id); + if(!playerSettings) + { + ++it; + continue; + } + + it = playerNames.erase(it); + setPlayerConnectedId(*playerSettings, PlayerSettings::PLAYER_AI); + + if(gh && si && state == EServerState::GAMEPLAY) + { + gh->playerMessage(playerSettings->color, playerLeftMsgText, ObjectInstanceID{}); + gh->connections[playerSettings->color].insert(hostClient); + startAiPack.players.push_back(playerSettings->color); + } + } + + if(!startAiPack.players.empty()) + gh->sendAndApply(&startAiPack); } void CVCMIServer::run() @@ -172,9 +223,6 @@ void CVCMIServer::run() } #endif - if(!lobbyConnectionsThread) - lobbyConnectionsThread = std::make_unique(&CVCMIServer::startAsyncAccept, this); - /*if(!remoteConnectionsThread && cmdLineOptions.count("lobby")) { remoteConnectionsThread = vstd::make_unique(&CVCMIServer::establishRemoteConnections, this); @@ -193,7 +241,6 @@ void CVCMIServer::run() while(state == EServerState::LOBBY || state == EServerState::GAMEPLAY_STARTING) { - connectionAccepted(); boost::this_thread::sleep(boost::posix_time::milliseconds(50)); } @@ -224,7 +271,7 @@ void CVCMIServer::connectToRemote(const std::string & addr, int port) try { logNetwork->info("Establishing connection..."); - c = std::make_shared(server, addr, port, SERVER_NAME, uuid); + //c = std::make_shared(server, addr, port, SERVER_NAME, uuid); } catch(...) { @@ -316,72 +363,6 @@ void CVCMIServer::startGameImmidiately() state = EServerState::GAMEPLAY; } -void CVCMIServer::startAsyncAccept() -{ - ENetEvent event; - while(state != EServerState::SHUTDOWN) - { - if(enet_host_service(server, &event, 2) > 0) - { - switch(event.type) - { - case ENET_EVENT_TYPE_CONNECT: { - if(state == EServerState::LOBBY) - { - upcomingConnection = std::make_shared(server, event.peer, SERVER_NAME, uuid); - connections.insert(upcomingConnection); - } - enet_packet_destroy(event.packet); - break; - } - - case ENET_EVENT_TYPE_RECEIVE: { - - bool receiverFound = false; - for(auto & c : connections) - { - if(c->getPeer() == event.peer) - { - c->dispatch(event.packet); - receiverFound = true; - break; - } - } - - if(!receiverFound) - enet_packet_destroy(event.packet); - - break; - } - - case ENET_EVENT_TYPE_DISCONNECT: { - enet_packet_destroy(event.packet); - for(auto & c : connections) - { - if(c->getPeer() == event.peer) - { - clientDisconnected(c); - break; - } - } - break; - - } - } - } - } -} - -void CVCMIServer::connectionAccepted() -{ - if(upcomingConnection) - { - upcomingConnection->init(); - upcomingConnection->handler = std::make_shared(&CVCMIServer::threadHandleClient, this, upcomingConnection); - upcomingConnection.reset(); - } -} - void CVCMIServer::threadHandleClient(std::shared_ptr c) { setThreadName("CVCMIServer::handleConnection"); @@ -555,51 +536,6 @@ void CVCMIServer::clientConnected(std::shared_ptr c, std::vector c) -{ - connections -= c; - if(connections.empty() || hostClient == c) - { - state = EServerState::SHUTDOWN; - return; - } - - PlayerReinitInterface startAiPack; - startAiPack.playerConnectionId = PlayerSettings::PLAYER_AI; - - for(auto it = playerNames.begin(); it != playerNames.end();) - { - if(it->second.connection != c->connectionID) - { - ++it; - continue; - } - - int id = it->first; - std::string playerLeftMsgText = boost::str(boost::format("%s (pid %d cid %d) left the game") % id % playerNames[id].name % c->connectionID); - announceTxt(playerLeftMsgText); //send lobby text, it will be ignored for non-lobby clients - auto * playerSettings = si->getPlayersSettings(id); - if(!playerSettings) - { - ++it; - continue; - } - - it = playerNames.erase(it); - setPlayerConnectedId(*playerSettings, PlayerSettings::PLAYER_AI); - - if(gh && si && state == EServerState::GAMEPLAY) - { - gh->playerMessage(playerSettings->color, playerLeftMsgText, ObjectInstanceID{}); - gh->connections[playerSettings->color].insert(hostClient); - startAiPack.players.push_back(playerSettings->color); - } - } - - if(!startAiPack.players.empty()) - gh->sendAndApply(&startAiPack); -} - void CVCMIServer::reconnectPlayer(int connId) { PlayerReinitInterface startAiPack; @@ -1073,10 +1009,6 @@ static void handleCommandOptions(int argc, char * argv[], boost::program_options int main(int argc, char * argv[]) { #if !defined(VCMI_ANDROID) && !defined(SINGLE_PROCESS_APP) - if(enet_initialize() != 0) - { - return EXIT_FAILURE; - } // 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 @@ -1126,7 +1058,6 @@ int main(int argc, char * argv[]) #endif logConfig.deconfigure(); vstd::clear_pointer(VLC); - enet_deinitialize(); return 0; } diff --git a/server/CVCMIServer.h b/server/CVCMIServer.h index 4acf4ad52..93bf79921 100644 --- a/server/CVCMIServer.h +++ b/server/CVCMIServer.h @@ -11,7 +11,7 @@ #include "../lib/serializer/Connection.h" #include "../lib/StartInfo.h" -#include +#include "../lib/EnetService.h" #include @@ -44,7 +44,7 @@ enum class EServerState : ui8 SHUTDOWN }; -class CVCMIServer : public LobbyInfo +class CVCMIServer : public LobbyInfo, public EnetService { std::atomic restartGameplay; // FIXME: this is just a hack @@ -53,9 +53,10 @@ class CVCMIServer : public LobbyInfo std::shared_ptr> applier; std::unique_ptr announceLobbyThread, lobbyConnectionsThread, remoteConnectionsThread; - ENetHost * server; - public: + void handleDisconnection(std::shared_ptr) override; + void handleConnection(std::shared_ptr) override; + std::shared_ptr gh; std::atomic state; ui16 port; @@ -67,7 +68,6 @@ public: std::atomic currentClientId; std::atomic currentPlayerId; std::shared_ptr hostClient; - std::shared_ptr upcomingConnection; CVCMIServer(boost::program_options::variables_map & opts); ~CVCMIServer(); @@ -78,8 +78,6 @@ public: void establishRemoteConnections(); void connectToRemote(const std::string & addr, int port); - void startAsyncAccept(); - void connectionAccepted(); void threadHandleClient(std::shared_ptr c); void threadAnnounceLobby(); void handleReceivedPack(std::unique_ptr pack); @@ -95,7 +93,6 @@ public: void updateStartInfoOnMapChange(std::shared_ptr mapInfo, std::shared_ptr mapGenOpt = {}); void clientConnected(std::shared_ptr c, std::vector & names, std::string uuid, StartInfo::EMode mode); - void clientDisconnected(std::shared_ptr c); void reconnectPlayer(int connId); void updateAndPropagateLobbyState(); diff --git a/server/NetPacksLobbyServer.cpp b/server/NetPacksLobbyServer.cpp index 98a952aed..b03908c51 100644 --- a/server/NetPacksLobbyServer.cpp +++ b/server/NetPacksLobbyServer.cpp @@ -129,7 +129,6 @@ bool LobbyClientDisconnected::checkClientPermissions(CVCMIServer * srv) const bool LobbyClientDisconnected::applyOnServer(CVCMIServer * srv) { - srv->clientDisconnected(c); c->close(); return true; }