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/mapObjects/MiscObjects.h"
|
||||
#include "../lib/modding/ModIncompatibility.h"
|
||||
#include "../lib/network/NetworkClient.h"
|
||||
#include "../lib/rmg/CMapGenOptions.h"
|
||||
#include "../lib/serializer/Connection.h"
|
||||
#include "../lib/filesystem/Filesystem.h"
|
||||
#include "../lib/registerTypes/RegisterTypesLobbyPacks.h"
|
||||
#include "../lib/serializer/Connection.h"
|
||||
#include "../lib/serializer/CMemorySerializer.h"
|
||||
#include "../lib/UnlockGuard.h"
|
||||
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
#include <boost/uuid/uuid_generators.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include "../lib/serializer/Cast.h"
|
||||
#include "LobbyClientNetPackVisitors.h"
|
||||
|
||||
@ -131,8 +131,16 @@ public:
|
||||
static const std::string NAME_AFFIX = "client";
|
||||
static const std::string NAME = GameConstants::VCMI_VERSION + std::string(" (") + NAME_AFFIX + ')'; //application name
|
||||
|
||||
CServerHandler::~CServerHandler() = default;
|
||||
|
||||
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()());
|
||||
//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());
|
||||
}
|
||||
|
||||
void CServerHandler::startLocalServerAndConnect()
|
||||
void CServerHandler::startLocalServerAndConnect(const std::function<void()> & onConnected)
|
||||
{
|
||||
if(threadRunLocalServer)
|
||||
threadRunLocalServer->join();
|
||||
@ -169,17 +177,13 @@ void CServerHandler::startLocalServerAndConnect()
|
||||
th->update();
|
||||
|
||||
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");
|
||||
CInfoWindow::showInfoDialog(errorMsg, {});
|
||||
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)
|
||||
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
|
||||
|
||||
justConnectToServer(localhostAddress, 0);
|
||||
justConnectToServer(localhostAddress, 0, onConnected);
|
||||
|
||||
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;
|
||||
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())
|
||||
{
|
||||
@ -286,13 +267,39 @@ void CServerHandler::justConnectToServer(const std::string & addr, const ui16 po
|
||||
Settings serverPort = settings.write["server"]["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()
|
||||
{
|
||||
if(!c || !c->handler)
|
||||
return;
|
||||
|
||||
boost::unique_lock<boost::recursive_mutex> lock(*mx);
|
||||
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()
|
||||
{
|
||||
return clientHumanColors(c->connectionID);
|
||||
@ -421,7 +418,6 @@ void CServerHandler::sendClientDisconnecting()
|
||||
{
|
||||
// Network thread might be applying network pack at this moment
|
||||
auto unlockInterface = vstd::makeUnlockGuard(GH.interfaceMutex);
|
||||
c->close();
|
||||
c.reset();
|
||||
}
|
||||
}
|
||||
@ -814,7 +810,7 @@ void CServerHandler::restoreLastSession()
|
||||
myNames.push_back(name.String());
|
||||
resetStateForLobby(StartInfo::LOAD_GAME, &myNames);
|
||||
screenType = ESelectionScreen::loadGame;
|
||||
justConnectToServer(settings["server"]["server"].String(), settings["server"]["port"].Integer());
|
||||
justConnectToServer(settings["server"]["server"].String(), settings["server"]["port"].Integer(), {});
|
||||
};
|
||||
|
||||
auto cleanUpSession = []()
|
||||
@ -844,9 +840,9 @@ void CServerHandler::debugStartTest(std::string filename, bool save)
|
||||
screenType = ESelectionScreen::newGame;
|
||||
}
|
||||
if(settings["session"]["donotstartserver"].Bool())
|
||||
justConnectToServer(localhostAddress, 3030);
|
||||
justConnectToServer(localhostAddress, 3030, {});
|
||||
else
|
||||
startLocalServerAndConnect();
|
||||
startLocalServerAndConnect({});
|
||||
|
||||
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");
|
||||
c->enterLobbyConnectionMode();
|
||||
|
||||
try
|
||||
CPack * pack = c->retrievePack(message);
|
||||
if(state == EClientState::DISCONNECTING)
|
||||
{
|
||||
sendClientConnecting();
|
||||
while(c && c->connected)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
//catch only asio exceptions
|
||||
catch(const boost::system::system_error & e)
|
||||
else
|
||||
{
|
||||
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
|
||||
{
|
||||
if (e.code() == boost::asio::error::eof)
|
||||
logNetwork->error("Lost connection to server, ending listening thread! Connection has been closed");
|
||||
else
|
||||
logNetwork->error("Lost connection to server, ending listening thread! Reason: %s", e.what());
|
||||
|
||||
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);
|
||||
}
|
||||
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/network/NetworkListener.h"
|
||||
#include "../lib/StartInfo.h"
|
||||
#include "../lib/CondSh.h"
|
||||
|
||||
@ -80,8 +81,10 @@ public:
|
||||
};
|
||||
|
||||
/// 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;
|
||||
|
||||
std::shared_ptr<CApplier<CBaseForLobbyApply>> applier;
|
||||
@ -95,12 +98,18 @@ class CServerHandler : public IServerAPI, public LobbyInfo
|
||||
|
||||
std::shared_ptr<HighScoreCalculation> highScoreCalc;
|
||||
|
||||
void threadHandleConnection();
|
||||
void threadRunServer();
|
||||
void onServerFinished();
|
||||
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:
|
||||
std::shared_ptr<CConnection> c;
|
||||
|
||||
std::atomic<EClientState> state;
|
||||
////////////////////
|
||||
// FIXME: Bunch of crutches to glue it all together
|
||||
@ -115,7 +124,6 @@ public:
|
||||
std::unique_ptr<CStopWatch> th;
|
||||
std::shared_ptr<boost::thread> threadRunLocalServer;
|
||||
|
||||
std::shared_ptr<CConnection> c;
|
||||
CClient * client;
|
||||
|
||||
CondSh<bool> campaignServerRestartLock;
|
||||
@ -123,15 +131,15 @@ public:
|
||||
static const std::string localhostAddress;
|
||||
|
||||
CServerHandler();
|
||||
~CServerHandler();
|
||||
|
||||
std::string getHostAddress() const;
|
||||
ui16 getHostPort() const;
|
||||
|
||||
void resetStateForLobby(const StartInfo::EMode mode, const std::vector<std::string> * names = nullptr);
|
||||
void startLocalServerAndConnect();
|
||||
void justConnectToServer(const std::string & addr, const ui16 port);
|
||||
void startLocalServerAndConnect(const std::function<void()> & onConnected);
|
||||
void justConnectToServer(const std::string & addr, const ui16 port, const std::function<void()> & onConnected);
|
||||
void applyPacksOnLobbyScreen();
|
||||
void stopServerConnection();
|
||||
|
||||
// Helpers for lobby state access
|
||||
std::set<PlayerColor> getHumanColors();
|
||||
|
@ -30,11 +30,12 @@
|
||||
#include "../lib/UnlockGuard.h"
|
||||
#include "../lib/battle/BattleInfo.h"
|
||||
#include "../lib/serializer/BinaryDeserializer.h"
|
||||
#include "../lib/serializer/BinarySerializer.h"
|
||||
#include "../lib/serializer/Connection.h"
|
||||
#include "../lib/mapping/CMapService.h"
|
||||
#include "../lib/pathfinder/CGPathNode.h"
|
||||
#include "../lib/filesystem/Filesystem.h"
|
||||
#include "../lib/registerTypes/RegisterTypesClientPacks.h"
|
||||
#include "../lib/serializer/Connection.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vcmi/events/EventBus.h>
|
||||
|
@ -27,8 +27,8 @@
|
||||
#include "../CCallback.h"
|
||||
#include "../lib/filesystem/Filesystem.h"
|
||||
#include "../lib/filesystem/FileInfo.h"
|
||||
#include "../lib/serializer/Connection.h"
|
||||
#include "../lib/serializer/BinarySerializer.h"
|
||||
#include "../lib/serializer/Connection.h"
|
||||
#include "../lib/CGeneralTextHandler.h"
|
||||
#include "../lib/CHeroHandler.h"
|
||||
#include "../lib/VCMI_Lib.h"
|
||||
|
@ -54,8 +54,6 @@ void ApplyOnLobbyHandlerNetPackVisitor::visitLobbyClientDisconnected(LobbyClient
|
||||
result = false;
|
||||
return;
|
||||
}
|
||||
|
||||
handler.stopServerConnection();
|
||||
}
|
||||
|
||||
void ApplyOnLobbyScreenNetPackVisitor::visitLobbyClientDisconnected(LobbyClientDisconnected & pack)
|
||||
|
@ -47,7 +47,7 @@
|
||||
#include "../../lib/filesystem/Filesystem.h"
|
||||
#include "../../lib/mapping/CMapInfo.h"
|
||||
#include "../../lib/mapping/CMapHeader.h"
|
||||
#include "../../lib/serializer/Connection.h"
|
||||
#include "../../lib/CRandomGenerator.h"
|
||||
|
||||
ISelectionScreenInfo::ISelectionScreenInfo(ESelectionScreen ScreenType)
|
||||
: screenType(ScreenType)
|
||||
|
@ -43,7 +43,6 @@
|
||||
#include "../../lib/mapping/CMapHeader.h"
|
||||
#include "../../lib/mapping/MapFormat.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)
|
||||
{
|
||||
|
@ -45,7 +45,6 @@
|
||||
#include "../../lib/CGeneralTextHandler.h"
|
||||
#include "../../lib/JsonNode.h"
|
||||
#include "../../lib/campaign/CampaignHandler.h"
|
||||
#include "../../lib/serializer/Connection.h"
|
||||
#include "../../lib/serializer/CTypeList.h"
|
||||
#include "../../lib/filesystem/Filesystem.h"
|
||||
#include "../../lib/filesystem/CCompressedStream.h"
|
||||
@ -559,7 +558,7 @@ CSimpleJoinScreen::CSimpleJoinScreen(bool host)
|
||||
{
|
||||
textTitle->setText(CGI->generaltexth->translate("vcmi.mainMenu.serverConnecting"));
|
||||
buttonOk->block(true);
|
||||
startConnectThread();
|
||||
startConnection();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -582,7 +581,7 @@ void CSimpleJoinScreen::connectToServer()
|
||||
buttonOk->block(true);
|
||||
GH.stopTextInput();
|
||||
|
||||
startConnectThread(inputAddress->getText(), boost::lexical_cast<ui16>(inputPort->getText()));
|
||||
startConnection(inputAddress->getText(), boost::lexical_cast<ui16>(inputPort->getText()));
|
||||
}
|
||||
|
||||
void CSimpleJoinScreen::leaveScreen()
|
||||
@ -603,7 +602,7 @@ void CSimpleJoinScreen::onChange(const std::string & newText)
|
||||
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)
|
||||
// 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
|
||||
CVCMIServer::reuseClientJNIEnv(SDL_AndroidGetJNIEnv());
|
||||
#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)
|
||||
{
|
||||
setThreadName("connectThread");
|
||||
if(!addr.length())
|
||||
CSH->startLocalServerAndConnect();
|
||||
textTitle->setText(CGI->generaltexth->translate("vcmi.mainMenu.serverAddressEnter"));
|
||||
GH.startTextInput(inputAddress->pos);
|
||||
buttonOk->block(false);
|
||||
}
|
||||
|
||||
if(GH.windows().isTopWindow(this))
|
||||
{
|
||||
close();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if(addr.empty())
|
||||
CSH->startLocalServerAndConnect(onConnected);
|
||||
else
|
||||
CSH->justConnectToServer(addr, port);
|
||||
|
||||
// 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();
|
||||
}
|
||||
});
|
||||
CSH->justConnectToServer(addr, port, onConnected);
|
||||
}
|
||||
|
||||
CLoadingScreen::CLoadingScreen()
|
||||
|
@ -177,8 +177,7 @@ class CSimpleJoinScreen : public WindowBase
|
||||
void connectToServer();
|
||||
void leaveScreen();
|
||||
void onChange(const std::string & newText);
|
||||
void startConnectThread(const std::string & addr = {}, ui16 port = 0);
|
||||
void connectThread(const std::string & addr, ui16 port);
|
||||
void startConnection(const std::string & addr = {}, ui16 port = 0);
|
||||
|
||||
public:
|
||||
CSimpleJoinScreen(bool host = true);
|
||||
|
@ -18,12 +18,12 @@
|
||||
|
||||
#include "../../lib/MetaString.h"
|
||||
#include "../../lib/CConfigHandler.h"
|
||||
#include "../../lib/network/NetworkClient.h"
|
||||
|
||||
LobbyClient::LobbyClient(LobbyWindow * window)
|
||||
: window(window)
|
||||
{
|
||||
|
||||
}
|
||||
: networkClient(std::make_unique<NetworkClient>(*this))
|
||||
, window(window)
|
||||
{}
|
||||
|
||||
static std::string getCurrentTimeFormatted(int timeOffsetSeconds = 0)
|
||||
{
|
||||
@ -100,7 +100,22 @@ void LobbyClient::sendMessage(const JsonNode & data)
|
||||
|
||||
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)
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "../gui/InterfaceObjectConfigurable.h"
|
||||
#include "../windows/CWindowObject.h"
|
||||
|
||||
#include "../../lib/network/NetworkClient.h"
|
||||
#include "../../lib/network/NetworkListener.h"
|
||||
|
||||
class LobbyWindow;
|
||||
|
||||
@ -27,8 +27,9 @@ public:
|
||||
std::shared_ptr<CTextBox> getGameChat();
|
||||
};
|
||||
|
||||
class LobbyClient : public NetworkClient
|
||||
class LobbyClient : public INetworkClientListener
|
||||
{
|
||||
std::unique_ptr<NetworkClient> networkClient;
|
||||
LobbyWindow * window;
|
||||
|
||||
void onPacketReceived(const std::vector<uint8_t> & message) override;
|
||||
@ -40,6 +41,10 @@ public:
|
||||
explicit LobbyClient(LobbyWindow * window);
|
||||
|
||||
void sendMessage(const JsonNode & data);
|
||||
void start(const std::string & host, uint16_t port);
|
||||
void run();
|
||||
void poll();
|
||||
|
||||
};
|
||||
|
||||
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/NetworkConnection.h
|
||||
${MAIN_LIB_DIR}/network/NetworkDefines.h
|
||||
${MAIN_LIB_DIR}/network/NetworkListener.h
|
||||
${MAIN_LIB_DIR}/network/NetworkServer.h
|
||||
|
||||
${MAIN_LIB_DIR}/networkPacks/ArtifactLocation.h
|
||||
|
@ -47,8 +47,6 @@
|
||||
#include "RiverHandler.h"
|
||||
#include "TerrainHandler.h"
|
||||
|
||||
#include "serializer/Connection.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
void CPrivilegedInfoCallback::getFreeTiles(std::vector<int3> & tiles) const
|
||||
|
@ -123,7 +123,12 @@ bool LobbyInfo::isClientHost(int clientId) const
|
||||
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;
|
||||
for(auto & elem : si->playerInfos)
|
||||
|
@ -197,7 +197,6 @@ struct DLL_LINKAGE LobbyState
|
||||
|
||||
struct DLL_LINKAGE LobbyInfo : public LobbyState
|
||||
{
|
||||
boost::mutex stateMutex;
|
||||
std::string uuid;
|
||||
|
||||
LobbyInfo() {}
|
||||
@ -205,7 +204,8 @@ struct DLL_LINKAGE LobbyInfo : public LobbyState
|
||||
void verifyStateBeforeStart(bool ignoreNoHuman = false) 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;
|
||||
|
||||
// Helpers for lobby state access
|
||||
|
@ -13,10 +13,27 @@
|
||||
|
||||
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)
|
||||
, 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)
|
||||
{
|
||||
onConnectionFailed(ec.message());
|
||||
listener.onConnectionFailed(ec.message());
|
||||
return;
|
||||
}
|
||||
|
||||
connection = std::make_shared<NetworkConnection>(socket, *this);
|
||||
connection->start();
|
||||
|
||||
onConnectionEstablished();
|
||||
listener.onConnectionEstablished();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
onDisconnected();
|
||||
listener.onDisconnected();
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
#include "NetworkDefines.h"
|
||||
#include "NetworkListener.h"
|
||||
|
||||
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 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<NetworkSocket> socket;
|
||||
std::shared_ptr<NetworkConnection> connection;
|
||||
std::shared_ptr<NetworkTimer> timer;
|
||||
|
||||
INetworkClientListener & listener;
|
||||
|
||||
void onConnected(const boost::system::error_code & ec);
|
||||
|
||||
void onDisconnected(const std::shared_ptr<NetworkConnection> & connection) override;
|
||||
void onPacketReceived(const std::shared_ptr<NetworkConnection> & connection, const std::vector<uint8_t> & message) override;
|
||||
|
||||
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;
|
||||
public:
|
||||
NetworkClient(INetworkClientListener & listener);
|
||||
virtual ~NetworkClient() = default;
|
||||
|
||||
void sendPacket(const std::vector<uint8_t> & message);
|
||||
public:
|
||||
NetworkClient();
|
||||
virtual ~NetworkClient() = default;
|
||||
|
||||
void start(const std::string & host, uint16_t port);
|
||||
void run();
|
||||
|
@ -10,6 +10,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "NetworkDefines.h"
|
||||
#include "NetworkListener.h"
|
||||
|
||||
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 NetworkAcceptor = boost::asio::basic_socket_acceptor<boost::asio::ip::tcp>;
|
||||
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
|
||||
|
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
|
||||
|
||||
NetworkServer::NetworkServer(INetworkServerListener & listener)
|
||||
:listener(listener)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void NetworkServer::start(uint16_t port)
|
||||
{
|
||||
io = std::make_shared<boost::asio::io_service>();
|
||||
@ -32,6 +38,11 @@ void NetworkServer::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)
|
||||
{
|
||||
if(ec)
|
||||
@ -43,7 +54,7 @@ void NetworkServer::connectionAccepted(std::shared_ptr<NetworkSocket> upcomingCo
|
||||
auto connection = std::make_shared<NetworkConnection>(upcomingConnection, *this);
|
||||
connections.insert(connection);
|
||||
connection->start();
|
||||
onNewConnection(connection);
|
||||
listener.onNewConnection(connection);
|
||||
startAsyncAccept();
|
||||
}
|
||||
|
||||
@ -56,7 +67,12 @@ void NetworkServer::onDisconnected(const std::shared_ptr<NetworkConnection> & co
|
||||
{
|
||||
assert(connections.count(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
|
||||
|
@ -10,6 +10,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "NetworkDefines.h"
|
||||
#include "NetworkListener.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@ -21,20 +22,20 @@ class DLL_LINKAGE NetworkServer : boost::noncopyable, public INetworkConnectionL
|
||||
std::shared_ptr<NetworkAcceptor> acceptor;
|
||||
std::set<std::shared_ptr<NetworkConnection>> connections;
|
||||
|
||||
INetworkServerListener & listener;
|
||||
|
||||
void connectionAccepted(std::shared_ptr<NetworkSocket>, const boost::system::error_code & ec);
|
||||
void startAsyncAccept();
|
||||
|
||||
void onDisconnected(const std::shared_ptr<NetworkConnection> & connection) override;
|
||||
protected:
|
||||
virtual void onNewConnection(const std::shared_ptr<NetworkConnection> &) = 0;
|
||||
virtual void onConnectionLost(const std::shared_ptr<NetworkConnection> &) = 0;
|
||||
void onPacketReceived(const std::shared_ptr<NetworkConnection> & connection, const std::vector<uint8_t> & message) override;
|
||||
public:
|
||||
explicit NetworkServer(INetworkServerListener & listener);
|
||||
|
||||
void sendPacket(const std::shared_ptr<NetworkConnection> &, const std::vector<uint8_t> & message);
|
||||
|
||||
public:
|
||||
virtual ~NetworkServer() = default;
|
||||
|
||||
void start(uint16_t port);
|
||||
void run(std::chrono::milliseconds duration);
|
||||
void run();
|
||||
};
|
||||
|
||||
|
@ -51,7 +51,7 @@ struct VectorizedObjectInfo
|
||||
};
|
||||
|
||||
/// 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>
|
||||
static int32_t idToNumber(const Numeric &t)
|
||||
|
@ -10,9 +10,52 @@
|
||||
#include "StdInc.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
|
||||
|
||||
@ -362,3 +405,5 @@ std::string CConnection::toString() const
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
|
@ -9,123 +9,84 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "BinaryDeserializer.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
|
||||
|
||||
#include "CSerializer.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class BinaryDeserializer;
|
||||
class BinarySerializer;
|
||||
struct CPack;
|
||||
struct ConnectionBuffers;
|
||||
class NetworkConnection;
|
||||
|
||||
/// Main class for network communication
|
||||
/// Allows establishing connection and bidirectional read-write
|
||||
class DLL_LINKAGE CConnection
|
||||
: public IBinaryReader, public IBinaryWriter, public std::enable_shared_from_this<CConnection>
|
||||
class DLL_LINKAGE CConnection : public IBinaryReader, public IBinaryWriter, public std::enable_shared_from_this<CConnection>
|
||||
{
|
||||
void init();
|
||||
void reportState(vstd::CLoggerBase * out) override;
|
||||
/// Non-owning pointer to underlying connection
|
||||
std::weak_ptr<NetworkConnection> networkConnection;
|
||||
|
||||
// void init();
|
||||
// void reportState(vstd::CLoggerBase * out) override;
|
||||
//
|
||||
int write(const void * data, unsigned size) override;
|
||||
int read(void * data, unsigned size) override;
|
||||
void flushBuffers();
|
||||
|
||||
std::shared_ptr<boost::asio::io_service> io_service; //can be empty if connection made from socket
|
||||
|
||||
bool enableBufferedWrite;
|
||||
bool enableBufferedRead;
|
||||
std::unique_ptr<ConnectionBuffers> connectionBuffers;
|
||||
// void flushBuffers();
|
||||
//
|
||||
// bool enableBufferedWrite;
|
||||
// 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:
|
||||
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;
|
||||
|
||||
int connectionID;
|
||||
std::shared_ptr<boost::thread> handler;
|
||||
|
||||
CConnection(const std::string & host, ui16 port, std::string Name, std::string UUID);
|
||||
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
|
||||
CConnection(std::weak_ptr<NetworkConnection> networkConnection);
|
||||
// CConnection(const std::string & host, ui16 port, std::string Name, std::string UUID);
|
||||
// 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();
|
||||
bool isOpen() const;
|
||||
template<class T>
|
||||
CConnection &operator&(const T&);
|
||||
virtual ~CConnection();
|
||||
|
||||
CPack * retrievePack();
|
||||
// void close();
|
||||
// bool isOpen() const;
|
||||
//
|
||||
// CPack * retrievePack();
|
||||
void sendPack(const CPack * pack);
|
||||
|
||||
CPack * retrievePack(const std::vector<uint8_t> & data);
|
||||
// std::vector<uint8_t> serializePack(const CPack * pack);
|
||||
//
|
||||
void disableStackSendingByID();
|
||||
void enableStackSendingByID();
|
||||
void disableSmartPointerSerialization();
|
||||
void enableSmartPointerSerialization();
|
||||
void disableSmartVectorMemberSerialization();
|
||||
void enableSmartVectorMemberSerializatoin();
|
||||
|
||||
// void enableStackSendingByID();
|
||||
// void disableSmartPointerSerialization();
|
||||
// void enableSmartPointerSerialization();
|
||||
// void disableSmartVectorMemberSerialization();
|
||||
// void enableSmartVectorMemberSerializatoin();
|
||||
//
|
||||
void enterLobbyConnectionMode();
|
||||
void enterGameplayConnectionMode(CGameState * gs);
|
||||
|
||||
std::string toString() const;
|
||||
|
||||
template<class T>
|
||||
CConnection & operator>>(T &t)
|
||||
{
|
||||
iser & t;
|
||||
return * this;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
CConnection & operator<<(const T &t)
|
||||
{
|
||||
oser & t;
|
||||
return * this;
|
||||
}
|
||||
//
|
||||
// std::string toString() const;
|
||||
//
|
||||
// template<class T>
|
||||
// CConnection & operator>>(T &t)
|
||||
// {
|
||||
// iser & t;
|
||||
// return * this;
|
||||
// }
|
||||
//
|
||||
// template<class T>
|
||||
// CConnection & operator<<(const T &t)
|
||||
// {
|
||||
// oser & t;
|
||||
// return * this;
|
||||
// }
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -104,14 +104,14 @@ void LobbyServer::sendMessage(const std::shared_ptr<NetworkConnection> & target,
|
||||
|
||||
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::onConnectionLost(const std::shared_ptr<NetworkConnection> & connection)
|
||||
void LobbyServer::onDisconnected(const std::shared_ptr<NetworkConnection> & connection)
|
||||
{
|
||||
activeAccounts.erase(connection);
|
||||
}
|
||||
@ -169,9 +169,20 @@ void LobbyServer::onPacketReceived(const std::shared_ptr<NetworkConnection> & co
|
||||
|
||||
LobbyServer::LobbyServer()
|
||||
: 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[])
|
||||
{
|
||||
LobbyServer server;
|
||||
|
@ -41,7 +41,7 @@ public:
|
||||
std::vector<ChatMessage> getRecentMessageHistory();
|
||||
};
|
||||
|
||||
class LobbyServer : public NetworkServer
|
||||
class LobbyServer : public INetworkServerListener
|
||||
{
|
||||
struct AccountState
|
||||
{
|
||||
@ -51,12 +51,16 @@ class LobbyServer : public NetworkServer
|
||||
std::map<std::shared_ptr<NetworkConnection>, AccountState> activeAccounts;
|
||||
|
||||
std::unique_ptr<LobbyDatabase> database;
|
||||
std::unique_ptr<NetworkServer> networkServer;
|
||||
|
||||
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 sendMessage(const std::shared_ptr<NetworkConnection> & target, const JsonNode & json);
|
||||
public:
|
||||
LobbyServer();
|
||||
|
||||
void start(uint16_t port);
|
||||
void run();
|
||||
};
|
||||
|
@ -61,6 +61,7 @@
|
||||
|
||||
#include "../lib/serializer/CSaveFile.h"
|
||||
#include "../lib/serializer/CLoadFile.h"
|
||||
#include "../lib/serializer/Connection.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
|
||||
}
|
||||
|
||||
void CGameHandler::run(bool resume)
|
||||
void CGameHandler::start(bool resume)
|
||||
{
|
||||
LOG_TRACE_PARAMS(logGlobal, "resume=%d", resume);
|
||||
|
||||
for (auto cc : lobby->connections)
|
||||
for (auto cc : lobby->activeConnections)
|
||||
{
|
||||
auto players = lobby->getAllClientPlayers(cc->connectionID);
|
||||
std::stringstream sbuffer;
|
||||
@ -1004,18 +1005,11 @@ void CGameHandler::run(bool resume)
|
||||
events::GameResumed::defaultExecute(serverEventBus.get());
|
||||
|
||||
turnOrder->onGameStarted();
|
||||
}
|
||||
|
||||
//wait till game is done
|
||||
auto clockLast = std::chrono::steady_clock::now();
|
||||
while(lobby->getState() == EServerState::GAMEPLAY)
|
||||
{
|
||||
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::tick(int millisecondsPassed)
|
||||
{
|
||||
turnTimerHandler.update(millisecondsPassed);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
logNetwork->trace("\tSending to all clients: %s", typeid(*pack).name());
|
||||
for (auto c : lobby->connections)
|
||||
{
|
||||
if(!c->isOpen())
|
||||
continue;
|
||||
|
||||
for (auto c : lobby->activeConnections)
|
||||
c->sendPack(pack);
|
||||
}
|
||||
}
|
||||
|
||||
void CGameHandler::sendAndApply(CPackForClient * pack)
|
||||
|
@ -261,7 +261,8 @@ public:
|
||||
|
||||
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);
|
||||
void spawnWanderingMonsters(CreatureID creatureID);
|
||||
|
||||
|
@ -8,12 +8,11 @@
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
#include "../lib/filesystem/Filesystem.h"
|
||||
#include "../lib/campaign/CampaignState.h"
|
||||
#include "../lib/CThreadHelper.h"
|
||||
#include "../lib/serializer/Connection.h"
|
||||
#include "../lib/CArtHandler.h"
|
||||
#include "../lib/CGeneralTextHandler.h"
|
||||
#include "../lib/CHeroHandler.h"
|
||||
@ -37,12 +36,15 @@
|
||||
#include "CGameHandler.h"
|
||||
#include "processors/PlayerMessageProcessor.h"
|
||||
#include "../lib/mapping/CMapInfo.h"
|
||||
#include "../lib/network/NetworkServer.h"
|
||||
#include "../lib/network/NetworkClient.h"
|
||||
#include "../lib/GameConstants.h"
|
||||
#include "../lib/logging/CBasicLogConfigurator.h"
|
||||
#include "../lib/CConfigHandler.h"
|
||||
#include "../lib/ScopeGuard.h"
|
||||
#include "../lib/serializer/CMemorySerializer.h"
|
||||
#include "../lib/serializer/Cast.h"
|
||||
#include "../lib/serializer/Connection.h"
|
||||
|
||||
#include "../lib/UnlockGuard.h"
|
||||
|
||||
@ -81,11 +83,8 @@ public:
|
||||
|
||||
if(checker.getResult())
|
||||
{
|
||||
boost::unique_lock<boost::mutex> stateLock(srv->stateMutex);
|
||||
ApplyOnServerNetPackVisitor applier(*srv);
|
||||
|
||||
ptr->visit(applier);
|
||||
|
||||
return applier.getResult();
|
||||
}
|
||||
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 = GameConstants::VCMI_VERSION + std::string(" (") + SERVER_NAME_AFFIX + ')';
|
||||
|
||||
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()());
|
||||
logNetwork->trace("CVCMIServer created! UUID: %s", uuid);
|
||||
applier = std::make_shared<CApplier<CBaseForServerApply>>();
|
||||
registerTypesLobbyPacks(*applier);
|
||||
|
||||
uint16_t port = 3030;
|
||||
if(cmdLineOptions.count("port"))
|
||||
port = cmdLineOptions["port"].as<ui16>();
|
||||
port = cmdLineOptions["port"].as<uint16_t>();
|
||||
logNetwork->info("Port %d will be used", port);
|
||||
try
|
||||
{
|
||||
acceptor = std::make_shared<TAcceptor>(*io, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 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();
|
||||
}
|
||||
|
||||
networkServer = std::make_unique<NetworkServer>(*this);
|
||||
networkServer->start(port);
|
||||
logNetwork->info("Listening for connections at port %d", port);
|
||||
}
|
||||
|
||||
CVCMIServer::~CVCMIServer()
|
||||
{
|
||||
announceQueue.clear();
|
||||
CVCMIServer::~CVCMIServer() = default;
|
||||
|
||||
if(announceLobbyThread)
|
||||
announceLobbyThread->join();
|
||||
void CVCMIServer::onNewConnection(const std::shared_ptr<NetworkConnection> & connection)
|
||||
{
|
||||
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)
|
||||
@ -171,101 +223,60 @@ EServerState CVCMIServer::getState() const
|
||||
return state.load();
|
||||
}
|
||||
|
||||
std::shared_ptr<CConnection> CVCMIServer::findConnection(const std::shared_ptr<NetworkConnection> & netConnection)
|
||||
{
|
||||
//TODO
|
||||
assert(0);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CVCMIServer::run()
|
||||
{
|
||||
#if defined(VCMI_ANDROID) && !defined(SINGLE_PROCESS_APP)
|
||||
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;
|
||||
vmHelper.callStaticVoidMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "onServerReady");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
while(state == EServerState::LOBBY || state == EServerState::GAMEPLAY_STARTING)
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(50));
|
||||
static const int serverUpdateIntervalMilliseconds = 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)
|
||||
{
|
||||
{
|
||||
boost::unique_lock<boost::recursive_mutex> myLock(mx);
|
||||
while(!announceQueue.empty())
|
||||
{
|
||||
announcePack(std::move(announceQueue.front()));
|
||||
announceQueue.pop_front();
|
||||
}
|
||||
networkServer->run(std::chrono::milliseconds(serverUpdateIntervalMilliseconds));
|
||||
|
||||
if(acceptor)
|
||||
{
|
||||
io->reset();
|
||||
io->poll();
|
||||
}
|
||||
}
|
||||
const auto clockNow = std::chrono::steady_clock::now();
|
||||
const auto clockPassed = clockNow - clockInitial;
|
||||
const int64_t msPassedNow = std::chrono::duration_cast<std::chrono::milliseconds>(clockPassed).count();
|
||||
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()
|
||||
{
|
||||
if(state == EServerState::GAMEPLAY)
|
||||
@ -280,11 +291,9 @@ void CVCMIServer::prepareToRestart()
|
||||
campaignMap = si->campState->currentScenario().value_or(CampaignScenarioID(0));
|
||||
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->disableStackSendingByID();
|
||||
@ -306,10 +315,11 @@ bool CVCMIServer::prepareToStartGame()
|
||||
{
|
||||
if(progressTracking.get() != currentProgress)
|
||||
{
|
||||
//FIXME: UNGUARDED MULTITHREADED ACCESS!!!
|
||||
currentProgress = progressTracking.get();
|
||||
std::unique_ptr<LobbyLoadProgress> loadProgress(new LobbyLoadProgress);
|
||||
loadProgress->progress = currentProgress;
|
||||
addToAnnounceQueue(std::move(loadProgress));
|
||||
announcePack(std::move(loadProgress));
|
||||
}
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(50));
|
||||
}
|
||||
@ -355,149 +365,55 @@ bool CVCMIServer::prepareToStartGame()
|
||||
return true;
|
||||
}
|
||||
|
||||
void CVCMIServer::startGameImmidiately()
|
||||
void CVCMIServer::startGameImmediately()
|
||||
{
|
||||
for(auto c : connections)
|
||||
for(auto c : activeConnections)
|
||||
c->enterGameplayConnectionMode(gh->gs);
|
||||
|
||||
gh->start(si->mode == StartInfo::LOAD_GAME);
|
||||
state = EServerState::GAMEPLAY;
|
||||
}
|
||||
|
||||
void CVCMIServer::startAsyncAccept()
|
||||
void CVCMIServer::onDisconnected(const std::shared_ptr<NetworkConnection> & connection)
|
||||
{
|
||||
assert(!upcomingConnection);
|
||||
assert(acceptor);
|
||||
logNetwork->error("Network error receiving a pack. Connection has been closed");
|
||||
|
||||
#if BOOST_VERSION >= 107000 // Boost version >= 1.70
|
||||
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));
|
||||
}
|
||||
std::shared_ptr<CConnection> c = findConnection(connection);
|
||||
|
||||
void CVCMIServer::connectionAccepted(const boost::system::error_code & ec)
|
||||
{
|
||||
if(ec)
|
||||
inactiveConnections.push_back(c);
|
||||
vstd::erase(activeConnections, c);
|
||||
|
||||
if(activeConnections.empty() || hostClientId == c->connectionID)
|
||||
state = EServerState::SHUTDOWN;
|
||||
|
||||
if(gh && state == EServerState::GAMEPLAY)
|
||||
{
|
||||
if(state != EServerState::SHUTDOWN)
|
||||
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);
|
||||
gh->handleClientDisconnection(c);
|
||||
}
|
||||
|
||||
boost::unique_lock<boost::recursive_mutex> queueLock(mx);
|
||||
|
||||
if(c->connected)
|
||||
{
|
||||
auto lcd = std::make_unique<LobbyClientDisconnected>();
|
||||
lcd->c = c;
|
||||
lcd->clientId = c->connectionID;
|
||||
handleReceivedPack(std::move(lcd));
|
||||
}
|
||||
|
||||
logNetwork->info("Thread listening for %s ended", c->toString());
|
||||
c->handler.reset();
|
||||
// if(c->connected)
|
||||
// {
|
||||
// auto lcd = std::make_unique<LobbyClientDisconnected>();
|
||||
// lcd->c = c;
|
||||
// lcd->clientId = c->connectionID;
|
||||
// handleReceivedPack(std::move(lcd));
|
||||
// }
|
||||
//
|
||||
// logNetwork->info("Thread listening for %s ended", c->toString());
|
||||
}
|
||||
|
||||
void CVCMIServer::handleReceivedPack(std::unique_ptr<CPackForLobby> pack)
|
||||
{
|
||||
CBaseForServerApply * apply = applier->getApplier(CTypeList::getInstance().getTypeID(pack.get()));
|
||||
if(apply->applyOnServerBefore(this, pack.get()))
|
||||
addToAnnounceQueue(std::move(pack));
|
||||
announcePack(std::move(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
|
||||
// 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);
|
||||
auto cm = std::make_unique<LobbyShowMessage>();
|
||||
cm->message = txt;
|
||||
addToAnnounceQueue(std::move(cm));
|
||||
announcePack(std::move(cm));
|
||||
}
|
||||
|
||||
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>();
|
||||
cm->playerName = playerName;
|
||||
cm->message = txt;
|
||||
addToAnnounceQueue(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));
|
||||
announcePack(std::move(cm));
|
||||
}
|
||||
|
||||
bool CVCMIServer::passHost(int toConnectionId)
|
||||
{
|
||||
for(auto c : connections)
|
||||
for(auto c : activeConnections)
|
||||
{
|
||||
if(isClientHost(c->connectionID))
|
||||
continue;
|
||||
if(c->connectionID != toConnectionId)
|
||||
continue;
|
||||
|
||||
hostClient = c;
|
||||
hostClientId = c->connectionID;
|
||||
announceTxt(boost::str(boost::format("Pass host to connection %d") % toConnectionId));
|
||||
return true;
|
||||
@ -555,9 +464,8 @@ void CVCMIServer::clientConnected(std::shared_ptr<CConnection> c, std::vector<st
|
||||
if(state == EServerState::LOBBY)
|
||||
c->connectionID = currentClientId++;
|
||||
|
||||
if(!hostClient)
|
||||
if(hostClientId == -1)
|
||||
{
|
||||
hostClient = c;
|
||||
hostClientId = c->connectionID;
|
||||
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)
|
||||
{
|
||||
connections -= c;
|
||||
if(connections.empty() || hostClient == c)
|
||||
vstd::erase(activeConnections, c);
|
||||
|
||||
if(activeConnections.empty() || hostClientId == c->connectionID)
|
||||
{
|
||||
state = EServerState::SHUTDOWN;
|
||||
return;
|
||||
@ -626,7 +535,7 @@ void CVCMIServer::clientDisconnected(std::shared_ptr<CConnection> c)
|
||||
if(gh && si && state == EServerState::GAMEPLAY)
|
||||
{
|
||||
gh->playerMessages->broadcastMessage(playerSettings->color, playerLeftMsgText);
|
||||
gh->connections[playerSettings->color].insert(hostClient);
|
||||
// gh->connections[playerSettings->color].insert(hostClient);
|
||||
startAiPack.players.push_back(playerSettings->color);
|
||||
}
|
||||
}
|
||||
@ -753,7 +662,6 @@ void CVCMIServer::updateStartInfoOnMapChange(std::shared_ptr<CMapInfo> mapInfo,
|
||||
|
||||
void CVCMIServer::updateAndPropagateLobbyState()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> stateLock(stateMutex);
|
||||
// Update player settings for RMG
|
||||
// TODO: find appropriate location for this code
|
||||
if(si->mapGenOptions && si->mode == StartInfo::NEW_GAME)
|
||||
@ -772,7 +680,7 @@ void CVCMIServer::updateAndPropagateLobbyState()
|
||||
|
||||
auto lus = std::make_unique<LobbyUpdateState>();
|
||||
lus->state = *this;
|
||||
addToAnnounceQueue(std::move(lus));
|
||||
announcePack(std::move(lus));
|
||||
}
|
||||
|
||||
void CVCMIServer::setPlayer(PlayerColor clickedColor)
|
||||
@ -1188,32 +1096,9 @@ int main(int argc, const char * argv[])
|
||||
cond->notify_one();
|
||||
#endif
|
||||
|
||||
try
|
||||
{
|
||||
boost::asio::io_service io_service;
|
||||
CVCMIServer server(opts);
|
||||
CVCMIServer server(opts);
|
||||
server.run();
|
||||
|
||||
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
|
||||
CAndroidVMHelper envHelper;
|
||||
envHelper.callStaticVoidMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "killServer");
|
||||
|
@ -9,10 +9,10 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../lib/serializer/Connection.h"
|
||||
#include "../lib/network/NetworkListener.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)
|
||||
#define VCMI_ANDROID_DUAL_PROCESS 1
|
||||
@ -24,6 +24,7 @@ class CMapInfo;
|
||||
|
||||
struct CPackForLobby;
|
||||
|
||||
class CConnection;
|
||||
struct StartInfo;
|
||||
struct LobbyInfo;
|
||||
struct PlayerSettings;
|
||||
@ -46,53 +47,66 @@ enum class EServerState : ui8
|
||||
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::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;
|
||||
std::shared_ptr<CApplier<CBaseForServerApply>> applier;
|
||||
std::unique_ptr<boost::thread> announceLobbyThread;
|
||||
std::unique_ptr<boost::thread> remoteConnectionsThread;
|
||||
std::atomic<EServerState> state;
|
||||
|
||||
public:
|
||||
std::shared_ptr<CGameHandler> gh;
|
||||
ui16 port;
|
||||
// INetworkServerListener impl
|
||||
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 onNewConnection(const std::shared_ptr<NetworkConnection> &) override;
|
||||
|
||||
// INetworkClientListener impl
|
||||
void onPacketReceived(const std::vector<uint8_t> & message) override;
|
||||
void onConnectionFailed(const std::string & errorMessage) override;
|
||||
void onConnectionEstablished() override;
|
||||
void onDisconnected() override;
|
||||
|
||||
void establishOutgoingConnection();
|
||||
|
||||
std::shared_ptr<CConnection> findConnection(const std::shared_ptr<NetworkConnection> &);
|
||||
|
||||
boost::program_options::variables_map cmdLineOptions;
|
||||
std::set<std::shared_ptr<CConnection>> connections;
|
||||
std::set<std::shared_ptr<CConnection>> remoteConnections;
|
||||
std::set<std::shared_ptr<CConnection>> hangingConnections; //keep connections of players disconnected during the game
|
||||
|
||||
std::atomic<int> currentClientId;
|
||||
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();
|
||||
|
||||
void run();
|
||||
|
||||
bool prepareToStartGame();
|
||||
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 threadAnnounceLobby();
|
||||
void handleReceivedPack(std::unique_ptr<CPackForLobby> pack);
|
||||
|
||||
void announcePack(std::unique_ptr<CPackForLobby> pack);
|
||||
bool passHost(int toConnectionId);
|
||||
|
||||
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 updateStartInfoOnMapChange(std::shared_ptr<CMapInfo> mapInfo, std::shared_ptr<CMapGenOptions> mapGenOpt = {});
|
||||
@ -101,6 +115,11 @@ public:
|
||||
void clientDisconnected(std::shared_ptr<CConnection> c);
|
||||
void reconnectPlayer(int connId);
|
||||
|
||||
public:
|
||||
void announceMessage(const std::string & txt);
|
||||
|
||||
void handleReceivedPack(std::unique_ptr<CPackForLobby> pack);
|
||||
|
||||
void updateAndPropagateLobbyState();
|
||||
|
||||
void setState(EServerState value);
|
||||
|
@ -13,11 +13,9 @@
|
||||
#include "CVCMIServer.h"
|
||||
#include "CGameHandler.h"
|
||||
|
||||
#include "../lib/serializer/Connection.h"
|
||||
#include "../lib/StartInfo.h"
|
||||
|
||||
// Campaigns
|
||||
#include "../lib/campaign/CampaignState.h"
|
||||
#include "../lib/serializer/Connection.h"
|
||||
|
||||
void ClientPermissionsCheckerNetPackVisitor::visitForLobby(CPackForLobby & pack)
|
||||
{
|
||||
@ -38,67 +36,18 @@ void ApplyOnServerAfterAnnounceNetPackVisitor::visitForLobby(CPackForLobby & pac
|
||||
|
||||
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)
|
||||
{
|
||||
result = true;
|
||||
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;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
// Server need to pass some data to newly connected client
|
||||
pack.clientId = pack.c->connectionID;
|
||||
@ -121,7 +70,7 @@ void ApplyOnServerAfterAnnounceNetPackVisitor::visitLobbyClientConnected(LobbyCl
|
||||
startGameForReconnectedPlayer->initializedStartInfo = srv.si;
|
||||
startGameForReconnectedPlayer->initializedGameState = srv.gh->gameState();
|
||||
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)
|
||||
{
|
||||
srv.clientDisconnected(pack.c);
|
||||
pack.c->close();
|
||||
pack.c->connected = false;
|
||||
|
||||
result = true;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
logNetwork->info("Client requested shutdown, server will close itself...");
|
||||
srv.setState(EServerState::SHUTDOWN);
|
||||
return;
|
||||
}
|
||||
else if(srv.connections.empty())
|
||||
else if(srv.activeConnections.empty())
|
||||
{
|
||||
logNetwork->error("Last connection lost, server will close itself...");
|
||||
srv.setState(EServerState::SHUTDOWN);
|
||||
}
|
||||
else if(pack.c == srv.hostClient)
|
||||
else if(pack.c->connectionID == srv.hostClientId)
|
||||
{
|
||||
auto ph = std::make_unique<LobbyChangeHost>();
|
||||
auto newHost = *RandomGeneratorUtil::nextItem(srv.connections, CRandomGenerator::getDefault());
|
||||
auto newHost = srv.activeConnections.front();
|
||||
ph->newHostConnectionId = newHost->connectionID;
|
||||
srv.addToAnnounceQueue(std::move(ph));
|
||||
srv.announcePack(std::move(ph));
|
||||
}
|
||||
srv.updateAndPropagateLobbyState();
|
||||
|
||||
@ -270,8 +209,7 @@ void ApplyOnServerNetPackVisitor::visitLobbyEndGame(LobbyEndGame & pack)
|
||||
|
||||
void ApplyOnServerAfterAnnounceNetPackVisitor::visitLobbyEndGame(LobbyEndGame & pack)
|
||||
{
|
||||
boost::unique_lock<boost::mutex> stateLock(srv.stateMutex);
|
||||
for(auto & c : srv.connections)
|
||||
for(auto & c : srv.activeConnections)
|
||||
{
|
||||
c->enterLobbyConnectionMode();
|
||||
c->disableStackSendingByID();
|
||||
@ -312,10 +250,10 @@ void ApplyOnServerNetPackVisitor::visitLobbyStartGame(LobbyStartGame & pack)
|
||||
void ApplyOnServerAfterAnnounceNetPackVisitor::visitLobbyStartGame(LobbyStartGame & pack)
|
||||
{
|
||||
if(pack.clientId == -1) //do not restart game for single client only
|
||||
srv.startGameImmidiately();
|
||||
srv.startGameImmediately();
|
||||
else
|
||||
{
|
||||
for(auto & c : srv.connections)
|
||||
for(auto & c : srv.activeConnections)
|
||||
{
|
||||
if(c->connectionID == pack.clientId)
|
||||
{
|
||||
|
@ -20,11 +20,11 @@
|
||||
|
||||
#include "../lib/IGameCallback.h"
|
||||
#include "../lib/mapObjects/CGTownInstance.h"
|
||||
#include "../lib/mapObjects/CGHeroInstance.h"
|
||||
#include "../lib/gameState/CGameState.h"
|
||||
#include "../lib/battle/IBattleState.h"
|
||||
#include "../lib/battle/BattleAction.h"
|
||||
#include "../lib/battle/Unit.h"
|
||||
#include "../lib/serializer/Connection.h"
|
||||
#include "../lib/spells/CSpellHandler.h"
|
||||
#include "../lib/spells/ISpellMechanics.h"
|
||||
#include "../lib/serializer/Cast.h"
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include "../CGameHandler.h"
|
||||
#include "../CVCMIServer.h"
|
||||
|
||||
#include "../../lib/serializer/Connection.h"
|
||||
#include "../../lib/CGeneralTextHandler.h"
|
||||
#include "../../lib/CHeroHandler.h"
|
||||
#include "../../lib/modding/IdentifierStorage.h"
|
||||
@ -22,11 +21,13 @@
|
||||
#include "../../lib/StartInfo.h"
|
||||
#include "../../lib/gameState/CGameState.h"
|
||||
#include "../../lib/mapObjects/CGTownInstance.h"
|
||||
#include "../../lib/mapObjects/CGHeroInstance.h"
|
||||
#include "../../lib/modding/IdentifierStorage.h"
|
||||
#include "../../lib/modding/ModScope.h"
|
||||
#include "../../lib/mapping/CMap.h"
|
||||
#include "../../lib/networkPacks/PacksForClient.h"
|
||||
#include "../../lib/networkPacks/StackLocation.h"
|
||||
#include "../../lib/serializer/Connection.h"
|
||||
|
||||
PlayerMessageProcessor::PlayerMessageProcessor()
|
||||
:gameHandler(nullptr)
|
||||
@ -62,10 +63,7 @@ bool PlayerMessageProcessor::handleHostCommand(PlayerColor player, const std::st
|
||||
std::vector<std::string> words;
|
||||
boost::split(words, message, boost::is_any_of(" "));
|
||||
|
||||
bool isHost = false;
|
||||
for(auto & c : gameHandler->connections[player])
|
||||
if(gameHandler->gameLobby()->isClientHost(c->connectionID))
|
||||
isHost = true;
|
||||
bool isHost = gameHandler->gameLobby()->isPlayerHost(player);
|
||||
|
||||
if(!isHost || words.size() < 2 || words[0] != "game")
|
||||
return false;
|
||||
|
Loading…
Reference in New Issue
Block a user