mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-22 22:13:35 +02:00
Switch client-server communication to new API
This commit is contained in:
parent
de5227142b
commit
0a1153e1c6
@ -45,17 +45,17 @@
|
|||||||
#include "../lib/mapping/CMapInfo.h"
|
#include "../lib/mapping/CMapInfo.h"
|
||||||
#include "../lib/mapObjects/MiscObjects.h"
|
#include "../lib/mapObjects/MiscObjects.h"
|
||||||
#include "../lib/modding/ModIncompatibility.h"
|
#include "../lib/modding/ModIncompatibility.h"
|
||||||
|
#include "../lib/network/NetworkClient.h"
|
||||||
#include "../lib/rmg/CMapGenOptions.h"
|
#include "../lib/rmg/CMapGenOptions.h"
|
||||||
|
#include "../lib/serializer/Connection.h"
|
||||||
#include "../lib/filesystem/Filesystem.h"
|
#include "../lib/filesystem/Filesystem.h"
|
||||||
#include "../lib/registerTypes/RegisterTypesLobbyPacks.h"
|
#include "../lib/registerTypes/RegisterTypesLobbyPacks.h"
|
||||||
#include "../lib/serializer/Connection.h"
|
|
||||||
#include "../lib/serializer/CMemorySerializer.h"
|
#include "../lib/serializer/CMemorySerializer.h"
|
||||||
#include "../lib/UnlockGuard.h"
|
#include "../lib/UnlockGuard.h"
|
||||||
|
|
||||||
#include <boost/uuid/uuid.hpp>
|
#include <boost/uuid/uuid.hpp>
|
||||||
#include <boost/uuid/uuid_io.hpp>
|
#include <boost/uuid/uuid_io.hpp>
|
||||||
#include <boost/uuid/uuid_generators.hpp>
|
#include <boost/uuid/uuid_generators.hpp>
|
||||||
#include <boost/asio.hpp>
|
|
||||||
#include "../lib/serializer/Cast.h"
|
#include "../lib/serializer/Cast.h"
|
||||||
#include "LobbyClientNetPackVisitors.h"
|
#include "LobbyClientNetPackVisitors.h"
|
||||||
|
|
||||||
@ -131,8 +131,16 @@ public:
|
|||||||
static const std::string NAME_AFFIX = "client";
|
static const std::string NAME_AFFIX = "client";
|
||||||
static const std::string NAME = GameConstants::VCMI_VERSION + std::string(" (") + NAME_AFFIX + ')'; //application name
|
static const std::string NAME = GameConstants::VCMI_VERSION + std::string(" (") + NAME_AFFIX + ')'; //application name
|
||||||
|
|
||||||
|
CServerHandler::~CServerHandler() = default;
|
||||||
|
|
||||||
CServerHandler::CServerHandler()
|
CServerHandler::CServerHandler()
|
||||||
: state(EClientState::NONE), mx(std::make_shared<boost::recursive_mutex>()), client(nullptr), loadMode(0), campaignStateToSend(nullptr), campaignServerRestartLock(false)
|
: state(EClientState::NONE)
|
||||||
|
, mx(std::make_shared<boost::recursive_mutex>())
|
||||||
|
, networkClient(std::make_unique<NetworkClient>(*this))
|
||||||
|
, client(nullptr)
|
||||||
|
, loadMode(0)
|
||||||
|
, campaignStateToSend(nullptr)
|
||||||
|
, campaignServerRestartLock(false)
|
||||||
{
|
{
|
||||||
uuid = boost::uuids::to_string(boost::uuids::random_generator()());
|
uuid = boost::uuids::to_string(boost::uuids::random_generator()());
|
||||||
//read from file to restore last session
|
//read from file to restore last session
|
||||||
@ -161,7 +169,7 @@ void CServerHandler::resetStateForLobby(const StartInfo::EMode mode, const std::
|
|||||||
myNames.push_back(settings["general"]["playerName"].String());
|
myNames.push_back(settings["general"]["playerName"].String());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CServerHandler::startLocalServerAndConnect()
|
void CServerHandler::startLocalServerAndConnect(const std::function<void()> & onConnected)
|
||||||
{
|
{
|
||||||
if(threadRunLocalServer)
|
if(threadRunLocalServer)
|
||||||
threadRunLocalServer->join();
|
threadRunLocalServer->join();
|
||||||
@ -169,17 +177,13 @@ void CServerHandler::startLocalServerAndConnect()
|
|||||||
th->update();
|
th->update();
|
||||||
|
|
||||||
auto errorMsg = CGI->generaltexth->translate("vcmi.server.errors.existingProcess");
|
auto errorMsg = CGI->generaltexth->translate("vcmi.server.errors.existingProcess");
|
||||||
try
|
|
||||||
|
if (!checkNetworkPortIsFree(localhostAddress, getDefaultPort()))
|
||||||
{
|
{
|
||||||
CConnection testConnection(localhostAddress, getDefaultPort(), NAME, uuid);
|
|
||||||
logNetwork->error("Port is busy, check if another instance of vcmiserver is working");
|
logNetwork->error("Port is busy, check if another instance of vcmiserver is working");
|
||||||
CInfoWindow::showInfoDialog(errorMsg, {});
|
CInfoWindow::showInfoDialog(errorMsg, {});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch(std::runtime_error & error)
|
|
||||||
{
|
|
||||||
//no connection means that port is not busy and we can start local server
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(SINGLE_PROCESS_APP)
|
#if defined(SINGLE_PROCESS_APP)
|
||||||
boost::condition_variable cond;
|
boost::condition_variable cond;
|
||||||
@ -243,38 +247,15 @@ void CServerHandler::startLocalServerAndConnect()
|
|||||||
|
|
||||||
th->update(); //put breakpoint here to attach to server before it does something stupid
|
th->update(); //put breakpoint here to attach to server before it does something stupid
|
||||||
|
|
||||||
justConnectToServer(localhostAddress, 0);
|
justConnectToServer(localhostAddress, 0, onConnected);
|
||||||
|
|
||||||
logNetwork->trace("\tConnecting to the server: %d ms", th->getDiff());
|
logNetwork->trace("\tConnecting to the server: %d ms", th->getDiff());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CServerHandler::justConnectToServer(const std::string & addr, const ui16 port)
|
void CServerHandler::justConnectToServer(const std::string & addr, const ui16 port, const std::function<void()> & onConnected)
|
||||||
{
|
{
|
||||||
|
logNetwork->info("Establishing connection...");
|
||||||
state = EClientState::CONNECTING;
|
state = EClientState::CONNECTING;
|
||||||
while(!c && state != EClientState::CONNECTION_CANCELLED)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
logNetwork->info("Establishing connection...");
|
|
||||||
c = std::make_shared<CConnection>(
|
|
||||||
addr.size() ? addr : getHostAddress(),
|
|
||||||
port ? port : getHostPort(),
|
|
||||||
NAME, uuid);
|
|
||||||
}
|
|
||||||
catch(std::runtime_error & error)
|
|
||||||
{
|
|
||||||
logNetwork->warn("\nCannot establish connection. %s Retrying in 1 second", error.what());
|
|
||||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(1000));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(state == EClientState::CONNECTION_CANCELLED)
|
|
||||||
{
|
|
||||||
logNetwork->info("Connection aborted by player!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
c->handler = std::make_shared<boost::thread>(&CServerHandler::threadHandleConnection, this);
|
|
||||||
|
|
||||||
if(!addr.empty() && addr != getHostAddress())
|
if(!addr.empty() && addr != getHostAddress())
|
||||||
{
|
{
|
||||||
@ -286,13 +267,39 @@ void CServerHandler::justConnectToServer(const std::string & addr, const ui16 po
|
|||||||
Settings serverPort = settings.write["server"]["port"];
|
Settings serverPort = settings.write["server"]["port"];
|
||||||
serverPort->Integer() = port;
|
serverPort->Integer() = port;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
networkClient->start(addr.size() ? addr : getHostAddress(), port ? port : getHostPort());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CServerHandler::onConnectionFailed(const std::string & errorMessage)
|
||||||
|
{
|
||||||
|
if(state == EClientState::CONNECTION_CANCELLED)
|
||||||
|
{
|
||||||
|
logNetwork->info("Connection aborted by player!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
logNetwork->warn("\nCannot establish connection. %s Retrying in 1 second", errorMessage);
|
||||||
|
|
||||||
|
//FIXME: replace with asio timer
|
||||||
|
boost::this_thread::sleep_for(boost::chrono::milliseconds(1000));
|
||||||
|
|
||||||
|
//FIXME: pass parameters from initial attempt
|
||||||
|
networkClient->start(getHostAddress(), getHostPort());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CServerHandler::onConnectionEstablished()
|
||||||
|
{
|
||||||
|
c->enterLobbyConnectionMode();
|
||||||
|
sendClientConnecting();
|
||||||
|
|
||||||
|
//FIXME: call functor provided in CServerHandler::justConnectToServer
|
||||||
|
assert(0);
|
||||||
|
//onConnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CServerHandler::applyPacksOnLobbyScreen()
|
void CServerHandler::applyPacksOnLobbyScreen()
|
||||||
{
|
{
|
||||||
if(!c || !c->handler)
|
|
||||||
return;
|
|
||||||
|
|
||||||
boost::unique_lock<boost::recursive_mutex> lock(*mx);
|
boost::unique_lock<boost::recursive_mutex> lock(*mx);
|
||||||
while(!packsForLobbyScreen.empty())
|
while(!packsForLobbyScreen.empty())
|
||||||
{
|
{
|
||||||
@ -306,16 +313,6 @@ void CServerHandler::applyPacksOnLobbyScreen()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CServerHandler::stopServerConnection()
|
|
||||||
{
|
|
||||||
if(c->handler)
|
|
||||||
{
|
|
||||||
while(!c->handler->timed_join(boost::chrono::milliseconds(50)))
|
|
||||||
applyPacksOnLobbyScreen();
|
|
||||||
c->handler->join();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::set<PlayerColor> CServerHandler::getHumanColors()
|
std::set<PlayerColor> CServerHandler::getHumanColors()
|
||||||
{
|
{
|
||||||
return clientHumanColors(c->connectionID);
|
return clientHumanColors(c->connectionID);
|
||||||
@ -421,7 +418,6 @@ void CServerHandler::sendClientDisconnecting()
|
|||||||
{
|
{
|
||||||
// Network thread might be applying network pack at this moment
|
// Network thread might be applying network pack at this moment
|
||||||
auto unlockInterface = vstd::makeUnlockGuard(GH.interfaceMutex);
|
auto unlockInterface = vstd::makeUnlockGuard(GH.interfaceMutex);
|
||||||
c->close();
|
|
||||||
c.reset();
|
c.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -814,7 +810,7 @@ void CServerHandler::restoreLastSession()
|
|||||||
myNames.push_back(name.String());
|
myNames.push_back(name.String());
|
||||||
resetStateForLobby(StartInfo::LOAD_GAME, &myNames);
|
resetStateForLobby(StartInfo::LOAD_GAME, &myNames);
|
||||||
screenType = ESelectionScreen::loadGame;
|
screenType = ESelectionScreen::loadGame;
|
||||||
justConnectToServer(settings["server"]["server"].String(), settings["server"]["port"].Integer());
|
justConnectToServer(settings["server"]["server"].String(), settings["server"]["port"].Integer(), {});
|
||||||
};
|
};
|
||||||
|
|
||||||
auto cleanUpSession = []()
|
auto cleanUpSession = []()
|
||||||
@ -844,9 +840,9 @@ void CServerHandler::debugStartTest(std::string filename, bool save)
|
|||||||
screenType = ESelectionScreen::newGame;
|
screenType = ESelectionScreen::newGame;
|
||||||
}
|
}
|
||||||
if(settings["session"]["donotstartserver"].Bool())
|
if(settings["session"]["donotstartserver"].Bool())
|
||||||
justConnectToServer(localhostAddress, 3030);
|
justConnectToServer(localhostAddress, 3030, {});
|
||||||
else
|
else
|
||||||
startLocalServerAndConnect();
|
startLocalServerAndConnect({});
|
||||||
|
|
||||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
|
boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
|
||||||
|
|
||||||
@ -902,65 +898,49 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void CServerHandler::threadHandleConnection()
|
void CServerHandler::onPacketReceived(const std::vector<uint8_t> & message)
|
||||||
{
|
{
|
||||||
setThreadName("handleConnection");
|
CPack * pack = c->retrievePack(message);
|
||||||
c->enterLobbyConnectionMode();
|
if(state == EClientState::DISCONNECTING)
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
sendClientConnecting();
|
// FIXME: server shouldn't really send netpacks after it's tells client to disconnect
|
||||||
while(c && c->connected)
|
// Though currently they'll be delivered and might cause crash.
|
||||||
{
|
vstd::clear_pointer(pack);
|
||||||
while(state == EClientState::STARTING)
|
|
||||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(10));
|
|
||||||
|
|
||||||
CPack * pack = c->retrievePack();
|
|
||||||
if(state == EClientState::DISCONNECTING)
|
|
||||||
{
|
|
||||||
// FIXME: server shouldn't really send netpacks after it's tells client to disconnect
|
|
||||||
// Though currently they'll be delivered and might cause crash.
|
|
||||||
vstd::clear_pointer(pack);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ServerHandlerCPackVisitor visitor(*this);
|
|
||||||
pack->visit(visitor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//catch only asio exceptions
|
else
|
||||||
catch(const boost::system::system_error & e)
|
|
||||||
{
|
{
|
||||||
if(state == EClientState::DISCONNECTING)
|
ServerHandlerCPackVisitor visitor(*this);
|
||||||
|
pack->visit(visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CServerHandler::onDisconnected()
|
||||||
|
{
|
||||||
|
if(state == EClientState::DISCONNECTING)
|
||||||
|
{
|
||||||
|
logNetwork->info("Successfully closed connection to server, ending listening thread!");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logNetwork->error("Lost connection to server, ending listening thread! Connection has been closed");
|
||||||
|
|
||||||
|
if(client)
|
||||||
{
|
{
|
||||||
logNetwork->info("Successfully closed connection to server, ending listening thread!");
|
state = EClientState::DISCONNECTING;
|
||||||
|
|
||||||
|
GH.dispatchMainThread([]()
|
||||||
|
{
|
||||||
|
CSH->endGameplay();
|
||||||
|
GH.defActionsDef = 63;
|
||||||
|
CMM->menu->switchToTab("main");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (e.code() == boost::asio::error::eof)
|
auto lcd = new LobbyClientDisconnected();
|
||||||
logNetwork->error("Lost connection to server, ending listening thread! Connection has been closed");
|
lcd->clientId = c->connectionID;
|
||||||
else
|
boost::unique_lock<boost::recursive_mutex> lock(*mx);
|
||||||
logNetwork->error("Lost connection to server, ending listening thread! Reason: %s", e.what());
|
packsForLobbyScreen.push_back(lcd);
|
||||||
|
|
||||||
if(client)
|
|
||||||
{
|
|
||||||
state = EClientState::DISCONNECTING;
|
|
||||||
|
|
||||||
GH.dispatchMainThread([]()
|
|
||||||
{
|
|
||||||
CSH->endGameplay();
|
|
||||||
GH.defActionsDef = 63;
|
|
||||||
CMM->menu->switchToTab("main");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto lcd = new LobbyClientDisconnected();
|
|
||||||
lcd->clientId = c->connectionID;
|
|
||||||
boost::unique_lock<boost::recursive_mutex> lock(*mx);
|
|
||||||
packsForLobbyScreen.push_back(lcd);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include "../lib/CStopWatch.h"
|
#include "../lib/CStopWatch.h"
|
||||||
|
|
||||||
|
#include "../lib/network/NetworkListener.h"
|
||||||
#include "../lib/StartInfo.h"
|
#include "../lib/StartInfo.h"
|
||||||
#include "../lib/CondSh.h"
|
#include "../lib/CondSh.h"
|
||||||
|
|
||||||
@ -80,8 +81,10 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// structure to handle running server and connecting to it
|
/// structure to handle running server and connecting to it
|
||||||
class CServerHandler : public IServerAPI, public LobbyInfo
|
class CServerHandler : public IServerAPI, public LobbyInfo, public INetworkClientListener, boost::noncopyable
|
||||||
{
|
{
|
||||||
|
std::unique_ptr<NetworkClient> networkClient;
|
||||||
|
|
||||||
friend class ApplyOnLobbyHandlerNetPackVisitor;
|
friend class ApplyOnLobbyHandlerNetPackVisitor;
|
||||||
|
|
||||||
std::shared_ptr<CApplier<CBaseForLobbyApply>> applier;
|
std::shared_ptr<CApplier<CBaseForLobbyApply>> applier;
|
||||||
@ -95,12 +98,18 @@ class CServerHandler : public IServerAPI, public LobbyInfo
|
|||||||
|
|
||||||
std::shared_ptr<HighScoreCalculation> highScoreCalc;
|
std::shared_ptr<HighScoreCalculation> highScoreCalc;
|
||||||
|
|
||||||
void threadHandleConnection();
|
|
||||||
void threadRunServer();
|
void threadRunServer();
|
||||||
void onServerFinished();
|
void onServerFinished();
|
||||||
void sendLobbyPack(const CPackForLobby & pack) const override;
|
void sendLobbyPack(const CPackForLobby & pack) const override;
|
||||||
|
|
||||||
|
void onPacketReceived(const std::vector<uint8_t> & message) override;
|
||||||
|
void onConnectionFailed(const std::string & errorMessage) override;
|
||||||
|
void onConnectionEstablished() override;
|
||||||
|
void onDisconnected() override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
std::shared_ptr<CConnection> c;
|
||||||
|
|
||||||
std::atomic<EClientState> state;
|
std::atomic<EClientState> state;
|
||||||
////////////////////
|
////////////////////
|
||||||
// FIXME: Bunch of crutches to glue it all together
|
// FIXME: Bunch of crutches to glue it all together
|
||||||
@ -115,7 +124,6 @@ public:
|
|||||||
std::unique_ptr<CStopWatch> th;
|
std::unique_ptr<CStopWatch> th;
|
||||||
std::shared_ptr<boost::thread> threadRunLocalServer;
|
std::shared_ptr<boost::thread> threadRunLocalServer;
|
||||||
|
|
||||||
std::shared_ptr<CConnection> c;
|
|
||||||
CClient * client;
|
CClient * client;
|
||||||
|
|
||||||
CondSh<bool> campaignServerRestartLock;
|
CondSh<bool> campaignServerRestartLock;
|
||||||
@ -123,15 +131,15 @@ public:
|
|||||||
static const std::string localhostAddress;
|
static const std::string localhostAddress;
|
||||||
|
|
||||||
CServerHandler();
|
CServerHandler();
|
||||||
|
~CServerHandler();
|
||||||
|
|
||||||
std::string getHostAddress() const;
|
std::string getHostAddress() const;
|
||||||
ui16 getHostPort() const;
|
ui16 getHostPort() const;
|
||||||
|
|
||||||
void resetStateForLobby(const StartInfo::EMode mode, const std::vector<std::string> * names = nullptr);
|
void resetStateForLobby(const StartInfo::EMode mode, const std::vector<std::string> * names = nullptr);
|
||||||
void startLocalServerAndConnect();
|
void startLocalServerAndConnect(const std::function<void()> & onConnected);
|
||||||
void justConnectToServer(const std::string & addr, const ui16 port);
|
void justConnectToServer(const std::string & addr, const ui16 port, const std::function<void()> & onConnected);
|
||||||
void applyPacksOnLobbyScreen();
|
void applyPacksOnLobbyScreen();
|
||||||
void stopServerConnection();
|
|
||||||
|
|
||||||
// Helpers for lobby state access
|
// Helpers for lobby state access
|
||||||
std::set<PlayerColor> getHumanColors();
|
std::set<PlayerColor> getHumanColors();
|
||||||
|
@ -30,11 +30,12 @@
|
|||||||
#include "../lib/UnlockGuard.h"
|
#include "../lib/UnlockGuard.h"
|
||||||
#include "../lib/battle/BattleInfo.h"
|
#include "../lib/battle/BattleInfo.h"
|
||||||
#include "../lib/serializer/BinaryDeserializer.h"
|
#include "../lib/serializer/BinaryDeserializer.h"
|
||||||
|
#include "../lib/serializer/BinarySerializer.h"
|
||||||
|
#include "../lib/serializer/Connection.h"
|
||||||
#include "../lib/mapping/CMapService.h"
|
#include "../lib/mapping/CMapService.h"
|
||||||
#include "../lib/pathfinder/CGPathNode.h"
|
#include "../lib/pathfinder/CGPathNode.h"
|
||||||
#include "../lib/filesystem/Filesystem.h"
|
#include "../lib/filesystem/Filesystem.h"
|
||||||
#include "../lib/registerTypes/RegisterTypesClientPacks.h"
|
#include "../lib/registerTypes/RegisterTypesClientPacks.h"
|
||||||
#include "../lib/serializer/Connection.h"
|
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vcmi/events/EventBus.h>
|
#include <vcmi/events/EventBus.h>
|
||||||
|
@ -27,8 +27,8 @@
|
|||||||
#include "../CCallback.h"
|
#include "../CCallback.h"
|
||||||
#include "../lib/filesystem/Filesystem.h"
|
#include "../lib/filesystem/Filesystem.h"
|
||||||
#include "../lib/filesystem/FileInfo.h"
|
#include "../lib/filesystem/FileInfo.h"
|
||||||
#include "../lib/serializer/Connection.h"
|
|
||||||
#include "../lib/serializer/BinarySerializer.h"
|
#include "../lib/serializer/BinarySerializer.h"
|
||||||
|
#include "../lib/serializer/Connection.h"
|
||||||
#include "../lib/CGeneralTextHandler.h"
|
#include "../lib/CGeneralTextHandler.h"
|
||||||
#include "../lib/CHeroHandler.h"
|
#include "../lib/CHeroHandler.h"
|
||||||
#include "../lib/VCMI_Lib.h"
|
#include "../lib/VCMI_Lib.h"
|
||||||
|
@ -54,8 +54,6 @@ void ApplyOnLobbyHandlerNetPackVisitor::visitLobbyClientDisconnected(LobbyClient
|
|||||||
result = false;
|
result = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
handler.stopServerConnection();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplyOnLobbyScreenNetPackVisitor::visitLobbyClientDisconnected(LobbyClientDisconnected & pack)
|
void ApplyOnLobbyScreenNetPackVisitor::visitLobbyClientDisconnected(LobbyClientDisconnected & pack)
|
||||||
|
@ -47,7 +47,7 @@
|
|||||||
#include "../../lib/filesystem/Filesystem.h"
|
#include "../../lib/filesystem/Filesystem.h"
|
||||||
#include "../../lib/mapping/CMapInfo.h"
|
#include "../../lib/mapping/CMapInfo.h"
|
||||||
#include "../../lib/mapping/CMapHeader.h"
|
#include "../../lib/mapping/CMapHeader.h"
|
||||||
#include "../../lib/serializer/Connection.h"
|
#include "../../lib/CRandomGenerator.h"
|
||||||
|
|
||||||
ISelectionScreenInfo::ISelectionScreenInfo(ESelectionScreen ScreenType)
|
ISelectionScreenInfo::ISelectionScreenInfo(ESelectionScreen ScreenType)
|
||||||
: screenType(ScreenType)
|
: screenType(ScreenType)
|
||||||
|
@ -43,7 +43,6 @@
|
|||||||
#include "../../lib/mapping/CMapHeader.h"
|
#include "../../lib/mapping/CMapHeader.h"
|
||||||
#include "../../lib/mapping/MapFormat.h"
|
#include "../../lib/mapping/MapFormat.h"
|
||||||
#include "../../lib/TerrainHandler.h"
|
#include "../../lib/TerrainHandler.h"
|
||||||
#include "../../lib/serializer/Connection.h"
|
|
||||||
|
|
||||||
bool mapSorter::operator()(const std::shared_ptr<ElementInfo> aaa, const std::shared_ptr<ElementInfo> bbb)
|
bool mapSorter::operator()(const std::shared_ptr<ElementInfo> aaa, const std::shared_ptr<ElementInfo> bbb)
|
||||||
{
|
{
|
||||||
|
@ -45,7 +45,6 @@
|
|||||||
#include "../../lib/CGeneralTextHandler.h"
|
#include "../../lib/CGeneralTextHandler.h"
|
||||||
#include "../../lib/JsonNode.h"
|
#include "../../lib/JsonNode.h"
|
||||||
#include "../../lib/campaign/CampaignHandler.h"
|
#include "../../lib/campaign/CampaignHandler.h"
|
||||||
#include "../../lib/serializer/Connection.h"
|
|
||||||
#include "../../lib/serializer/CTypeList.h"
|
#include "../../lib/serializer/CTypeList.h"
|
||||||
#include "../../lib/filesystem/Filesystem.h"
|
#include "../../lib/filesystem/Filesystem.h"
|
||||||
#include "../../lib/filesystem/CCompressedStream.h"
|
#include "../../lib/filesystem/CCompressedStream.h"
|
||||||
@ -559,7 +558,7 @@ CSimpleJoinScreen::CSimpleJoinScreen(bool host)
|
|||||||
{
|
{
|
||||||
textTitle->setText(CGI->generaltexth->translate("vcmi.mainMenu.serverConnecting"));
|
textTitle->setText(CGI->generaltexth->translate("vcmi.mainMenu.serverConnecting"));
|
||||||
buttonOk->block(true);
|
buttonOk->block(true);
|
||||||
startConnectThread();
|
startConnection();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -582,7 +581,7 @@ void CSimpleJoinScreen::connectToServer()
|
|||||||
buttonOk->block(true);
|
buttonOk->block(true);
|
||||||
GH.stopTextInput();
|
GH.stopTextInput();
|
||||||
|
|
||||||
startConnectThread(inputAddress->getText(), boost::lexical_cast<ui16>(inputPort->getText()));
|
startConnection(inputAddress->getText(), boost::lexical_cast<ui16>(inputPort->getText()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSimpleJoinScreen::leaveScreen()
|
void CSimpleJoinScreen::leaveScreen()
|
||||||
@ -603,7 +602,7 @@ void CSimpleJoinScreen::onChange(const std::string & newText)
|
|||||||
buttonOk->block(inputAddress->getText().empty() || inputPort->getText().empty());
|
buttonOk->block(inputAddress->getText().empty() || inputPort->getText().empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSimpleJoinScreen::startConnectThread(const std::string & addr, ui16 port)
|
void CSimpleJoinScreen::startConnection(const std::string & addr, ui16 port)
|
||||||
{
|
{
|
||||||
#if defined(SINGLE_PROCESS_APP) && defined(VCMI_ANDROID)
|
#if defined(SINGLE_PROCESS_APP) && defined(VCMI_ANDROID)
|
||||||
// in single process build server must use same JNIEnv as client
|
// in single process build server must use same JNIEnv as client
|
||||||
@ -611,35 +610,31 @@ void CSimpleJoinScreen::startConnectThread(const std::string & addr, ui16 port)
|
|||||||
// https://github.com/libsdl-org/SDL/blob/main/docs/README-android.md#threads-and-the-java-vm
|
// https://github.com/libsdl-org/SDL/blob/main/docs/README-android.md#threads-and-the-java-vm
|
||||||
CVCMIServer::reuseClientJNIEnv(SDL_AndroidGetJNIEnv());
|
CVCMIServer::reuseClientJNIEnv(SDL_AndroidGetJNIEnv());
|
||||||
#endif
|
#endif
|
||||||
boost::thread connector(&CSimpleJoinScreen::connectThread, this, addr, port);
|
|
||||||
|
|
||||||
connector.detach();
|
auto const & onConnected = [this]()
|
||||||
}
|
{
|
||||||
|
// async call to prevent thread race
|
||||||
|
GH.dispatchMainThread([this](){
|
||||||
|
if(CSH->state == EClientState::CONNECTION_FAILED)
|
||||||
|
{
|
||||||
|
CInfoWindow::showInfoDialog(CGI->generaltexth->translate("vcmi.mainMenu.serverConnectionFailed"), {});
|
||||||
|
|
||||||
void CSimpleJoinScreen::connectThread(const std::string & addr, ui16 port)
|
textTitle->setText(CGI->generaltexth->translate("vcmi.mainMenu.serverAddressEnter"));
|
||||||
{
|
GH.startTextInput(inputAddress->pos);
|
||||||
setThreadName("connectThread");
|
buttonOk->block(false);
|
||||||
if(!addr.length())
|
}
|
||||||
CSH->startLocalServerAndConnect();
|
|
||||||
|
if(GH.windows().isTopWindow(this))
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if(addr.empty())
|
||||||
|
CSH->startLocalServerAndConnect(onConnected);
|
||||||
else
|
else
|
||||||
CSH->justConnectToServer(addr, port);
|
CSH->justConnectToServer(addr, port, onConnected);
|
||||||
|
|
||||||
// async call to prevent thread race
|
|
||||||
GH.dispatchMainThread([this](){
|
|
||||||
if(CSH->state == EClientState::CONNECTION_FAILED)
|
|
||||||
{
|
|
||||||
CInfoWindow::showInfoDialog(CGI->generaltexth->translate("vcmi.mainMenu.serverConnectionFailed"), {});
|
|
||||||
|
|
||||||
textTitle->setText(CGI->generaltexth->translate("vcmi.mainMenu.serverAddressEnter"));
|
|
||||||
GH.startTextInput(inputAddress->pos);
|
|
||||||
buttonOk->block(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(GH.windows().isTopWindow(this))
|
|
||||||
{
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CLoadingScreen::CLoadingScreen()
|
CLoadingScreen::CLoadingScreen()
|
||||||
|
@ -177,8 +177,7 @@ class CSimpleJoinScreen : public WindowBase
|
|||||||
void connectToServer();
|
void connectToServer();
|
||||||
void leaveScreen();
|
void leaveScreen();
|
||||||
void onChange(const std::string & newText);
|
void onChange(const std::string & newText);
|
||||||
void startConnectThread(const std::string & addr = {}, ui16 port = 0);
|
void startConnection(const std::string & addr = {}, ui16 port = 0);
|
||||||
void connectThread(const std::string & addr, ui16 port);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CSimpleJoinScreen(bool host = true);
|
CSimpleJoinScreen(bool host = true);
|
||||||
|
@ -18,12 +18,12 @@
|
|||||||
|
|
||||||
#include "../../lib/MetaString.h"
|
#include "../../lib/MetaString.h"
|
||||||
#include "../../lib/CConfigHandler.h"
|
#include "../../lib/CConfigHandler.h"
|
||||||
|
#include "../../lib/network/NetworkClient.h"
|
||||||
|
|
||||||
LobbyClient::LobbyClient(LobbyWindow * window)
|
LobbyClient::LobbyClient(LobbyWindow * window)
|
||||||
: window(window)
|
: networkClient(std::make_unique<NetworkClient>(*this))
|
||||||
{
|
, window(window)
|
||||||
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
static std::string getCurrentTimeFormatted(int timeOffsetSeconds = 0)
|
static std::string getCurrentTimeFormatted(int timeOffsetSeconds = 0)
|
||||||
{
|
{
|
||||||
@ -100,7 +100,22 @@ void LobbyClient::sendMessage(const JsonNode & data)
|
|||||||
|
|
||||||
std::vector<uint8_t> payloadBuffer(payloadBegin, payloadEnd);
|
std::vector<uint8_t> payloadBuffer(payloadBegin, payloadEnd);
|
||||||
|
|
||||||
sendPacket(payloadBuffer);
|
networkClient->sendPacket(payloadBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LobbyClient::start(const std::string & host, uint16_t port)
|
||||||
|
{
|
||||||
|
networkClient->start(host, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LobbyClient::run()
|
||||||
|
{
|
||||||
|
networkClient->run();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LobbyClient::poll()
|
||||||
|
{
|
||||||
|
networkClient->poll();
|
||||||
}
|
}
|
||||||
|
|
||||||
LobbyWidget::LobbyWidget(LobbyWindow * window)
|
LobbyWidget::LobbyWidget(LobbyWindow * window)
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
#include "../gui/InterfaceObjectConfigurable.h"
|
#include "../gui/InterfaceObjectConfigurable.h"
|
||||||
#include "../windows/CWindowObject.h"
|
#include "../windows/CWindowObject.h"
|
||||||
|
|
||||||
#include "../../lib/network/NetworkClient.h"
|
#include "../../lib/network/NetworkListener.h"
|
||||||
|
|
||||||
class LobbyWindow;
|
class LobbyWindow;
|
||||||
|
|
||||||
@ -27,8 +27,9 @@ public:
|
|||||||
std::shared_ptr<CTextBox> getGameChat();
|
std::shared_ptr<CTextBox> getGameChat();
|
||||||
};
|
};
|
||||||
|
|
||||||
class LobbyClient : public NetworkClient
|
class LobbyClient : public INetworkClientListener
|
||||||
{
|
{
|
||||||
|
std::unique_ptr<NetworkClient> networkClient;
|
||||||
LobbyWindow * window;
|
LobbyWindow * window;
|
||||||
|
|
||||||
void onPacketReceived(const std::vector<uint8_t> & message) override;
|
void onPacketReceived(const std::vector<uint8_t> & message) override;
|
||||||
@ -40,6 +41,10 @@ public:
|
|||||||
explicit LobbyClient(LobbyWindow * window);
|
explicit LobbyClient(LobbyWindow * window);
|
||||||
|
|
||||||
void sendMessage(const JsonNode & data);
|
void sendMessage(const JsonNode & data);
|
||||||
|
void start(const std::string & host, uint16_t port);
|
||||||
|
void run();
|
||||||
|
void poll();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class LobbyWindow : public CWindowObject
|
class LobbyWindow : public CWindowObject
|
||||||
|
@ -478,6 +478,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
|
|||||||
${MAIN_LIB_DIR}/network/NetworkClient.h
|
${MAIN_LIB_DIR}/network/NetworkClient.h
|
||||||
${MAIN_LIB_DIR}/network/NetworkConnection.h
|
${MAIN_LIB_DIR}/network/NetworkConnection.h
|
||||||
${MAIN_LIB_DIR}/network/NetworkDefines.h
|
${MAIN_LIB_DIR}/network/NetworkDefines.h
|
||||||
|
${MAIN_LIB_DIR}/network/NetworkListener.h
|
||||||
${MAIN_LIB_DIR}/network/NetworkServer.h
|
${MAIN_LIB_DIR}/network/NetworkServer.h
|
||||||
|
|
||||||
${MAIN_LIB_DIR}/networkPacks/ArtifactLocation.h
|
${MAIN_LIB_DIR}/networkPacks/ArtifactLocation.h
|
||||||
|
@ -47,8 +47,6 @@
|
|||||||
#include "RiverHandler.h"
|
#include "RiverHandler.h"
|
||||||
#include "TerrainHandler.h"
|
#include "TerrainHandler.h"
|
||||||
|
|
||||||
#include "serializer/Connection.h"
|
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
void CPrivilegedInfoCallback::getFreeTiles(std::vector<int3> & tiles) const
|
void CPrivilegedInfoCallback::getFreeTiles(std::vector<int3> & tiles) const
|
||||||
|
@ -123,7 +123,12 @@ bool LobbyInfo::isClientHost(int clientId) const
|
|||||||
return clientId == hostClientId;
|
return clientId == hostClientId;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<PlayerColor> LobbyInfo::getAllClientPlayers(int clientId)
|
bool LobbyInfo::isPlayerHost(const PlayerColor & color) const
|
||||||
|
{
|
||||||
|
return vstd::contains(getAllClientPlayers(hostClientId), color);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::set<PlayerColor> LobbyInfo::getAllClientPlayers(int clientId) const
|
||||||
{
|
{
|
||||||
std::set<PlayerColor> players;
|
std::set<PlayerColor> players;
|
||||||
for(auto & elem : si->playerInfos)
|
for(auto & elem : si->playerInfos)
|
||||||
|
@ -197,7 +197,6 @@ struct DLL_LINKAGE LobbyState
|
|||||||
|
|
||||||
struct DLL_LINKAGE LobbyInfo : public LobbyState
|
struct DLL_LINKAGE LobbyInfo : public LobbyState
|
||||||
{
|
{
|
||||||
boost::mutex stateMutex;
|
|
||||||
std::string uuid;
|
std::string uuid;
|
||||||
|
|
||||||
LobbyInfo() {}
|
LobbyInfo() {}
|
||||||
@ -205,7 +204,8 @@ struct DLL_LINKAGE LobbyInfo : public LobbyState
|
|||||||
void verifyStateBeforeStart(bool ignoreNoHuman = false) const;
|
void verifyStateBeforeStart(bool ignoreNoHuman = false) const;
|
||||||
|
|
||||||
bool isClientHost(int clientId) const;
|
bool isClientHost(int clientId) const;
|
||||||
std::set<PlayerColor> getAllClientPlayers(int clientId);
|
bool isPlayerHost(const PlayerColor & color) const;
|
||||||
|
std::set<PlayerColor> getAllClientPlayers(int clientId) const;
|
||||||
std::vector<ui8> getConnectedPlayerIdsForClient(int clientId) const;
|
std::vector<ui8> getConnectedPlayerIdsForClient(int clientId) const;
|
||||||
|
|
||||||
// Helpers for lobby state access
|
// Helpers for lobby state access
|
||||||
|
@ -13,10 +13,27 @@
|
|||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
NetworkClient::NetworkClient()
|
DLL_LINKAGE bool checkNetworkPortIsFree(const std::string & host, uint16_t port)
|
||||||
|
{
|
||||||
|
boost::asio::io_service io;
|
||||||
|
NetworkAcceptor acceptor(io);
|
||||||
|
|
||||||
|
boost::system::error_code ec;
|
||||||
|
acceptor.open(boost::asio::ip::tcp::v4(), ec);
|
||||||
|
if (ec)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
acceptor.bind(boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port), ec);
|
||||||
|
if (ec)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkClient::NetworkClient(INetworkClientListener & listener)
|
||||||
: io(new NetworkService)
|
: io(new NetworkService)
|
||||||
, socket(new NetworkSocket(*io))
|
, socket(new NetworkSocket(*io))
|
||||||
// , timer(new NetworkTimer(*io))
|
, listener(listener)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,14 +49,14 @@ void NetworkClient::onConnected(const boost::system::error_code & ec)
|
|||||||
{
|
{
|
||||||
if (ec)
|
if (ec)
|
||||||
{
|
{
|
||||||
onConnectionFailed(ec.message());
|
listener.onConnectionFailed(ec.message());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
connection = std::make_shared<NetworkConnection>(socket, *this);
|
connection = std::make_shared<NetworkConnection>(socket, *this);
|
||||||
connection->start();
|
connection->start();
|
||||||
|
|
||||||
onConnectionEstablished();
|
listener.onConnectionEstablished();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkClient::run()
|
void NetworkClient::run()
|
||||||
@ -59,12 +76,12 @@ void NetworkClient::sendPacket(const std::vector<uint8_t> & message)
|
|||||||
|
|
||||||
void NetworkClient::onDisconnected(const std::shared_ptr<NetworkConnection> & connection)
|
void NetworkClient::onDisconnected(const std::shared_ptr<NetworkConnection> & connection)
|
||||||
{
|
{
|
||||||
onDisconnected();
|
listener.onDisconnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkClient::onPacketReceived(const std::shared_ptr<NetworkConnection> & connection, const std::vector<uint8_t> & message)
|
void NetworkClient::onPacketReceived(const std::shared_ptr<NetworkConnection> & connection, const std::vector<uint8_t> & message)
|
||||||
{
|
{
|
||||||
onPacketReceived(message);
|
listener.onPacketReceived(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -10,9 +10,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "NetworkDefines.h"
|
#include "NetworkDefines.h"
|
||||||
|
#include "NetworkListener.h"
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/// Function that attempts to open specified port on local system to determine whether port is in use
|
||||||
|
/// Returns: true if port is free and can be used to receive connections
|
||||||
|
DLL_LINKAGE bool checkNetworkPortIsFree(const std::string & host, uint16_t port);
|
||||||
|
|
||||||
class NetworkConnection;
|
class NetworkConnection;
|
||||||
|
|
||||||
class DLL_LINKAGE NetworkClient : boost::noncopyable, public INetworkConnectionListener
|
class DLL_LINKAGE NetworkClient : boost::noncopyable, public INetworkConnectionListener
|
||||||
@ -20,23 +25,19 @@ class DLL_LINKAGE NetworkClient : boost::noncopyable, public INetworkConnectionL
|
|||||||
std::shared_ptr<NetworkService> io;
|
std::shared_ptr<NetworkService> io;
|
||||||
std::shared_ptr<NetworkSocket> socket;
|
std::shared_ptr<NetworkSocket> socket;
|
||||||
std::shared_ptr<NetworkConnection> connection;
|
std::shared_ptr<NetworkConnection> connection;
|
||||||
std::shared_ptr<NetworkTimer> timer;
|
|
||||||
|
INetworkClientListener & listener;
|
||||||
|
|
||||||
void onConnected(const boost::system::error_code & ec);
|
void onConnected(const boost::system::error_code & ec);
|
||||||
|
|
||||||
void onDisconnected(const std::shared_ptr<NetworkConnection> & connection) override;
|
void onDisconnected(const std::shared_ptr<NetworkConnection> & connection) override;
|
||||||
void onPacketReceived(const std::shared_ptr<NetworkConnection> & connection, const std::vector<uint8_t> & message) override;
|
void onPacketReceived(const std::shared_ptr<NetworkConnection> & connection, const std::vector<uint8_t> & message) override;
|
||||||
|
|
||||||
protected:
|
public:
|
||||||
virtual void onPacketReceived(const std::vector<uint8_t> & message) = 0;
|
NetworkClient(INetworkClientListener & listener);
|
||||||
virtual void onConnectionFailed(const std::string & errorMessage) = 0;
|
virtual ~NetworkClient() = default;
|
||||||
virtual void onConnectionEstablished() = 0;
|
|
||||||
virtual void onDisconnected() = 0;
|
|
||||||
|
|
||||||
void sendPacket(const std::vector<uint8_t> & message);
|
void sendPacket(const std::vector<uint8_t> & message);
|
||||||
public:
|
|
||||||
NetworkClient();
|
|
||||||
virtual ~NetworkClient() = default;
|
|
||||||
|
|
||||||
void start(const std::string & host, uint16_t port);
|
void start(const std::string & host, uint16_t port);
|
||||||
void run();
|
void run();
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "NetworkDefines.h"
|
#include "NetworkDefines.h"
|
||||||
|
#include "NetworkListener.h"
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
@ -17,17 +17,5 @@ using NetworkService = boost::asio::io_service;
|
|||||||
using NetworkSocket = boost::asio::basic_stream_socket<boost::asio::ip::tcp>;
|
using NetworkSocket = boost::asio::basic_stream_socket<boost::asio::ip::tcp>;
|
||||||
using NetworkAcceptor = boost::asio::basic_socket_acceptor<boost::asio::ip::tcp>;
|
using NetworkAcceptor = boost::asio::basic_socket_acceptor<boost::asio::ip::tcp>;
|
||||||
using NetworkBuffer = boost::asio::streambuf;
|
using NetworkBuffer = boost::asio::streambuf;
|
||||||
using NetworkTimer = boost::asio::steady_timer;
|
|
||||||
|
|
||||||
class NetworkConnection;
|
|
||||||
|
|
||||||
class DLL_LINKAGE INetworkConnectionListener
|
|
||||||
{
|
|
||||||
friend class NetworkConnection;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void onDisconnected(const std::shared_ptr<NetworkConnection> & connection) = 0;
|
|
||||||
virtual void onPacketReceived(const std::shared_ptr<NetworkConnection> & connection, const std::vector<uint8_t> & message) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
50
lib/network/NetworkListener.h
Normal file
50
lib/network/NetworkListener.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* NetworkListener.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
|
||||||
|
|
||||||
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
class NetworkConnection;
|
||||||
|
class NetworkServer;
|
||||||
|
class NetworkClient;
|
||||||
|
|
||||||
|
class DLL_LINKAGE INetworkConnectionListener
|
||||||
|
{
|
||||||
|
friend class NetworkConnection;
|
||||||
|
protected:
|
||||||
|
virtual void onDisconnected(const std::shared_ptr<NetworkConnection> & connection) = 0;
|
||||||
|
virtual void onPacketReceived(const std::shared_ptr<NetworkConnection> & connection, const std::vector<uint8_t> & message) = 0;
|
||||||
|
|
||||||
|
~INetworkConnectionListener() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DLL_LINKAGE INetworkServerListener : public INetworkConnectionListener
|
||||||
|
{
|
||||||
|
friend class NetworkServer;
|
||||||
|
protected:
|
||||||
|
virtual void onNewConnection(const std::shared_ptr<NetworkConnection> &) = 0;
|
||||||
|
|
||||||
|
~INetworkServerListener() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DLL_LINKAGE INetworkClientListener
|
||||||
|
{
|
||||||
|
friend class NetworkClient;
|
||||||
|
protected:
|
||||||
|
virtual void onPacketReceived(const std::vector<uint8_t> & message) = 0;
|
||||||
|
virtual void onConnectionFailed(const std::string & errorMessage) = 0;
|
||||||
|
virtual void onConnectionEstablished() = 0;
|
||||||
|
virtual void onDisconnected() = 0;
|
||||||
|
|
||||||
|
~INetworkClientListener() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
VCMI_LIB_NAMESPACE_END
|
@ -13,6 +13,12 @@
|
|||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
NetworkServer::NetworkServer(INetworkServerListener & listener)
|
||||||
|
:listener(listener)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void NetworkServer::start(uint16_t port)
|
void NetworkServer::start(uint16_t port)
|
||||||
{
|
{
|
||||||
io = std::make_shared<boost::asio::io_service>();
|
io = std::make_shared<boost::asio::io_service>();
|
||||||
@ -32,6 +38,11 @@ void NetworkServer::run()
|
|||||||
io->run();
|
io->run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetworkServer::run(std::chrono::milliseconds duration)
|
||||||
|
{
|
||||||
|
io->run_for(duration);
|
||||||
|
}
|
||||||
|
|
||||||
void NetworkServer::connectionAccepted(std::shared_ptr<NetworkSocket> upcomingConnection, const boost::system::error_code & ec)
|
void NetworkServer::connectionAccepted(std::shared_ptr<NetworkSocket> upcomingConnection, const boost::system::error_code & ec)
|
||||||
{
|
{
|
||||||
if(ec)
|
if(ec)
|
||||||
@ -43,7 +54,7 @@ void NetworkServer::connectionAccepted(std::shared_ptr<NetworkSocket> upcomingCo
|
|||||||
auto connection = std::make_shared<NetworkConnection>(upcomingConnection, *this);
|
auto connection = std::make_shared<NetworkConnection>(upcomingConnection, *this);
|
||||||
connections.insert(connection);
|
connections.insert(connection);
|
||||||
connection->start();
|
connection->start();
|
||||||
onNewConnection(connection);
|
listener.onNewConnection(connection);
|
||||||
startAsyncAccept();
|
startAsyncAccept();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,7 +67,12 @@ void NetworkServer::onDisconnected(const std::shared_ptr<NetworkConnection> & co
|
|||||||
{
|
{
|
||||||
assert(connections.count(connection));
|
assert(connections.count(connection));
|
||||||
connections.erase(connection);
|
connections.erase(connection);
|
||||||
onConnectionLost(connection);
|
listener.onDisconnected(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkServer::onPacketReceived(const std::shared_ptr<NetworkConnection> & connection, const std::vector<uint8_t> & message)
|
||||||
|
{
|
||||||
|
listener.onPacketReceived(connection, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "NetworkDefines.h"
|
#include "NetworkDefines.h"
|
||||||
|
#include "NetworkListener.h"
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
@ -21,20 +22,20 @@ class DLL_LINKAGE NetworkServer : boost::noncopyable, public INetworkConnectionL
|
|||||||
std::shared_ptr<NetworkAcceptor> acceptor;
|
std::shared_ptr<NetworkAcceptor> acceptor;
|
||||||
std::set<std::shared_ptr<NetworkConnection>> connections;
|
std::set<std::shared_ptr<NetworkConnection>> connections;
|
||||||
|
|
||||||
|
INetworkServerListener & listener;
|
||||||
|
|
||||||
void connectionAccepted(std::shared_ptr<NetworkSocket>, const boost::system::error_code & ec);
|
void connectionAccepted(std::shared_ptr<NetworkSocket>, const boost::system::error_code & ec);
|
||||||
void startAsyncAccept();
|
void startAsyncAccept();
|
||||||
|
|
||||||
void onDisconnected(const std::shared_ptr<NetworkConnection> & connection) override;
|
void onDisconnected(const std::shared_ptr<NetworkConnection> & connection) override;
|
||||||
protected:
|
void onPacketReceived(const std::shared_ptr<NetworkConnection> & connection, const std::vector<uint8_t> & message) override;
|
||||||
virtual void onNewConnection(const std::shared_ptr<NetworkConnection> &) = 0;
|
public:
|
||||||
virtual void onConnectionLost(const std::shared_ptr<NetworkConnection> &) = 0;
|
explicit NetworkServer(INetworkServerListener & listener);
|
||||||
|
|
||||||
void sendPacket(const std::shared_ptr<NetworkConnection> &, const std::vector<uint8_t> & message);
|
void sendPacket(const std::shared_ptr<NetworkConnection> &, const std::vector<uint8_t> & message);
|
||||||
|
|
||||||
public:
|
|
||||||
virtual ~NetworkServer() = default;
|
|
||||||
|
|
||||||
void start(uint16_t port);
|
void start(uint16_t port);
|
||||||
|
void run(std::chrono::milliseconds duration);
|
||||||
void run();
|
void run();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ struct VectorizedObjectInfo
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Base class for serializers capable of reading or writing data
|
/// Base class for serializers capable of reading or writing data
|
||||||
class DLL_LINKAGE CSerializer
|
class DLL_LINKAGE CSerializer : boost::noncopyable
|
||||||
{
|
{
|
||||||
template<typename Numeric, std::enable_if_t<std::is_arithmetic_v<Numeric>, bool> = true>
|
template<typename Numeric, std::enable_if_t<std::is_arithmetic_v<Numeric>, bool> = true>
|
||||||
static int32_t idToNumber(const Numeric &t)
|
static int32_t idToNumber(const Numeric &t)
|
||||||
|
@ -10,9 +10,52 @@
|
|||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "Connection.h"
|
#include "Connection.h"
|
||||||
|
|
||||||
#include "../networkPacks/NetPacksBase.h"
|
#include "BinaryDeserializer.h"
|
||||||
|
#include "BinarySerializer.h"
|
||||||
|
|
||||||
#include <boost/asio.hpp>
|
//#include "../networkPacks/NetPacksBase.h"
|
||||||
|
|
||||||
|
CConnection::CConnection(std::weak_ptr<NetworkConnection> networkConnection)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CConnection::sendPack(const CPack * pack)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
CPack * CConnection::retrievePack(const std::vector<uint8_t> & data)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CConnection::disableStackSendingByID()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CConnection::enterLobbyConnectionMode()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CConnection::enterGameplayConnectionMode(CGameState * gs)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int CConnection::write(const void * data, unsigned size)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CConnection::read(void * data, unsigned size)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
@ -362,3 +405,5 @@ std::string CConnection::toString() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@ -9,123 +9,84 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "BinaryDeserializer.h"
|
#include "CSerializer.h"
|
||||||
#include "BinarySerializer.h"
|
|
||||||
|
|
||||||
#if BOOST_VERSION >= 107000 // Boost version >= 1.70
|
|
||||||
#include <boost/asio.hpp>
|
|
||||||
using TSocket = boost::asio::basic_stream_socket<boost::asio::ip::tcp>;
|
|
||||||
using TAcceptor = boost::asio::basic_socket_acceptor<boost::asio::ip::tcp>;
|
|
||||||
#else
|
|
||||||
namespace boost
|
|
||||||
{
|
|
||||||
namespace asio
|
|
||||||
{
|
|
||||||
namespace ip
|
|
||||||
{
|
|
||||||
class tcp;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if BOOST_VERSION >= 106600 // Boost version >= 1.66
|
|
||||||
class io_context;
|
|
||||||
typedef io_context io_service;
|
|
||||||
#else
|
|
||||||
class io_service;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template <typename Protocol> class stream_socket_service;
|
|
||||||
template <typename Protocol,typename StreamSocketService>
|
|
||||||
class basic_stream_socket;
|
|
||||||
|
|
||||||
template <typename Protocol> class socket_acceptor_service;
|
|
||||||
template <typename Protocol,typename SocketAcceptorService>
|
|
||||||
class basic_socket_acceptor;
|
|
||||||
}
|
|
||||||
class mutex;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef boost::asio::basic_stream_socket < boost::asio::ip::tcp , boost::asio::stream_socket_service<boost::asio::ip::tcp> > TSocket;
|
|
||||||
typedef boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::socket_acceptor_service<boost::asio::ip::tcp> > TAcceptor;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
class BinaryDeserializer;
|
||||||
|
class BinarySerializer;
|
||||||
struct CPack;
|
struct CPack;
|
||||||
struct ConnectionBuffers;
|
struct ConnectionBuffers;
|
||||||
|
class NetworkConnection;
|
||||||
|
|
||||||
/// Main class for network communication
|
/// Main class for network communication
|
||||||
/// Allows establishing connection and bidirectional read-write
|
/// Allows establishing connection and bidirectional read-write
|
||||||
class DLL_LINKAGE CConnection
|
class DLL_LINKAGE CConnection : public IBinaryReader, public IBinaryWriter, public std::enable_shared_from_this<CConnection>
|
||||||
: public IBinaryReader, public IBinaryWriter, public std::enable_shared_from_this<CConnection>
|
|
||||||
{
|
{
|
||||||
void init();
|
/// Non-owning pointer to underlying connection
|
||||||
void reportState(vstd::CLoggerBase * out) override;
|
std::weak_ptr<NetworkConnection> networkConnection;
|
||||||
|
|
||||||
|
// void init();
|
||||||
|
// void reportState(vstd::CLoggerBase * out) override;
|
||||||
|
//
|
||||||
int write(const void * data, unsigned size) override;
|
int write(const void * data, unsigned size) override;
|
||||||
int read(void * data, unsigned size) override;
|
int read(void * data, unsigned size) override;
|
||||||
void flushBuffers();
|
// void flushBuffers();
|
||||||
|
//
|
||||||
std::shared_ptr<boost::asio::io_service> io_service; //can be empty if connection made from socket
|
// bool enableBufferedWrite;
|
||||||
|
// bool enableBufferedRead;
|
||||||
bool enableBufferedWrite;
|
// std::unique_ptr<ConnectionBuffers> connectionBuffers;
|
||||||
bool enableBufferedRead;
|
//
|
||||||
std::unique_ptr<ConnectionBuffers> connectionBuffers;
|
std::unique_ptr<BinaryDeserializer> iser;
|
||||||
|
std::unique_ptr<BinarySerializer> oser;
|
||||||
|
//
|
||||||
|
// std::string contactUuid;
|
||||||
|
// std::string name; //who uses this connection
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BinaryDeserializer iser;
|
|
||||||
BinarySerializer oser;
|
|
||||||
|
|
||||||
std::shared_ptr<boost::mutex> mutexRead;
|
|
||||||
std::shared_ptr<boost::mutex> mutexWrite;
|
|
||||||
std::shared_ptr<TSocket> socket;
|
|
||||||
bool connected;
|
|
||||||
bool myEndianess, contactEndianess; //true if little endian, if endianness is different we'll have to revert received multi-byte vars
|
|
||||||
std::string contactUuid;
|
|
||||||
std::string name; //who uses this connection
|
|
||||||
std::string uuid;
|
std::string uuid;
|
||||||
|
|
||||||
int connectionID;
|
int connectionID;
|
||||||
std::shared_ptr<boost::thread> handler;
|
|
||||||
|
|
||||||
CConnection(const std::string & host, ui16 port, std::string Name, std::string UUID);
|
CConnection(std::weak_ptr<NetworkConnection> networkConnection);
|
||||||
CConnection(const std::shared_ptr<TAcceptor> & acceptor, const std::shared_ptr<boost::asio::io_service> & Io_service, std::string Name, std::string UUID);
|
// CConnection(const std::string & host, ui16 port, std::string Name, std::string UUID);
|
||||||
CConnection(std::shared_ptr<TSocket> Socket, std::string Name, std::string UUID); //use immediately after accepting connection into socket
|
// CConnection(const std::shared_ptr<TAcceptor> & acceptor, const std::shared_ptr<boost::asio::io_service> & Io_service, std::string Name, std::string UUID);
|
||||||
|
// CConnection(std::shared_ptr<TSocket> Socket, std::string Name, std::string UUID); //use immediately after accepting connection into socket
|
||||||
|
// virtual ~CConnection();
|
||||||
|
|
||||||
void close();
|
// void close();
|
||||||
bool isOpen() const;
|
// bool isOpen() const;
|
||||||
template<class T>
|
//
|
||||||
CConnection &operator&(const T&);
|
// CPack * retrievePack();
|
||||||
virtual ~CConnection();
|
|
||||||
|
|
||||||
CPack * retrievePack();
|
|
||||||
void sendPack(const CPack * pack);
|
void sendPack(const CPack * pack);
|
||||||
|
|
||||||
|
CPack * retrievePack(const std::vector<uint8_t> & data);
|
||||||
|
// std::vector<uint8_t> serializePack(const CPack * pack);
|
||||||
|
//
|
||||||
void disableStackSendingByID();
|
void disableStackSendingByID();
|
||||||
void enableStackSendingByID();
|
// void enableStackSendingByID();
|
||||||
void disableSmartPointerSerialization();
|
// void disableSmartPointerSerialization();
|
||||||
void enableSmartPointerSerialization();
|
// void enableSmartPointerSerialization();
|
||||||
void disableSmartVectorMemberSerialization();
|
// void disableSmartVectorMemberSerialization();
|
||||||
void enableSmartVectorMemberSerializatoin();
|
// void enableSmartVectorMemberSerializatoin();
|
||||||
|
//
|
||||||
void enterLobbyConnectionMode();
|
void enterLobbyConnectionMode();
|
||||||
void enterGameplayConnectionMode(CGameState * gs);
|
void enterGameplayConnectionMode(CGameState * gs);
|
||||||
|
//
|
||||||
std::string toString() const;
|
// std::string toString() const;
|
||||||
|
//
|
||||||
template<class T>
|
// template<class T>
|
||||||
CConnection & operator>>(T &t)
|
// CConnection & operator>>(T &t)
|
||||||
{
|
// {
|
||||||
iser & t;
|
// iser & t;
|
||||||
return * this;
|
// return * this;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
template<class T>
|
// template<class T>
|
||||||
CConnection & operator<<(const T &t)
|
// CConnection & operator<<(const T &t)
|
||||||
{
|
// {
|
||||||
oser & t;
|
// oser & t;
|
||||||
return * this;
|
// return * this;
|
||||||
}
|
// }
|
||||||
};
|
};
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
@ -104,14 +104,14 @@ void LobbyServer::sendMessage(const std::shared_ptr<NetworkConnection> & target,
|
|||||||
|
|
||||||
std::vector<uint8_t> payloadBuffer(payloadBegin, payloadEnd);
|
std::vector<uint8_t> payloadBuffer(payloadBegin, payloadEnd);
|
||||||
|
|
||||||
sendPacket(target, payloadBuffer);
|
networkServer->sendPacket(target, payloadBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LobbyServer::onNewConnection(const std::shared_ptr<NetworkConnection> & connection)
|
void LobbyServer::onNewConnection(const std::shared_ptr<NetworkConnection> & connection)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void LobbyServer::onConnectionLost(const std::shared_ptr<NetworkConnection> & connection)
|
void LobbyServer::onDisconnected(const std::shared_ptr<NetworkConnection> & connection)
|
||||||
{
|
{
|
||||||
activeAccounts.erase(connection);
|
activeAccounts.erase(connection);
|
||||||
}
|
}
|
||||||
@ -169,9 +169,20 @@ void LobbyServer::onPacketReceived(const std::shared_ptr<NetworkConnection> & co
|
|||||||
|
|
||||||
LobbyServer::LobbyServer()
|
LobbyServer::LobbyServer()
|
||||||
: database(new LobbyDatabase())
|
: database(new LobbyDatabase())
|
||||||
|
, networkServer(new NetworkServer(*this))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LobbyServer::start(uint16_t port)
|
||||||
|
{
|
||||||
|
networkServer->start(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LobbyServer::run()
|
||||||
|
{
|
||||||
|
networkServer->run();
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, const char * argv[])
|
int main(int argc, const char * argv[])
|
||||||
{
|
{
|
||||||
LobbyServer server;
|
LobbyServer server;
|
||||||
|
@ -41,7 +41,7 @@ public:
|
|||||||
std::vector<ChatMessage> getRecentMessageHistory();
|
std::vector<ChatMessage> getRecentMessageHistory();
|
||||||
};
|
};
|
||||||
|
|
||||||
class LobbyServer : public NetworkServer
|
class LobbyServer : public INetworkServerListener
|
||||||
{
|
{
|
||||||
struct AccountState
|
struct AccountState
|
||||||
{
|
{
|
||||||
@ -51,12 +51,16 @@ class LobbyServer : public NetworkServer
|
|||||||
std::map<std::shared_ptr<NetworkConnection>, AccountState> activeAccounts;
|
std::map<std::shared_ptr<NetworkConnection>, AccountState> activeAccounts;
|
||||||
|
|
||||||
std::unique_ptr<LobbyDatabase> database;
|
std::unique_ptr<LobbyDatabase> database;
|
||||||
|
std::unique_ptr<NetworkServer> networkServer;
|
||||||
|
|
||||||
void onNewConnection(const std::shared_ptr<NetworkConnection> &) override;
|
void onNewConnection(const std::shared_ptr<NetworkConnection> &) override;
|
||||||
void onConnectionLost(const std::shared_ptr<NetworkConnection> &) override;
|
void onDisconnected(const std::shared_ptr<NetworkConnection> &) override;
|
||||||
void onPacketReceived(const std::shared_ptr<NetworkConnection> &, const std::vector<uint8_t> & message) override;
|
void onPacketReceived(const std::shared_ptr<NetworkConnection> &, const std::vector<uint8_t> & message) override;
|
||||||
|
|
||||||
void sendMessage(const std::shared_ptr<NetworkConnection> & target, const JsonNode & json);
|
void sendMessage(const std::shared_ptr<NetworkConnection> & target, const JsonNode & json);
|
||||||
public:
|
public:
|
||||||
LobbyServer();
|
LobbyServer();
|
||||||
|
|
||||||
|
void start(uint16_t port);
|
||||||
|
void run();
|
||||||
};
|
};
|
||||||
|
@ -61,6 +61,7 @@
|
|||||||
|
|
||||||
#include "../lib/serializer/CSaveFile.h"
|
#include "../lib/serializer/CSaveFile.h"
|
||||||
#include "../lib/serializer/CLoadFile.h"
|
#include "../lib/serializer/CLoadFile.h"
|
||||||
|
#include "../lib/serializer/Connection.h"
|
||||||
|
|
||||||
#include "../lib/spells/CSpellHandler.h"
|
#include "../lib/spells/CSpellHandler.h"
|
||||||
|
|
||||||
@ -969,11 +970,11 @@ void CGameHandler::onNewTurn()
|
|||||||
synchronizeArtifactHandlerLists(); //new day events may have changed them. TODO better of managing that
|
synchronizeArtifactHandlerLists(); //new day events may have changed them. TODO better of managing that
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameHandler::run(bool resume)
|
void CGameHandler::start(bool resume)
|
||||||
{
|
{
|
||||||
LOG_TRACE_PARAMS(logGlobal, "resume=%d", resume);
|
LOG_TRACE_PARAMS(logGlobal, "resume=%d", resume);
|
||||||
|
|
||||||
for (auto cc : lobby->connections)
|
for (auto cc : lobby->activeConnections)
|
||||||
{
|
{
|
||||||
auto players = lobby->getAllClientPlayers(cc->connectionID);
|
auto players = lobby->getAllClientPlayers(cc->connectionID);
|
||||||
std::stringstream sbuffer;
|
std::stringstream sbuffer;
|
||||||
@ -1004,18 +1005,11 @@ void CGameHandler::run(bool resume)
|
|||||||
events::GameResumed::defaultExecute(serverEventBus.get());
|
events::GameResumed::defaultExecute(serverEventBus.get());
|
||||||
|
|
||||||
turnOrder->onGameStarted();
|
turnOrder->onGameStarted();
|
||||||
|
}
|
||||||
|
|
||||||
//wait till game is done
|
void CGameHandler::tick(int millisecondsPassed)
|
||||||
auto clockLast = std::chrono::steady_clock::now();
|
{
|
||||||
while(lobby->getState() == EServerState::GAMEPLAY)
|
turnTimerHandler.update(millisecondsPassed);
|
||||||
{
|
|
||||||
const auto clockDuration = std::chrono::steady_clock::now() - clockLast;
|
|
||||||
const int timePassed = std::chrono::duration_cast<std::chrono::milliseconds>(clockDuration).count();
|
|
||||||
clockLast += clockDuration;
|
|
||||||
turnTimerHandler.update(timePassed);
|
|
||||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameHandler::giveSpells(const CGTownInstance *t, const CGHeroInstance *h)
|
void CGameHandler::giveSpells(const CGTownInstance *t, const CGHeroInstance *h)
|
||||||
@ -1677,13 +1671,8 @@ void CGameHandler::heroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2)
|
|||||||
void CGameHandler::sendToAllClients(CPackForClient * pack)
|
void CGameHandler::sendToAllClients(CPackForClient * pack)
|
||||||
{
|
{
|
||||||
logNetwork->trace("\tSending to all clients: %s", typeid(*pack).name());
|
logNetwork->trace("\tSending to all clients: %s", typeid(*pack).name());
|
||||||
for (auto c : lobby->connections)
|
for (auto c : lobby->activeConnections)
|
||||||
{
|
|
||||||
if(!c->isOpen())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
c->sendPack(pack);
|
c->sendPack(pack);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameHandler::sendAndApply(CPackForClient * pack)
|
void CGameHandler::sendAndApply(CPackForClient * pack)
|
||||||
|
@ -261,7 +261,8 @@ public:
|
|||||||
|
|
||||||
bool isPlayerOwns(CPackForServer * pack, ObjectInstanceID id);
|
bool isPlayerOwns(CPackForServer * pack, ObjectInstanceID id);
|
||||||
|
|
||||||
void run(bool resume);
|
void start(bool resume);
|
||||||
|
void tick(int millisecondsPassed);
|
||||||
bool sacrificeArtifact(const IMarket * m, const CGHeroInstance * hero, const std::vector<ArtifactPosition> & slot);
|
bool sacrificeArtifact(const IMarket * m, const CGHeroInstance * hero, const std::vector<ArtifactPosition> & slot);
|
||||||
void spawnWanderingMonsters(CreatureID creatureID);
|
void spawnWanderingMonsters(CreatureID creatureID);
|
||||||
|
|
||||||
|
@ -8,12 +8,11 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include <boost/asio.hpp>
|
#include <boost/program_options.hpp>
|
||||||
|
|
||||||
#include "../lib/filesystem/Filesystem.h"
|
#include "../lib/filesystem/Filesystem.h"
|
||||||
#include "../lib/campaign/CampaignState.h"
|
#include "../lib/campaign/CampaignState.h"
|
||||||
#include "../lib/CThreadHelper.h"
|
#include "../lib/CThreadHelper.h"
|
||||||
#include "../lib/serializer/Connection.h"
|
|
||||||
#include "../lib/CArtHandler.h"
|
#include "../lib/CArtHandler.h"
|
||||||
#include "../lib/CGeneralTextHandler.h"
|
#include "../lib/CGeneralTextHandler.h"
|
||||||
#include "../lib/CHeroHandler.h"
|
#include "../lib/CHeroHandler.h"
|
||||||
@ -37,12 +36,15 @@
|
|||||||
#include "CGameHandler.h"
|
#include "CGameHandler.h"
|
||||||
#include "processors/PlayerMessageProcessor.h"
|
#include "processors/PlayerMessageProcessor.h"
|
||||||
#include "../lib/mapping/CMapInfo.h"
|
#include "../lib/mapping/CMapInfo.h"
|
||||||
|
#include "../lib/network/NetworkServer.h"
|
||||||
|
#include "../lib/network/NetworkClient.h"
|
||||||
#include "../lib/GameConstants.h"
|
#include "../lib/GameConstants.h"
|
||||||
#include "../lib/logging/CBasicLogConfigurator.h"
|
#include "../lib/logging/CBasicLogConfigurator.h"
|
||||||
#include "../lib/CConfigHandler.h"
|
#include "../lib/CConfigHandler.h"
|
||||||
#include "../lib/ScopeGuard.h"
|
#include "../lib/ScopeGuard.h"
|
||||||
#include "../lib/serializer/CMemorySerializer.h"
|
#include "../lib/serializer/CMemorySerializer.h"
|
||||||
#include "../lib/serializer/Cast.h"
|
#include "../lib/serializer/Cast.h"
|
||||||
|
#include "../lib/serializer/Connection.h"
|
||||||
|
|
||||||
#include "../lib/UnlockGuard.h"
|
#include "../lib/UnlockGuard.h"
|
||||||
|
|
||||||
@ -81,11 +83,8 @@ public:
|
|||||||
|
|
||||||
if(checker.getResult())
|
if(checker.getResult())
|
||||||
{
|
{
|
||||||
boost::unique_lock<boost::mutex> stateLock(srv->stateMutex);
|
|
||||||
ApplyOnServerNetPackVisitor applier(*srv);
|
ApplyOnServerNetPackVisitor applier(*srv);
|
||||||
|
|
||||||
ptr->visit(applier);
|
ptr->visit(applier);
|
||||||
|
|
||||||
return applier.getResult();
|
return applier.getResult();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -117,48 +116,101 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CVCMIServerPackVisitor : public VCMI_LIB_WRAP_NAMESPACE(ICPackVisitor)
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
CVCMIServer & handler;
|
||||||
|
std::shared_ptr<CGameHandler> gh;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CVCMIServerPackVisitor(CVCMIServer & handler, std::shared_ptr<CGameHandler> gh)
|
||||||
|
:handler(handler), gh(gh)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool callTyped() override { return false; }
|
||||||
|
|
||||||
|
virtual void visitForLobby(CPackForLobby & packForLobby) override
|
||||||
|
{
|
||||||
|
handler.handleReceivedPack(std::unique_ptr<CPackForLobby>(&packForLobby));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visitForServer(CPackForServer & serverPack) override
|
||||||
|
{
|
||||||
|
if (gh)
|
||||||
|
gh->handleReceivedPack(&serverPack);
|
||||||
|
else
|
||||||
|
logNetwork->error("Received pack for game server while in lobby!");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visitForClient(CPackForClient & clientPack) override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
std::string SERVER_NAME_AFFIX = "server";
|
std::string SERVER_NAME_AFFIX = "server";
|
||||||
std::string SERVER_NAME = GameConstants::VCMI_VERSION + std::string(" (") + SERVER_NAME_AFFIX + ')';
|
std::string SERVER_NAME = GameConstants::VCMI_VERSION + std::string(" (") + SERVER_NAME_AFFIX + ')';
|
||||||
|
|
||||||
CVCMIServer::CVCMIServer(boost::program_options::variables_map & opts)
|
CVCMIServer::CVCMIServer(boost::program_options::variables_map & opts)
|
||||||
: port(3030), io(std::make_shared<boost::asio::io_service>()), state(EServerState::LOBBY), cmdLineOptions(opts), currentClientId(1), currentPlayerId(1), restartGameplay(false)
|
: state(EServerState::LOBBY), cmdLineOptions(opts), currentClientId(1), currentPlayerId(1), restartGameplay(false)
|
||||||
{
|
{
|
||||||
uuid = boost::uuids::to_string(boost::uuids::random_generator()());
|
uuid = boost::uuids::to_string(boost::uuids::random_generator()());
|
||||||
logNetwork->trace("CVCMIServer created! UUID: %s", uuid);
|
logNetwork->trace("CVCMIServer created! UUID: %s", uuid);
|
||||||
applier = std::make_shared<CApplier<CBaseForServerApply>>();
|
applier = std::make_shared<CApplier<CBaseForServerApply>>();
|
||||||
registerTypesLobbyPacks(*applier);
|
registerTypesLobbyPacks(*applier);
|
||||||
|
|
||||||
|
uint16_t port = 3030;
|
||||||
if(cmdLineOptions.count("port"))
|
if(cmdLineOptions.count("port"))
|
||||||
port = cmdLineOptions["port"].as<ui16>();
|
port = cmdLineOptions["port"].as<uint16_t>();
|
||||||
logNetwork->info("Port %d will be used", port);
|
logNetwork->info("Port %d will be used", port);
|
||||||
try
|
|
||||||
{
|
networkServer = std::make_unique<NetworkServer>(*this);
|
||||||
acceptor = std::make_shared<TAcceptor>(*io, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port));
|
networkServer->start(port);
|
||||||
}
|
|
||||||
catch(...)
|
|
||||||
{
|
|
||||||
logNetwork->info("Port %d is busy, trying to use random port instead", port);
|
|
||||||
if(cmdLineOptions.count("run-by-client"))
|
|
||||||
{
|
|
||||||
logNetwork->error("Port must be specified when run-by-client is used!!");
|
|
||||||
#if (defined(__ANDROID_API__) && __ANDROID_API__ < 21) || (defined(__MINGW32__)) || defined(VCMI_APPLE)
|
|
||||||
::exit(0);
|
|
||||||
#else
|
|
||||||
std::quick_exit(0);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
acceptor = std::make_shared<TAcceptor>(*io, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 0));
|
|
||||||
port = acceptor->local_endpoint().port();
|
|
||||||
}
|
|
||||||
logNetwork->info("Listening for connections at port %d", port);
|
logNetwork->info("Listening for connections at port %d", port);
|
||||||
}
|
}
|
||||||
|
|
||||||
CVCMIServer::~CVCMIServer()
|
CVCMIServer::~CVCMIServer() = default;
|
||||||
{
|
|
||||||
announceQueue.clear();
|
|
||||||
|
|
||||||
if(announceLobbyThread)
|
void CVCMIServer::onNewConnection(const std::shared_ptr<NetworkConnection> & connection)
|
||||||
announceLobbyThread->join();
|
{
|
||||||
|
if (activeConnections.empty())
|
||||||
|
establishOutgoingConnection();
|
||||||
|
|
||||||
|
if(state == EServerState::LOBBY)
|
||||||
|
activeConnections.push_back(std::make_shared<CConnection>(connection));//, SERVER_NAME, uuid);)
|
||||||
|
// TODO: else: deny connection
|
||||||
|
// TODO: else: try to reconnect / send state to reconnected client
|
||||||
|
}
|
||||||
|
|
||||||
|
void CVCMIServer::onPacketReceived(const std::shared_ptr<NetworkConnection> & connection, const std::vector<uint8_t> & message)
|
||||||
|
{
|
||||||
|
std::shared_ptr<CConnection> c = findConnection(connection);
|
||||||
|
CPack * pack = c->retrievePack(message);
|
||||||
|
pack->c = c;
|
||||||
|
CVCMIServerPackVisitor visitor(*this, this->gh);
|
||||||
|
pack->visit(visitor);
|
||||||
|
|
||||||
|
//FIXME: delete pack?
|
||||||
|
}
|
||||||
|
|
||||||
|
void CVCMIServer::onPacketReceived(const std::vector<uint8_t> & message)
|
||||||
|
{
|
||||||
|
//TODO: handle pack received from lobby
|
||||||
|
}
|
||||||
|
|
||||||
|
void CVCMIServer::onConnectionFailed(const std::string & errorMessage)
|
||||||
|
{
|
||||||
|
//TODO: handle failure to connect to lobby
|
||||||
|
}
|
||||||
|
|
||||||
|
void CVCMIServer::onConnectionEstablished()
|
||||||
|
{
|
||||||
|
//TODO: handle connection to lobby - login?
|
||||||
|
}
|
||||||
|
|
||||||
|
void CVCMIServer::onDisconnected()
|
||||||
|
{
|
||||||
|
//TODO: handle disconnection from lobby
|
||||||
}
|
}
|
||||||
|
|
||||||
void CVCMIServer::setState(EServerState value)
|
void CVCMIServer::setState(EServerState value)
|
||||||
@ -171,101 +223,60 @@ EServerState CVCMIServer::getState() const
|
|||||||
return state.load();
|
return state.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<CConnection> CVCMIServer::findConnection(const std::shared_ptr<NetworkConnection> & netConnection)
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
assert(0);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void CVCMIServer::run()
|
void CVCMIServer::run()
|
||||||
{
|
{
|
||||||
|
#if defined(VCMI_ANDROID) && !defined(SINGLE_PROCESS_APP)
|
||||||
if(!restartGameplay)
|
if(!restartGameplay)
|
||||||
{
|
{
|
||||||
this->announceLobbyThread = std::make_unique<boost::thread>(&CVCMIServer::threadAnnounceLobby, this);
|
|
||||||
|
|
||||||
startAsyncAccept();
|
|
||||||
if(!remoteConnectionsThread && cmdLineOptions.count("lobby"))
|
|
||||||
{
|
|
||||||
remoteConnectionsThread = std::make_unique<boost::thread>(&CVCMIServer::establishRemoteConnections, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(VCMI_ANDROID)
|
|
||||||
#ifndef SINGLE_PROCESS_APP
|
|
||||||
CAndroidVMHelper vmHelper;
|
CAndroidVMHelper vmHelper;
|
||||||
vmHelper.callStaticVoidMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "onServerReady");
|
vmHelper.callStaticVoidMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "onServerReady");
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
while(state == EServerState::LOBBY || state == EServerState::GAMEPLAY_STARTING)
|
static const int serverUpdateIntervalMilliseconds = 50;
|
||||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(50));
|
auto clockInitial = std::chrono::steady_clock::now();
|
||||||
|
int64_t msPassedLast = 0;
|
||||||
|
|
||||||
logNetwork->info("Thread handling connections ended");
|
|
||||||
|
|
||||||
if(state == EServerState::GAMEPLAY)
|
|
||||||
{
|
|
||||||
gh->run(si->mode == StartInfo::LOAD_GAME);
|
|
||||||
}
|
|
||||||
while(state == EServerState::GAMEPLAY_ENDED)
|
|
||||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(50));
|
|
||||||
}
|
|
||||||
|
|
||||||
void CVCMIServer::establishRemoteConnections()
|
|
||||||
{
|
|
||||||
setThreadName("establishConnection");
|
|
||||||
|
|
||||||
//wait for host connection
|
|
||||||
while(connections.empty())
|
|
||||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(50));
|
|
||||||
|
|
||||||
uuid = cmdLineOptions["lobby-uuid"].as<std::string>();
|
|
||||||
int numOfConnections = cmdLineOptions["connections"].as<ui16>();
|
|
||||||
for(int i = 0; i < numOfConnections; ++i)
|
|
||||||
connectToRemote();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CVCMIServer::connectToRemote()
|
|
||||||
{
|
|
||||||
std::shared_ptr<CConnection> c;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
auto address = cmdLineOptions["lobby"].as<std::string>();
|
|
||||||
int port = cmdLineOptions["lobby-port"].as<ui16>();
|
|
||||||
|
|
||||||
logNetwork->info("Establishing connection to remote at %s:%d with uuid %s", address, port, uuid);
|
|
||||||
c = std::make_shared<CConnection>(address, port, SERVER_NAME, uuid);
|
|
||||||
}
|
|
||||||
catch(...)
|
|
||||||
{
|
|
||||||
logNetwork->error("\nCannot establish remote connection!");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(c)
|
|
||||||
{
|
|
||||||
connections.insert(c);
|
|
||||||
remoteConnections.insert(c);
|
|
||||||
c->handler = std::make_shared<boost::thread>(&CVCMIServer::threadHandleClient, this, c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CVCMIServer::threadAnnounceLobby()
|
|
||||||
{
|
|
||||||
setThreadName("announceLobby");
|
|
||||||
while(state != EServerState::SHUTDOWN)
|
while(state != EServerState::SHUTDOWN)
|
||||||
{
|
{
|
||||||
{
|
networkServer->run(std::chrono::milliseconds(serverUpdateIntervalMilliseconds));
|
||||||
boost::unique_lock<boost::recursive_mutex> myLock(mx);
|
|
||||||
while(!announceQueue.empty())
|
|
||||||
{
|
|
||||||
announcePack(std::move(announceQueue.front()));
|
|
||||||
announceQueue.pop_front();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(acceptor)
|
const auto clockNow = std::chrono::steady_clock::now();
|
||||||
{
|
const auto clockPassed = clockNow - clockInitial;
|
||||||
io->reset();
|
const int64_t msPassedNow = std::chrono::duration_cast<std::chrono::milliseconds>(clockPassed).count();
|
||||||
io->poll();
|
const int64_t msDelta = msPassedNow - msPassedLast;
|
||||||
}
|
msPassedLast = msPassedNow;
|
||||||
}
|
|
||||||
|
|
||||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(50));
|
if (state == EServerState::GAMEPLAY)
|
||||||
|
gh->tick(msDelta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CVCMIServer::establishOutgoingConnection()
|
||||||
|
{
|
||||||
|
if(!cmdLineOptions.count("lobby"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
uuid = cmdLineOptions["lobby-uuid"].as<std::string>();
|
||||||
|
auto address = cmdLineOptions["lobby"].as<std::string>();
|
||||||
|
int port = cmdLineOptions["lobby-port"].as<ui16>();
|
||||||
|
logNetwork->info("Establishing connection to remote at %s:%d with uuid %s", address, port, uuid);
|
||||||
|
|
||||||
|
outgoingConnection = std::make_unique<NetworkClient>(*this);
|
||||||
|
|
||||||
|
outgoingConnection->start(address, port);//, SERVER_NAME, uuid);
|
||||||
|
|
||||||
|
// connections.insert(c);
|
||||||
|
// remoteConnections.insert(c);
|
||||||
|
}
|
||||||
|
|
||||||
void CVCMIServer::prepareToRestart()
|
void CVCMIServer::prepareToRestart()
|
||||||
{
|
{
|
||||||
if(state == EServerState::GAMEPLAY)
|
if(state == EServerState::GAMEPLAY)
|
||||||
@ -280,11 +291,9 @@ void CVCMIServer::prepareToRestart()
|
|||||||
campaignMap = si->campState->currentScenario().value_or(CampaignScenarioID(0));
|
campaignMap = si->campState->currentScenario().value_or(CampaignScenarioID(0));
|
||||||
campaignBonus = si->campState->getBonusID(campaignMap).value_or(-1);
|
campaignBonus = si->campState->getBonusID(campaignMap).value_or(-1);
|
||||||
}
|
}
|
||||||
// FIXME: dirry hack to make sure old CGameHandler::run is finished
|
|
||||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(1000));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto c : connections)
|
for(auto c : activeConnections)
|
||||||
{
|
{
|
||||||
c->enterLobbyConnectionMode();
|
c->enterLobbyConnectionMode();
|
||||||
c->disableStackSendingByID();
|
c->disableStackSendingByID();
|
||||||
@ -306,10 +315,11 @@ bool CVCMIServer::prepareToStartGame()
|
|||||||
{
|
{
|
||||||
if(progressTracking.get() != currentProgress)
|
if(progressTracking.get() != currentProgress)
|
||||||
{
|
{
|
||||||
|
//FIXME: UNGUARDED MULTITHREADED ACCESS!!!
|
||||||
currentProgress = progressTracking.get();
|
currentProgress = progressTracking.get();
|
||||||
std::unique_ptr<LobbyLoadProgress> loadProgress(new LobbyLoadProgress);
|
std::unique_ptr<LobbyLoadProgress> loadProgress(new LobbyLoadProgress);
|
||||||
loadProgress->progress = currentProgress;
|
loadProgress->progress = currentProgress;
|
||||||
addToAnnounceQueue(std::move(loadProgress));
|
announcePack(std::move(loadProgress));
|
||||||
}
|
}
|
||||||
boost::this_thread::sleep(boost::posix_time::milliseconds(50));
|
boost::this_thread::sleep(boost::posix_time::milliseconds(50));
|
||||||
}
|
}
|
||||||
@ -355,149 +365,55 @@ bool CVCMIServer::prepareToStartGame()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CVCMIServer::startGameImmidiately()
|
void CVCMIServer::startGameImmediately()
|
||||||
{
|
{
|
||||||
for(auto c : connections)
|
for(auto c : activeConnections)
|
||||||
c->enterGameplayConnectionMode(gh->gs);
|
c->enterGameplayConnectionMode(gh->gs);
|
||||||
|
|
||||||
|
gh->start(si->mode == StartInfo::LOAD_GAME);
|
||||||
state = EServerState::GAMEPLAY;
|
state = EServerState::GAMEPLAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CVCMIServer::startAsyncAccept()
|
void CVCMIServer::onDisconnected(const std::shared_ptr<NetworkConnection> & connection)
|
||||||
{
|
{
|
||||||
assert(!upcomingConnection);
|
logNetwork->error("Network error receiving a pack. Connection has been closed");
|
||||||
assert(acceptor);
|
|
||||||
|
|
||||||
#if BOOST_VERSION >= 107000 // Boost version >= 1.70
|
std::shared_ptr<CConnection> c = findConnection(connection);
|
||||||
upcomingConnection = std::make_shared<TSocket>(acceptor->get_executor());
|
|
||||||
#else
|
|
||||||
upcomingConnection = std::make_shared<TSocket>(acceptor->get_io_service());
|
|
||||||
#endif
|
|
||||||
acceptor->async_accept(*upcomingConnection, std::bind(&CVCMIServer::connectionAccepted, this, _1));
|
|
||||||
}
|
|
||||||
|
|
||||||
void CVCMIServer::connectionAccepted(const boost::system::error_code & ec)
|
inactiveConnections.push_back(c);
|
||||||
{
|
vstd::erase(activeConnections, c);
|
||||||
if(ec)
|
|
||||||
|
if(activeConnections.empty() || hostClientId == c->connectionID)
|
||||||
|
state = EServerState::SHUTDOWN;
|
||||||
|
|
||||||
|
if(gh && state == EServerState::GAMEPLAY)
|
||||||
{
|
{
|
||||||
if(state != EServerState::SHUTDOWN)
|
gh->handleClientDisconnection(c);
|
||||||
logNetwork->info("Something wrong during accepting: %s", ec.message());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if(state == EServerState::LOBBY || !hangingConnections.empty())
|
|
||||||
{
|
|
||||||
logNetwork->info("We got a new connection! :)");
|
|
||||||
auto c = std::make_shared<CConnection>(upcomingConnection, SERVER_NAME, uuid);
|
|
||||||
upcomingConnection.reset();
|
|
||||||
connections.insert(c);
|
|
||||||
c->handler = std::make_shared<boost::thread>(&CVCMIServer::threadHandleClient, this, c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(std::exception & e)
|
|
||||||
{
|
|
||||||
logNetwork->error("Failure processing new connection! %s", e.what());
|
|
||||||
upcomingConnection.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
startAsyncAccept();
|
|
||||||
}
|
|
||||||
|
|
||||||
class CVCMIServerPackVisitor : public VCMI_LIB_WRAP_NAMESPACE(ICPackVisitor)
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
CVCMIServer & handler;
|
|
||||||
std::shared_ptr<CGameHandler> gh;
|
|
||||||
|
|
||||||
public:
|
|
||||||
CVCMIServerPackVisitor(CVCMIServer & handler, std::shared_ptr<CGameHandler> gh)
|
|
||||||
:handler(handler), gh(gh)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool callTyped() override { return false; }
|
|
||||||
|
|
||||||
virtual void visitForLobby(CPackForLobby & packForLobby) override
|
|
||||||
{
|
|
||||||
handler.handleReceivedPack(std::unique_ptr<CPackForLobby>(&packForLobby));
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void visitForServer(CPackForServer & serverPack) override
|
|
||||||
{
|
|
||||||
if (gh)
|
|
||||||
gh->handleReceivedPack(&serverPack);
|
|
||||||
else
|
|
||||||
logNetwork->error("Received pack for game server while in lobby!");
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void visitForClient(CPackForClient & clientPack) override
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void CVCMIServer::threadHandleClient(std::shared_ptr<CConnection> c)
|
|
||||||
{
|
|
||||||
setThreadName("handleClient");
|
|
||||||
c->enterLobbyConnectionMode();
|
|
||||||
|
|
||||||
while(c->connected)
|
|
||||||
{
|
|
||||||
CPack * pack;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
pack = c->retrievePack();
|
|
||||||
pack->c = c;
|
|
||||||
}
|
|
||||||
catch(boost::system::system_error & e)
|
|
||||||
{
|
|
||||||
if (e.code() == boost::asio::error::eof)
|
|
||||||
logNetwork->error("Network error receiving a pack. Connection has been closed");
|
|
||||||
else
|
|
||||||
logNetwork->error("Network error receiving a pack. Connection %s dies. What happened: %s", c->toString(), e.what());
|
|
||||||
|
|
||||||
hangingConnections.insert(c);
|
|
||||||
connections.erase(c);
|
|
||||||
if(connections.empty() || hostClient == c)
|
|
||||||
state = EServerState::SHUTDOWN;
|
|
||||||
|
|
||||||
if(gh && state == EServerState::GAMEPLAY)
|
|
||||||
{
|
|
||||||
gh->handleClientDisconnection(c);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
CVCMIServerPackVisitor visitor(*this, this->gh);
|
|
||||||
pack->visit(visitor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::unique_lock<boost::recursive_mutex> queueLock(mx);
|
boost::unique_lock<boost::recursive_mutex> queueLock(mx);
|
||||||
|
|
||||||
if(c->connected)
|
// if(c->connected)
|
||||||
{
|
// {
|
||||||
auto lcd = std::make_unique<LobbyClientDisconnected>();
|
// auto lcd = std::make_unique<LobbyClientDisconnected>();
|
||||||
lcd->c = c;
|
// lcd->c = c;
|
||||||
lcd->clientId = c->connectionID;
|
// lcd->clientId = c->connectionID;
|
||||||
handleReceivedPack(std::move(lcd));
|
// handleReceivedPack(std::move(lcd));
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
logNetwork->info("Thread listening for %s ended", c->toString());
|
// logNetwork->info("Thread listening for %s ended", c->toString());
|
||||||
c->handler.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CVCMIServer::handleReceivedPack(std::unique_ptr<CPackForLobby> pack)
|
void CVCMIServer::handleReceivedPack(std::unique_ptr<CPackForLobby> pack)
|
||||||
{
|
{
|
||||||
CBaseForServerApply * apply = applier->getApplier(CTypeList::getInstance().getTypeID(pack.get()));
|
CBaseForServerApply * apply = applier->getApplier(CTypeList::getInstance().getTypeID(pack.get()));
|
||||||
if(apply->applyOnServerBefore(this, pack.get()))
|
if(apply->applyOnServerBefore(this, pack.get()))
|
||||||
addToAnnounceQueue(std::move(pack));
|
announcePack(std::move(pack));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CVCMIServer::announcePack(std::unique_ptr<CPackForLobby> pack)
|
void CVCMIServer::announcePack(std::unique_ptr<CPackForLobby> pack)
|
||||||
{
|
{
|
||||||
for(auto c : connections)
|
for(auto c : activeConnections)
|
||||||
{
|
{
|
||||||
// FIXME: we need to avoid sending something to client that not yet get answer for LobbyClientConnected
|
// FIXME: we need to avoid sending something to client that not yet get answer for LobbyClientConnected
|
||||||
// Until UUID set we only pass LobbyClientConnected to this client
|
// Until UUID set we only pass LobbyClientConnected to this client
|
||||||
@ -515,7 +431,7 @@ void CVCMIServer::announceMessage(const std::string & txt)
|
|||||||
logNetwork->info("Show message: %s", txt);
|
logNetwork->info("Show message: %s", txt);
|
||||||
auto cm = std::make_unique<LobbyShowMessage>();
|
auto cm = std::make_unique<LobbyShowMessage>();
|
||||||
cm->message = txt;
|
cm->message = txt;
|
||||||
addToAnnounceQueue(std::move(cm));
|
announcePack(std::move(cm));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CVCMIServer::announceTxt(const std::string & txt, const std::string & playerName)
|
void CVCMIServer::announceTxt(const std::string & txt, const std::string & playerName)
|
||||||
@ -524,25 +440,18 @@ void CVCMIServer::announceTxt(const std::string & txt, const std::string & playe
|
|||||||
auto cm = std::make_unique<LobbyChatMessage>();
|
auto cm = std::make_unique<LobbyChatMessage>();
|
||||||
cm->playerName = playerName;
|
cm->playerName = playerName;
|
||||||
cm->message = txt;
|
cm->message = txt;
|
||||||
addToAnnounceQueue(std::move(cm));
|
announcePack(std::move(cm));
|
||||||
}
|
|
||||||
|
|
||||||
void CVCMIServer::addToAnnounceQueue(std::unique_ptr<CPackForLobby> pack)
|
|
||||||
{
|
|
||||||
boost::unique_lock<boost::recursive_mutex> queueLock(mx);
|
|
||||||
announceQueue.push_back(std::move(pack));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CVCMIServer::passHost(int toConnectionId)
|
bool CVCMIServer::passHost(int toConnectionId)
|
||||||
{
|
{
|
||||||
for(auto c : connections)
|
for(auto c : activeConnections)
|
||||||
{
|
{
|
||||||
if(isClientHost(c->connectionID))
|
if(isClientHost(c->connectionID))
|
||||||
continue;
|
continue;
|
||||||
if(c->connectionID != toConnectionId)
|
if(c->connectionID != toConnectionId)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
hostClient = c;
|
|
||||||
hostClientId = c->connectionID;
|
hostClientId = c->connectionID;
|
||||||
announceTxt(boost::str(boost::format("Pass host to connection %d") % toConnectionId));
|
announceTxt(boost::str(boost::format("Pass host to connection %d") % toConnectionId));
|
||||||
return true;
|
return true;
|
||||||
@ -555,9 +464,8 @@ void CVCMIServer::clientConnected(std::shared_ptr<CConnection> c, std::vector<st
|
|||||||
if(state == EServerState::LOBBY)
|
if(state == EServerState::LOBBY)
|
||||||
c->connectionID = currentClientId++;
|
c->connectionID = currentClientId++;
|
||||||
|
|
||||||
if(!hostClient)
|
if(hostClientId == -1)
|
||||||
{
|
{
|
||||||
hostClient = c;
|
|
||||||
hostClientId = c->connectionID;
|
hostClientId = c->connectionID;
|
||||||
si->mode = mode;
|
si->mode = mode;
|
||||||
}
|
}
|
||||||
@ -592,8 +500,9 @@ void CVCMIServer::clientConnected(std::shared_ptr<CConnection> c, std::vector<st
|
|||||||
|
|
||||||
void CVCMIServer::clientDisconnected(std::shared_ptr<CConnection> c)
|
void CVCMIServer::clientDisconnected(std::shared_ptr<CConnection> c)
|
||||||
{
|
{
|
||||||
connections -= c;
|
vstd::erase(activeConnections, c);
|
||||||
if(connections.empty() || hostClient == c)
|
|
||||||
|
if(activeConnections.empty() || hostClientId == c->connectionID)
|
||||||
{
|
{
|
||||||
state = EServerState::SHUTDOWN;
|
state = EServerState::SHUTDOWN;
|
||||||
return;
|
return;
|
||||||
@ -626,7 +535,7 @@ void CVCMIServer::clientDisconnected(std::shared_ptr<CConnection> c)
|
|||||||
if(gh && si && state == EServerState::GAMEPLAY)
|
if(gh && si && state == EServerState::GAMEPLAY)
|
||||||
{
|
{
|
||||||
gh->playerMessages->broadcastMessage(playerSettings->color, playerLeftMsgText);
|
gh->playerMessages->broadcastMessage(playerSettings->color, playerLeftMsgText);
|
||||||
gh->connections[playerSettings->color].insert(hostClient);
|
// gh->connections[playerSettings->color].insert(hostClient);
|
||||||
startAiPack.players.push_back(playerSettings->color);
|
startAiPack.players.push_back(playerSettings->color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -753,7 +662,6 @@ void CVCMIServer::updateStartInfoOnMapChange(std::shared_ptr<CMapInfo> mapInfo,
|
|||||||
|
|
||||||
void CVCMIServer::updateAndPropagateLobbyState()
|
void CVCMIServer::updateAndPropagateLobbyState()
|
||||||
{
|
{
|
||||||
boost::unique_lock<boost::mutex> stateLock(stateMutex);
|
|
||||||
// Update player settings for RMG
|
// Update player settings for RMG
|
||||||
// TODO: find appropriate location for this code
|
// TODO: find appropriate location for this code
|
||||||
if(si->mapGenOptions && si->mode == StartInfo::NEW_GAME)
|
if(si->mapGenOptions && si->mode == StartInfo::NEW_GAME)
|
||||||
@ -772,7 +680,7 @@ void CVCMIServer::updateAndPropagateLobbyState()
|
|||||||
|
|
||||||
auto lus = std::make_unique<LobbyUpdateState>();
|
auto lus = std::make_unique<LobbyUpdateState>();
|
||||||
lus->state = *this;
|
lus->state = *this;
|
||||||
addToAnnounceQueue(std::move(lus));
|
announcePack(std::move(lus));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CVCMIServer::setPlayer(PlayerColor clickedColor)
|
void CVCMIServer::setPlayer(PlayerColor clickedColor)
|
||||||
@ -1188,32 +1096,9 @@ int main(int argc, const char * argv[])
|
|||||||
cond->notify_one();
|
cond->notify_one();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
try
|
CVCMIServer server(opts);
|
||||||
{
|
server.run();
|
||||||
boost::asio::io_service io_service;
|
|
||||||
CVCMIServer server(opts);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
while(server.getState() != EServerState::SHUTDOWN)
|
|
||||||
{
|
|
||||||
server.run();
|
|
||||||
}
|
|
||||||
io_service.run();
|
|
||||||
}
|
|
||||||
catch(boost::system::system_error & e) //for boost errors just log, not crash - probably client shut down connection
|
|
||||||
{
|
|
||||||
logNetwork->error(e.what());
|
|
||||||
server.setState(EServerState::SHUTDOWN);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(boost::system::system_error & e)
|
|
||||||
{
|
|
||||||
logNetwork->error(e.what());
|
|
||||||
//catch any startup errors (e.g. can't access port) errors
|
|
||||||
//and return non-zero status so client can detect error
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
#if VCMI_ANDROID_DUAL_PROCESS
|
#if VCMI_ANDROID_DUAL_PROCESS
|
||||||
CAndroidVMHelper envHelper;
|
CAndroidVMHelper envHelper;
|
||||||
envHelper.callStaticVoidMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "killServer");
|
envHelper.callStaticVoidMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "killServer");
|
||||||
|
@ -9,10 +9,10 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../lib/serializer/Connection.h"
|
#include "../lib/network/NetworkListener.h"
|
||||||
#include "../lib/StartInfo.h"
|
#include "../lib/StartInfo.h"
|
||||||
|
|
||||||
#include <boost/program_options.hpp>
|
#include <boost/program_options/variables_map.hpp>
|
||||||
|
|
||||||
#if defined(VCMI_ANDROID) && !defined(SINGLE_PROCESS_APP)
|
#if defined(VCMI_ANDROID) && !defined(SINGLE_PROCESS_APP)
|
||||||
#define VCMI_ANDROID_DUAL_PROCESS 1
|
#define VCMI_ANDROID_DUAL_PROCESS 1
|
||||||
@ -24,6 +24,7 @@ class CMapInfo;
|
|||||||
|
|
||||||
struct CPackForLobby;
|
struct CPackForLobby;
|
||||||
|
|
||||||
|
class CConnection;
|
||||||
struct StartInfo;
|
struct StartInfo;
|
||||||
struct LobbyInfo;
|
struct LobbyInfo;
|
||||||
struct PlayerSettings;
|
struct PlayerSettings;
|
||||||
@ -46,53 +47,66 @@ enum class EServerState : ui8
|
|||||||
SHUTDOWN
|
SHUTDOWN
|
||||||
};
|
};
|
||||||
|
|
||||||
class CVCMIServer : public LobbyInfo
|
class CVCMIServer : public LobbyInfo, public INetworkServerListener, public INetworkClientListener
|
||||||
{
|
{
|
||||||
|
/// Network server instance that receives and processes incoming connections on active socket
|
||||||
|
std::unique_ptr<NetworkServer> networkServer;
|
||||||
|
|
||||||
|
/// Outgoing connection established by this server to game lobby for proxy mode (only in lobby game)
|
||||||
|
std::unique_ptr<NetworkClient> outgoingConnection;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// List of all active connections
|
||||||
|
std::vector<std::shared_ptr<CConnection>> activeConnections;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// List of all connections that were closed (but can still reconnect later)
|
||||||
|
std::vector<std::shared_ptr<CConnection>> inactiveConnections;
|
||||||
|
|
||||||
std::atomic<bool> restartGameplay; // FIXME: this is just a hack
|
std::atomic<bool> restartGameplay; // FIXME: this is just a hack
|
||||||
std::shared_ptr<boost::asio::io_service> io;
|
|
||||||
std::shared_ptr<TAcceptor> acceptor;
|
|
||||||
std::shared_ptr<TSocket> upcomingConnection;
|
|
||||||
std::list<std::unique_ptr<CPackForLobby>> announceQueue;
|
|
||||||
boost::recursive_mutex mx;
|
boost::recursive_mutex mx;
|
||||||
std::shared_ptr<CApplier<CBaseForServerApply>> applier;
|
std::shared_ptr<CApplier<CBaseForServerApply>> applier;
|
||||||
std::unique_ptr<boost::thread> announceLobbyThread;
|
|
||||||
std::unique_ptr<boost::thread> remoteConnectionsThread;
|
std::unique_ptr<boost::thread> remoteConnectionsThread;
|
||||||
std::atomic<EServerState> state;
|
std::atomic<EServerState> state;
|
||||||
|
|
||||||
public:
|
// INetworkServerListener impl
|
||||||
std::shared_ptr<CGameHandler> gh;
|
void onDisconnected(const std::shared_ptr<NetworkConnection> & connection) override;
|
||||||
ui16 port;
|
void onPacketReceived(const std::shared_ptr<NetworkConnection> & connection, const std::vector<uint8_t> & message) override;
|
||||||
|
void onNewConnection(const std::shared_ptr<NetworkConnection> &) override;
|
||||||
|
|
||||||
boost::program_options::variables_map cmdLineOptions;
|
// INetworkClientListener impl
|
||||||
std::set<std::shared_ptr<CConnection>> connections;
|
void onPacketReceived(const std::vector<uint8_t> & message) override;
|
||||||
std::set<std::shared_ptr<CConnection>> remoteConnections;
|
void onConnectionFailed(const std::string & errorMessage) override;
|
||||||
std::set<std::shared_ptr<CConnection>> hangingConnections; //keep connections of players disconnected during the game
|
void onConnectionEstablished() override;
|
||||||
|
void onDisconnected() override;
|
||||||
|
|
||||||
|
void establishOutgoingConnection();
|
||||||
|
|
||||||
|
std::shared_ptr<CConnection> findConnection(const std::shared_ptr<NetworkConnection> &);
|
||||||
|
|
||||||
std::atomic<int> currentClientId;
|
std::atomic<int> currentClientId;
|
||||||
std::atomic<ui8> currentPlayerId;
|
std::atomic<ui8> currentPlayerId;
|
||||||
std::shared_ptr<CConnection> hostClient;
|
|
||||||
|
public:
|
||||||
|
std::shared_ptr<CGameHandler> gh;
|
||||||
|
boost::program_options::variables_map cmdLineOptions;
|
||||||
|
|
||||||
CVCMIServer(boost::program_options::variables_map & opts);
|
CVCMIServer(boost::program_options::variables_map & opts);
|
||||||
~CVCMIServer();
|
~CVCMIServer();
|
||||||
|
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
bool prepareToStartGame();
|
bool prepareToStartGame();
|
||||||
void prepareToRestart();
|
void prepareToRestart();
|
||||||
void startGameImmidiately();
|
void startGameImmediately();
|
||||||
|
|
||||||
void establishRemoteConnections();
|
|
||||||
void connectToRemote();
|
|
||||||
void startAsyncAccept();
|
|
||||||
void connectionAccepted(const boost::system::error_code & ec);
|
|
||||||
void threadHandleClient(std::shared_ptr<CConnection> c);
|
void threadHandleClient(std::shared_ptr<CConnection> c);
|
||||||
void threadAnnounceLobby();
|
|
||||||
void handleReceivedPack(std::unique_ptr<CPackForLobby> pack);
|
|
||||||
|
|
||||||
void announcePack(std::unique_ptr<CPackForLobby> pack);
|
void announcePack(std::unique_ptr<CPackForLobby> pack);
|
||||||
bool passHost(int toConnectionId);
|
bool passHost(int toConnectionId);
|
||||||
|
|
||||||
void announceTxt(const std::string & txt, const std::string & playerName = "system");
|
void announceTxt(const std::string & txt, const std::string & playerName = "system");
|
||||||
void announceMessage(const std::string & txt);
|
|
||||||
void addToAnnounceQueue(std::unique_ptr<CPackForLobby> pack);
|
|
||||||
|
|
||||||
void setPlayerConnectedId(PlayerSettings & pset, ui8 player) const;
|
void setPlayerConnectedId(PlayerSettings & pset, ui8 player) const;
|
||||||
void updateStartInfoOnMapChange(std::shared_ptr<CMapInfo> mapInfo, std::shared_ptr<CMapGenOptions> mapGenOpt = {});
|
void updateStartInfoOnMapChange(std::shared_ptr<CMapInfo> mapInfo, std::shared_ptr<CMapGenOptions> mapGenOpt = {});
|
||||||
@ -101,6 +115,11 @@ public:
|
|||||||
void clientDisconnected(std::shared_ptr<CConnection> c);
|
void clientDisconnected(std::shared_ptr<CConnection> c);
|
||||||
void reconnectPlayer(int connId);
|
void reconnectPlayer(int connId);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void announceMessage(const std::string & txt);
|
||||||
|
|
||||||
|
void handleReceivedPack(std::unique_ptr<CPackForLobby> pack);
|
||||||
|
|
||||||
void updateAndPropagateLobbyState();
|
void updateAndPropagateLobbyState();
|
||||||
|
|
||||||
void setState(EServerState value);
|
void setState(EServerState value);
|
||||||
|
@ -13,11 +13,9 @@
|
|||||||
#include "CVCMIServer.h"
|
#include "CVCMIServer.h"
|
||||||
#include "CGameHandler.h"
|
#include "CGameHandler.h"
|
||||||
|
|
||||||
#include "../lib/serializer/Connection.h"
|
|
||||||
#include "../lib/StartInfo.h"
|
#include "../lib/StartInfo.h"
|
||||||
|
|
||||||
// Campaigns
|
|
||||||
#include "../lib/campaign/CampaignState.h"
|
#include "../lib/campaign/CampaignState.h"
|
||||||
|
#include "../lib/serializer/Connection.h"
|
||||||
|
|
||||||
void ClientPermissionsCheckerNetPackVisitor::visitForLobby(CPackForLobby & pack)
|
void ClientPermissionsCheckerNetPackVisitor::visitForLobby(CPackForLobby & pack)
|
||||||
{
|
{
|
||||||
@ -38,67 +36,18 @@ void ApplyOnServerAfterAnnounceNetPackVisitor::visitForLobby(CPackForLobby & pac
|
|||||||
|
|
||||||
void ClientPermissionsCheckerNetPackVisitor::visitLobbyClientConnected(LobbyClientConnected & pack)
|
void ClientPermissionsCheckerNetPackVisitor::visitLobbyClientConnected(LobbyClientConnected & pack)
|
||||||
{
|
{
|
||||||
if(srv.gh)
|
|
||||||
{
|
|
||||||
for(auto & connection : srv.hangingConnections)
|
|
||||||
{
|
|
||||||
if(connection->uuid == pack.uuid)
|
|
||||||
{
|
|
||||||
{
|
|
||||||
result = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(srv.getState() == EServerState::LOBBY)
|
if(srv.getState() == EServerState::LOBBY)
|
||||||
{
|
{
|
||||||
result = true;
|
result = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//disconnect immediately and ignore this client
|
|
||||||
srv.connections.erase(pack.c);
|
|
||||||
if(pack.c && pack.c->isOpen())
|
|
||||||
{
|
|
||||||
pack.c->close();
|
|
||||||
pack.c->connected = false;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
result = false;
|
result = false;
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplyOnServerNetPackVisitor::visitLobbyClientConnected(LobbyClientConnected & pack)
|
void ApplyOnServerNetPackVisitor::visitLobbyClientConnected(LobbyClientConnected & pack)
|
||||||
{
|
{
|
||||||
if(srv.gh)
|
|
||||||
{
|
|
||||||
for(auto & connection : srv.hangingConnections)
|
|
||||||
{
|
|
||||||
if(connection->uuid == pack.uuid)
|
|
||||||
{
|
|
||||||
logNetwork->info("Reconnection player");
|
|
||||||
pack.c->connectionID = connection->connectionID;
|
|
||||||
for(auto & playerConnection : srv.gh->connections)
|
|
||||||
{
|
|
||||||
for(auto & existingConnection : playerConnection.second)
|
|
||||||
{
|
|
||||||
if(existingConnection == connection)
|
|
||||||
{
|
|
||||||
playerConnection.second.erase(existingConnection);
|
|
||||||
playerConnection.second.insert(pack.c);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
srv.hangingConnections.erase(connection);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
srv.clientConnected(pack.c, pack.names, pack.uuid, pack.mode);
|
srv.clientConnected(pack.c, pack.names, pack.uuid, pack.mode);
|
||||||
// Server need to pass some data to newly connected client
|
// Server need to pass some data to newly connected client
|
||||||
pack.clientId = pack.c->connectionID;
|
pack.clientId = pack.c->connectionID;
|
||||||
@ -121,7 +70,7 @@ void ApplyOnServerAfterAnnounceNetPackVisitor::visitLobbyClientConnected(LobbyCl
|
|||||||
startGameForReconnectedPlayer->initializedStartInfo = srv.si;
|
startGameForReconnectedPlayer->initializedStartInfo = srv.si;
|
||||||
startGameForReconnectedPlayer->initializedGameState = srv.gh->gameState();
|
startGameForReconnectedPlayer->initializedGameState = srv.gh->gameState();
|
||||||
startGameForReconnectedPlayer->clientId = pack.c->connectionID;
|
startGameForReconnectedPlayer->clientId = pack.c->connectionID;
|
||||||
srv.addToAnnounceQueue(std::move(startGameForReconnectedPlayer));
|
srv.announcePack(std::move(startGameForReconnectedPlayer));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,38 +103,28 @@ void ClientPermissionsCheckerNetPackVisitor::visitLobbyClientDisconnected(LobbyC
|
|||||||
void ApplyOnServerNetPackVisitor::visitLobbyClientDisconnected(LobbyClientDisconnected & pack)
|
void ApplyOnServerNetPackVisitor::visitLobbyClientDisconnected(LobbyClientDisconnected & pack)
|
||||||
{
|
{
|
||||||
srv.clientDisconnected(pack.c);
|
srv.clientDisconnected(pack.c);
|
||||||
pack.c->close();
|
|
||||||
pack.c->connected = false;
|
|
||||||
|
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplyOnServerAfterAnnounceNetPackVisitor::visitLobbyClientDisconnected(LobbyClientDisconnected & pack)
|
void ApplyOnServerAfterAnnounceNetPackVisitor::visitLobbyClientDisconnected(LobbyClientDisconnected & pack)
|
||||||
{
|
{
|
||||||
if(pack.c && pack.c->isOpen())
|
|
||||||
{
|
|
||||||
boost::unique_lock<boost::mutex> lock(*pack.c->mutexWrite);
|
|
||||||
pack.c->close();
|
|
||||||
pack.c->connected = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pack.shutdownServer)
|
if(pack.shutdownServer)
|
||||||
{
|
{
|
||||||
logNetwork->info("Client requested shutdown, server will close itself...");
|
logNetwork->info("Client requested shutdown, server will close itself...");
|
||||||
srv.setState(EServerState::SHUTDOWN);
|
srv.setState(EServerState::SHUTDOWN);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if(srv.connections.empty())
|
else if(srv.activeConnections.empty())
|
||||||
{
|
{
|
||||||
logNetwork->error("Last connection lost, server will close itself...");
|
logNetwork->error("Last connection lost, server will close itself...");
|
||||||
srv.setState(EServerState::SHUTDOWN);
|
srv.setState(EServerState::SHUTDOWN);
|
||||||
}
|
}
|
||||||
else if(pack.c == srv.hostClient)
|
else if(pack.c->connectionID == srv.hostClientId)
|
||||||
{
|
{
|
||||||
auto ph = std::make_unique<LobbyChangeHost>();
|
auto ph = std::make_unique<LobbyChangeHost>();
|
||||||
auto newHost = *RandomGeneratorUtil::nextItem(srv.connections, CRandomGenerator::getDefault());
|
auto newHost = srv.activeConnections.front();
|
||||||
ph->newHostConnectionId = newHost->connectionID;
|
ph->newHostConnectionId = newHost->connectionID;
|
||||||
srv.addToAnnounceQueue(std::move(ph));
|
srv.announcePack(std::move(ph));
|
||||||
}
|
}
|
||||||
srv.updateAndPropagateLobbyState();
|
srv.updateAndPropagateLobbyState();
|
||||||
|
|
||||||
@ -270,8 +209,7 @@ void ApplyOnServerNetPackVisitor::visitLobbyEndGame(LobbyEndGame & pack)
|
|||||||
|
|
||||||
void ApplyOnServerAfterAnnounceNetPackVisitor::visitLobbyEndGame(LobbyEndGame & pack)
|
void ApplyOnServerAfterAnnounceNetPackVisitor::visitLobbyEndGame(LobbyEndGame & pack)
|
||||||
{
|
{
|
||||||
boost::unique_lock<boost::mutex> stateLock(srv.stateMutex);
|
for(auto & c : srv.activeConnections)
|
||||||
for(auto & c : srv.connections)
|
|
||||||
{
|
{
|
||||||
c->enterLobbyConnectionMode();
|
c->enterLobbyConnectionMode();
|
||||||
c->disableStackSendingByID();
|
c->disableStackSendingByID();
|
||||||
@ -312,10 +250,10 @@ void ApplyOnServerNetPackVisitor::visitLobbyStartGame(LobbyStartGame & pack)
|
|||||||
void ApplyOnServerAfterAnnounceNetPackVisitor::visitLobbyStartGame(LobbyStartGame & pack)
|
void ApplyOnServerAfterAnnounceNetPackVisitor::visitLobbyStartGame(LobbyStartGame & pack)
|
||||||
{
|
{
|
||||||
if(pack.clientId == -1) //do not restart game for single client only
|
if(pack.clientId == -1) //do not restart game for single client only
|
||||||
srv.startGameImmidiately();
|
srv.startGameImmediately();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for(auto & c : srv.connections)
|
for(auto & c : srv.activeConnections)
|
||||||
{
|
{
|
||||||
if(c->connectionID == pack.clientId)
|
if(c->connectionID == pack.clientId)
|
||||||
{
|
{
|
||||||
|
@ -20,11 +20,11 @@
|
|||||||
|
|
||||||
#include "../lib/IGameCallback.h"
|
#include "../lib/IGameCallback.h"
|
||||||
#include "../lib/mapObjects/CGTownInstance.h"
|
#include "../lib/mapObjects/CGTownInstance.h"
|
||||||
|
#include "../lib/mapObjects/CGHeroInstance.h"
|
||||||
#include "../lib/gameState/CGameState.h"
|
#include "../lib/gameState/CGameState.h"
|
||||||
#include "../lib/battle/IBattleState.h"
|
#include "../lib/battle/IBattleState.h"
|
||||||
#include "../lib/battle/BattleAction.h"
|
#include "../lib/battle/BattleAction.h"
|
||||||
#include "../lib/battle/Unit.h"
|
#include "../lib/battle/Unit.h"
|
||||||
#include "../lib/serializer/Connection.h"
|
|
||||||
#include "../lib/spells/CSpellHandler.h"
|
#include "../lib/spells/CSpellHandler.h"
|
||||||
#include "../lib/spells/ISpellMechanics.h"
|
#include "../lib/spells/ISpellMechanics.h"
|
||||||
#include "../lib/serializer/Cast.h"
|
#include "../lib/serializer/Cast.h"
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
#include "../CGameHandler.h"
|
#include "../CGameHandler.h"
|
||||||
#include "../CVCMIServer.h"
|
#include "../CVCMIServer.h"
|
||||||
|
|
||||||
#include "../../lib/serializer/Connection.h"
|
|
||||||
#include "../../lib/CGeneralTextHandler.h"
|
#include "../../lib/CGeneralTextHandler.h"
|
||||||
#include "../../lib/CHeroHandler.h"
|
#include "../../lib/CHeroHandler.h"
|
||||||
#include "../../lib/modding/IdentifierStorage.h"
|
#include "../../lib/modding/IdentifierStorage.h"
|
||||||
@ -22,11 +21,13 @@
|
|||||||
#include "../../lib/StartInfo.h"
|
#include "../../lib/StartInfo.h"
|
||||||
#include "../../lib/gameState/CGameState.h"
|
#include "../../lib/gameState/CGameState.h"
|
||||||
#include "../../lib/mapObjects/CGTownInstance.h"
|
#include "../../lib/mapObjects/CGTownInstance.h"
|
||||||
|
#include "../../lib/mapObjects/CGHeroInstance.h"
|
||||||
#include "../../lib/modding/IdentifierStorage.h"
|
#include "../../lib/modding/IdentifierStorage.h"
|
||||||
#include "../../lib/modding/ModScope.h"
|
#include "../../lib/modding/ModScope.h"
|
||||||
#include "../../lib/mapping/CMap.h"
|
#include "../../lib/mapping/CMap.h"
|
||||||
#include "../../lib/networkPacks/PacksForClient.h"
|
#include "../../lib/networkPacks/PacksForClient.h"
|
||||||
#include "../../lib/networkPacks/StackLocation.h"
|
#include "../../lib/networkPacks/StackLocation.h"
|
||||||
|
#include "../../lib/serializer/Connection.h"
|
||||||
|
|
||||||
PlayerMessageProcessor::PlayerMessageProcessor()
|
PlayerMessageProcessor::PlayerMessageProcessor()
|
||||||
:gameHandler(nullptr)
|
:gameHandler(nullptr)
|
||||||
@ -62,10 +63,7 @@ bool PlayerMessageProcessor::handleHostCommand(PlayerColor player, const std::st
|
|||||||
std::vector<std::string> words;
|
std::vector<std::string> words;
|
||||||
boost::split(words, message, boost::is_any_of(" "));
|
boost::split(words, message, boost::is_any_of(" "));
|
||||||
|
|
||||||
bool isHost = false;
|
bool isHost = gameHandler->gameLobby()->isPlayerHost(player);
|
||||||
for(auto & c : gameHandler->connections[player])
|
|
||||||
if(gameHandler->gameLobby()->isClientHost(c->connectionID))
|
|
||||||
isHost = true;
|
|
||||||
|
|
||||||
if(!isHost || words.size() < 2 || words[0] != "game")
|
if(!isHost || words.size() < 2 || words[0] != "game")
|
||||||
return false;
|
return false;
|
||||||
|
Loading…
Reference in New Issue
Block a user