mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Merge pull request #305 from vcmi/networkImprovements
Network and multiplayer improvements
This commit is contained in:
commit
5b0a0d5959
@ -1273,8 +1273,11 @@ static void mainLoop()
|
|||||||
|
|
||||||
void startGame(StartInfo * options, CConnection *serv/* = nullptr*/)
|
void startGame(StartInfo * options, CConnection *serv/* = nullptr*/)
|
||||||
{
|
{
|
||||||
serverAlive.waitWhileTrue();
|
if(!CServerHandler::DO_NOT_START_SERVER)
|
||||||
serverAlive.setn(true);
|
{
|
||||||
|
serverAlive.waitWhileTrue();
|
||||||
|
serverAlive.setn(true);
|
||||||
|
}
|
||||||
|
|
||||||
if(vm.count("onlyAI"))
|
if(vm.count("onlyAI"))
|
||||||
{
|
{
|
||||||
|
@ -83,7 +83,7 @@ struct EvilHlpStruct
|
|||||||
|
|
||||||
void reset()
|
void reset()
|
||||||
{
|
{
|
||||||
vstd::clear_pointer(serv);
|
// vstd::clear_pointer(serv);
|
||||||
vstd::clear_pointer(sInfo);
|
vstd::clear_pointer(sInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,7 +391,7 @@ void CClient::newGame( CConnection *con, StartInfo *si )
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
serv = con;
|
serv = con;
|
||||||
networkMode = (con->connectionID == 1) ? HOST : GUEST;
|
networkMode = con->isHost() ? HOST : GUEST;
|
||||||
}
|
}
|
||||||
|
|
||||||
CConnection &c = *serv;
|
CConnection &c = *serv;
|
||||||
@ -693,7 +693,7 @@ void CClient::stopConnection()
|
|||||||
{
|
{
|
||||||
terminate = true;
|
terminate = true;
|
||||||
|
|
||||||
if (serv) //request closing connection
|
if (serv && serv->isHost()) //request closing connection
|
||||||
{
|
{
|
||||||
logNetwork->infoStream() << "Connection has been requested to be closed.";
|
logNetwork->infoStream() << "Connection has been requested to be closed.";
|
||||||
boost::unique_lock<boost::mutex>(*serv->wmx);
|
boost::unique_lock<boost::mutex>(*serv->wmx);
|
||||||
@ -701,6 +701,12 @@ void CClient::stopConnection()
|
|||||||
sendRequest(&close_server, PlayerColor::NEUTRAL);
|
sendRequest(&close_server, PlayerColor::NEUTRAL);
|
||||||
logNetwork->infoStream() << "Sent closing signal to the server";
|
logNetwork->infoStream() << "Sent closing signal to the server";
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LeaveGame leave_Game;
|
||||||
|
sendRequest(&leave_Game, PlayerColor::NEUTRAL);
|
||||||
|
logNetwork->infoStream() << "Sent leaving signal to the server";
|
||||||
|
}
|
||||||
|
|
||||||
if(connectionHandler)//end connection handler
|
if(connectionHandler)//end connection handler
|
||||||
{
|
{
|
||||||
@ -708,16 +714,13 @@ void CClient::stopConnection()
|
|||||||
connectionHandler->join();
|
connectionHandler->join();
|
||||||
|
|
||||||
logNetwork->infoStream() << "Connection handler thread joined";
|
logNetwork->infoStream() << "Connection handler thread joined";
|
||||||
|
vstd::clear_pointer(connectionHandler);
|
||||||
delete connectionHandler;
|
|
||||||
connectionHandler = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (serv) //and delete connection
|
if (serv) //and delete connection
|
||||||
{
|
{
|
||||||
serv->close();
|
serv->close();
|
||||||
delete serv;
|
vstd::clear_pointer(serv);
|
||||||
serv = nullptr;
|
|
||||||
logNetwork->warnStream() << "Our socket has been closed.";
|
logNetwork->warnStream() << "Our socket has been closed.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -966,10 +969,13 @@ void CServerHandler::waitForServer()
|
|||||||
th.update();
|
th.update();
|
||||||
|
|
||||||
#ifndef VCMI_ANDROID
|
#ifndef VCMI_ANDROID
|
||||||
intpr::scoped_lock<intpr::interprocess_mutex> slock(shared->sr->mutex);
|
if(shared)
|
||||||
while(!shared->sr->ready)
|
|
||||||
{
|
{
|
||||||
shared->sr->cond.wait(slock);
|
intpr::scoped_lock<intpr::interprocess_mutex> slock(shared->sr->mutex);
|
||||||
|
while(!shared->sr->ready)
|
||||||
|
{
|
||||||
|
shared->sr->cond.wait(slock);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
logNetwork->infoStream() << "waiting for server";
|
logNetwork->infoStream() << "waiting for server";
|
||||||
@ -988,8 +994,12 @@ void CServerHandler::waitForServer()
|
|||||||
CConnection * CServerHandler::connectToServer()
|
CConnection * CServerHandler::connectToServer()
|
||||||
{
|
{
|
||||||
#ifndef VCMI_ANDROID
|
#ifndef VCMI_ANDROID
|
||||||
if(!shared->sr->ready)
|
if(shared)
|
||||||
waitForServer();
|
{
|
||||||
|
if(!shared->sr->ready)
|
||||||
|
waitForServer();
|
||||||
|
port = boost::lexical_cast<std::string>(shared->sr->port);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
waitForServer();
|
waitForServer();
|
||||||
#endif
|
#endif
|
||||||
@ -1015,6 +1025,9 @@ CServerHandler::CServerHandler(bool runServer /*= false*/)
|
|||||||
verbose = true;
|
verbose = true;
|
||||||
|
|
||||||
#ifndef VCMI_ANDROID
|
#ifndef VCMI_ANDROID
|
||||||
|
if(DO_NOT_START_SERVER)
|
||||||
|
return;
|
||||||
|
|
||||||
boost::interprocess::shared_memory_object::remove("vcmi_memory"); //if the application has previously crashed, the memory may not have been removed. to avoid problems - try to destroy it
|
boost::interprocess::shared_memory_object::remove("vcmi_memory"); //if the application has previously crashed, the memory may not have been removed. to avoid problems - try to destroy it
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -1022,6 +1035,7 @@ CServerHandler::CServerHandler(bool runServer /*= false*/)
|
|||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
|
vstd::clear_pointer(shared);
|
||||||
logNetwork->error("Cannot open interprocess memory.");
|
logNetwork->error("Cannot open interprocess memory.");
|
||||||
handleException();
|
handleException();
|
||||||
throw;
|
throw;
|
||||||
@ -1040,7 +1054,12 @@ void CServerHandler::callServer()
|
|||||||
#ifndef VCMI_ANDROID
|
#ifndef VCMI_ANDROID
|
||||||
setThreadName("CServerHandler::callServer");
|
setThreadName("CServerHandler::callServer");
|
||||||
const std::string logName = (VCMIDirs::get().userCachePath() / "server_log.txt").string();
|
const std::string logName = (VCMIDirs::get().userCachePath() / "server_log.txt").string();
|
||||||
const std::string comm = VCMIDirs::get().serverPath().string() + " --port=" + port + " > \"" + logName + '\"';
|
const std::string comm = VCMIDirs::get().serverPath().string()
|
||||||
|
+ " --port=" + port
|
||||||
|
+ " --run-by-client"
|
||||||
|
+ (shared ? " --use-shm" : "")
|
||||||
|
+ " > \"" + logName + '\"';
|
||||||
|
|
||||||
int result = std::system(comm.c_str());
|
int result = std::system(comm.c_str());
|
||||||
if (result == 0)
|
if (result == 0)
|
||||||
{
|
{
|
||||||
@ -1075,6 +1094,7 @@ CConnection * CServerHandler::justConnectToServer(const std::string &host, const
|
|||||||
ret = new CConnection( host.size() ? host : settings["server"]["server"].String(),
|
ret = new CConnection( host.size() ? host : settings["server"]["server"].String(),
|
||||||
realPort,
|
realPort,
|
||||||
NAME);
|
NAME);
|
||||||
|
ret->connectionID = 1; // TODO: Refactoring for the server so IDs set outside of CConnection
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
|
@ -19,19 +19,22 @@
|
|||||||
struct ServerReady
|
struct ServerReady
|
||||||
{
|
{
|
||||||
bool ready;
|
bool ready;
|
||||||
|
uint16_t port; //ui16?
|
||||||
boost::interprocess::interprocess_mutex mutex;
|
boost::interprocess::interprocess_mutex mutex;
|
||||||
boost::interprocess::interprocess_condition cond;
|
boost::interprocess::interprocess_condition cond;
|
||||||
|
|
||||||
ServerReady()
|
ServerReady()
|
||||||
{
|
{
|
||||||
ready = false;
|
ready = false;
|
||||||
|
port = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setToTrueAndNotify()
|
void setToTrueAndNotify(uint16_t Port)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
boost::unique_lock<boost::interprocess::interprocess_mutex> lock(mutex);
|
boost::unique_lock<boost::interprocess::interprocess_mutex> lock(mutex);
|
||||||
ready = true;
|
ready = true;
|
||||||
|
port = Port;
|
||||||
}
|
}
|
||||||
cond.notify_all();
|
cond.notify_all();
|
||||||
}
|
}
|
||||||
|
@ -152,6 +152,21 @@ struct PlayerBlocked : public CPackForClient
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct PlayerCheated : public CPackForClient
|
||||||
|
{
|
||||||
|
PlayerCheated() : losingCheatCode(false), winningCheatCode(false) {}
|
||||||
|
DLL_LINKAGE void applyGs(CGameState *gs);
|
||||||
|
|
||||||
|
PlayerColor player;
|
||||||
|
bool losingCheatCode;
|
||||||
|
bool winningCheatCode;
|
||||||
|
|
||||||
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
|
{
|
||||||
|
h & player & losingCheatCode & winningCheatCode;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct YourTurn : public CPackForClient
|
struct YourTurn : public CPackForClient
|
||||||
{
|
{
|
||||||
YourTurn(){}
|
YourTurn(){}
|
||||||
@ -1774,6 +1789,13 @@ struct CloseServer : public CPackForServer
|
|||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct LeaveGame : public CPackForServer
|
||||||
|
{
|
||||||
|
bool applyGh(CGameHandler *gh);
|
||||||
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
struct EndTurn : public CPackForServer
|
struct EndTurn : public CPackForServer
|
||||||
{
|
{
|
||||||
bool applyGh(CGameHandler *gh);
|
bool applyGh(CGameHandler *gh);
|
||||||
|
@ -1840,6 +1840,12 @@ DLL_LINKAGE void BattleSetStackProperty::applyGs(CGameState *gs)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DLL_LINKAGE void PlayerCheated::applyGs(CGameState *gs)
|
||||||
|
{
|
||||||
|
gs->getPlayer(player)->enteredLosingCheatCode = losingCheatCode;
|
||||||
|
gs->getPlayer(player)->enteredWinningCheatCode = winningCheatCode;
|
||||||
|
}
|
||||||
|
|
||||||
DLL_LINKAGE void YourTurn::applyGs(CGameState *gs)
|
DLL_LINKAGE void YourTurn::applyGs(CGameState *gs)
|
||||||
{
|
{
|
||||||
gs->currentPlayer = player;
|
gs->currentPlayer = player;
|
||||||
|
@ -424,4 +424,4 @@
|
|||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -669,4 +669,4 @@
|
|||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -210,6 +210,7 @@ void registerTypesClientPacks1(Serializer &s)
|
|||||||
s.template registerType<CPackForClient, PackageApplied>();
|
s.template registerType<CPackForClient, PackageApplied>();
|
||||||
s.template registerType<CPackForClient, SystemMessage>();
|
s.template registerType<CPackForClient, SystemMessage>();
|
||||||
s.template registerType<CPackForClient, PlayerBlocked>();
|
s.template registerType<CPackForClient, PlayerBlocked>();
|
||||||
|
s.template registerType<CPackForClient, PlayerCheated>();
|
||||||
s.template registerType<CPackForClient, YourTurn>();
|
s.template registerType<CPackForClient, YourTurn>();
|
||||||
s.template registerType<CPackForClient, SetResources>();
|
s.template registerType<CPackForClient, SetResources>();
|
||||||
s.template registerType<CPackForClient, SetPrimSkill>();
|
s.template registerType<CPackForClient, SetPrimSkill>();
|
||||||
@ -314,6 +315,7 @@ void registerTypesServerPacks(Serializer &s)
|
|||||||
{
|
{
|
||||||
s.template registerType<CPack, CPackForServer>();
|
s.template registerType<CPack, CPackForServer>();
|
||||||
s.template registerType<CPackForServer, CloseServer>();
|
s.template registerType<CPackForServer, CloseServer>();
|
||||||
|
s.template registerType<CPackForServer, LeaveGame>();
|
||||||
s.template registerType<CPackForServer, EndTurn>();
|
s.template registerType<CPackForServer, EndTurn>();
|
||||||
s.template registerType<CPackForServer, DismissHero>();
|
s.template registerType<CPackForServer, DismissHero>();
|
||||||
s.template registerType<CPackForServer, MoveHero>();
|
s.template registerType<CPackForServer, MoveHero>();
|
||||||
|
@ -191,8 +191,7 @@ void CConnection::close()
|
|||||||
if(socket)
|
if(socket)
|
||||||
{
|
{
|
||||||
socket->close();
|
socket->close();
|
||||||
delete socket;
|
vstd::clear_pointer(socket);
|
||||||
socket = nullptr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,6 +200,11 @@ bool CConnection::isOpen() const
|
|||||||
return socket && connected;
|
return socket && connected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CConnection::isHost() const
|
||||||
|
{
|
||||||
|
return connectionID == 1;
|
||||||
|
}
|
||||||
|
|
||||||
void CConnection::reportState(CLogger * out)
|
void CConnection::reportState(CLogger * out)
|
||||||
{
|
{
|
||||||
out->debugStream() << "CConnection";
|
out->debugStream() << "CConnection";
|
||||||
|
@ -74,6 +74,7 @@ public:
|
|||||||
|
|
||||||
void close();
|
void close();
|
||||||
bool isOpen() const;
|
bool isOpen() const;
|
||||||
|
bool isHost() const;
|
||||||
template<class T>
|
template<class T>
|
||||||
CConnection &operator&(const T&);
|
CConnection &operator&(const T&);
|
||||||
virtual ~CConnection(void);
|
virtual ~CConnection(void);
|
||||||
|
@ -1031,6 +1031,24 @@ void CGameHandler::handleConnection(std::set<PlayerColor> players, CConnection &
|
|||||||
{
|
{
|
||||||
setThreadName("CGameHandler::handleConnection");
|
setThreadName("CGameHandler::handleConnection");
|
||||||
|
|
||||||
|
auto handleDisconnection = [&](const std::exception & e)
|
||||||
|
{
|
||||||
|
assert(!c.connected); //make sure that connection has been marked as broken
|
||||||
|
logGlobal->error(e.what());
|
||||||
|
conns -= &c;
|
||||||
|
for(auto playerConn : connections)
|
||||||
|
{
|
||||||
|
if(playerConn.second == &c)
|
||||||
|
{
|
||||||
|
PlayerCheated pc;
|
||||||
|
pc.player = playerConn.first;
|
||||||
|
pc.losingCheatCode = true;
|
||||||
|
sendAndApply(&pc);
|
||||||
|
checkVictoryLossConditionsForPlayer(playerConn.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
while(1)//server should never shut connection first //was: while(!end2)
|
while(1)//server should never shut connection first //was: while(!end2)
|
||||||
@ -1042,6 +1060,8 @@ void CGameHandler::handleConnection(std::set<PlayerColor> players, CConnection &
|
|||||||
|
|
||||||
{
|
{
|
||||||
boost::unique_lock<boost::mutex> lock(*c.rmx);
|
boost::unique_lock<boost::mutex> lock(*c.rmx);
|
||||||
|
if(!c.connected)
|
||||||
|
throw clientDisconnectedException();
|
||||||
c >> player >> requestID >> pack; //get the package
|
c >> player >> requestID >> pack; //get the package
|
||||||
|
|
||||||
if (!pack)
|
if (!pack)
|
||||||
@ -1060,6 +1080,11 @@ void CGameHandler::handleConnection(std::set<PlayerColor> players, CConnection &
|
|||||||
//prepare struct informing that action was applied
|
//prepare struct informing that action was applied
|
||||||
auto sendPackageResponse = [&](bool succesfullyApplied)
|
auto sendPackageResponse = [&](bool succesfullyApplied)
|
||||||
{
|
{
|
||||||
|
//dont reply to disconnected client
|
||||||
|
//TODO: this must be implemented as option of CPackForServer
|
||||||
|
if(dynamic_cast<LeaveGame *>(pack) || dynamic_cast<CloseServer *>(pack))
|
||||||
|
return;
|
||||||
|
|
||||||
PackageApplied applied;
|
PackageApplied applied;
|
||||||
applied.player = player;
|
applied.player = player;
|
||||||
applied.result = succesfullyApplied;
|
applied.result = succesfullyApplied;
|
||||||
@ -1095,9 +1120,11 @@ void CGameHandler::handleConnection(std::set<PlayerColor> players, CConnection &
|
|||||||
}
|
}
|
||||||
catch(boost::system::system_error &e) //for boost errors just log, not crash - probably client shut down connection
|
catch(boost::system::system_error &e) //for boost errors just log, not crash - probably client shut down connection
|
||||||
{
|
{
|
||||||
assert(!c.connected); //make sure that connection has been marked as broken
|
handleDisconnection(e);
|
||||||
logGlobal->error(e.what());
|
}
|
||||||
end2 = true;
|
catch(clientDisconnectedException & e)
|
||||||
|
{
|
||||||
|
handleDisconnection(e);
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
@ -2631,6 +2658,9 @@ void CGameHandler::sendToAllClients(CPackForClient * info)
|
|||||||
logNetwork->trace("Sending to all clients a package of type %s", typeid(*info).name());
|
logNetwork->trace("Sending to all clients a package of type %s", typeid(*info).name());
|
||||||
for (auto & elem : conns)
|
for (auto & elem : conns)
|
||||||
{
|
{
|
||||||
|
if(!elem->isOpen())
|
||||||
|
continue;
|
||||||
|
|
||||||
boost::unique_lock<boost::mutex> lock(*(elem)->wmx);
|
boost::unique_lock<boost::mutex> lock(*(elem)->wmx);
|
||||||
*elem << info;
|
*elem << info;
|
||||||
}
|
}
|
||||||
@ -2703,11 +2733,32 @@ void CGameHandler::close()
|
|||||||
{
|
{
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
end2 = true;
|
||||||
|
|
||||||
//for (CConnection *cc : conns)
|
for (auto & elem : conns)
|
||||||
// if (cc && cc->socket && cc->socket->is_open())
|
{
|
||||||
// cc->socket->close();
|
if(!elem->isOpen())
|
||||||
//exit(0);
|
continue;
|
||||||
|
|
||||||
|
boost::unique_lock<boost::mutex> lock(*(elem)->wmx);
|
||||||
|
elem->close();
|
||||||
|
elem->connected = false;
|
||||||
|
}
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGameHandler::playerLeftGame(int cid)
|
||||||
|
{
|
||||||
|
for (auto & elem : conns)
|
||||||
|
{
|
||||||
|
if(elem->isOpen() && elem->connectionID == cid)
|
||||||
|
{
|
||||||
|
boost::unique_lock<boost::mutex> lock(*(elem)->wmx);
|
||||||
|
elem->close();
|
||||||
|
elem->connected = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CGameHandler::arrangeStacks(ObjectInstanceID id1, ObjectInstanceID id2, ui8 what, SlotID p1, SlotID p2, si32 val, PlayerColor player)
|
bool CGameHandler::arrangeStacks(ObjectInstanceID id1, ObjectInstanceID id2, ui8 what, SlotID p1, SlotID p2, si32 val, PlayerColor player)
|
||||||
@ -6162,12 +6213,18 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons
|
|||||||
else if (cheat == "vcmisilmaril")
|
else if (cheat == "vcmisilmaril")
|
||||||
{
|
{
|
||||||
///Player wins
|
///Player wins
|
||||||
gs->getPlayer(player)->enteredWinningCheatCode = 1;
|
PlayerCheated pc;
|
||||||
|
pc.player = player;
|
||||||
|
pc.winningCheatCode = true;
|
||||||
|
sendAndApply(&pc);
|
||||||
}
|
}
|
||||||
else if (cheat == "vcmimelkor")
|
else if (cheat == "vcmimelkor")
|
||||||
{
|
{
|
||||||
///Player looses
|
///Player looses
|
||||||
gs->getPlayer(player)->enteredLosingCheatCode = 1;
|
PlayerCheated pc;
|
||||||
|
pc.player = player;
|
||||||
|
pc.losingCheatCode = true;
|
||||||
|
sendAndApply(&pc);
|
||||||
}
|
}
|
||||||
else if (cheat == "vcmieagles" || cheat == "vcmiungoliant")
|
else if (cheat == "vcmieagles" || cheat == "vcmiungoliant")
|
||||||
{
|
{
|
||||||
|
@ -223,6 +223,7 @@ public:
|
|||||||
bool arrangeStacks( ObjectInstanceID id1, ObjectInstanceID id2, ui8 what, SlotID p1, SlotID p2, si32 val, PlayerColor player);
|
bool arrangeStacks( ObjectInstanceID id1, ObjectInstanceID id2, ui8 what, SlotID p1, SlotID p2, si32 val, PlayerColor player);
|
||||||
void save(const std::string &fname);
|
void save(const std::string &fname);
|
||||||
void close();
|
void close();
|
||||||
|
void playerLeftGame(int cid);
|
||||||
void handleTimeEvents();
|
void handleTimeEvents();
|
||||||
void handleTownEvents(CGTownInstance *town, NewTurn &n);
|
void handleTownEvents(CGTownInstance *town, NewTurn &n);
|
||||||
bool complain(const std::string &problem); //sends message to all clients, prints on the logs and return true
|
bool complain(const std::string &problem); //sends message to all clients, prints on the logs and return true
|
||||||
@ -298,4 +299,9 @@ private:
|
|||||||
void checkVictoryLossConditionsForAll();
|
void checkVictoryLossConditionsForAll();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class clientDisconnectedException : public std::exception
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
void makeStackDoNothing();
|
void makeStackDoNothing();
|
||||||
|
@ -45,7 +45,6 @@ std::string NAME = GameConstants::VCMI_VERSION + std::string(" (") + NAME_AFFIX
|
|||||||
namespace intpr = boost::interprocess;
|
namespace intpr = boost::interprocess;
|
||||||
#endif
|
#endif
|
||||||
bool end2 = false;
|
bool end2 = false;
|
||||||
int port = 3030;
|
|
||||||
|
|
||||||
boost::program_options::variables_map cmdLineOptions;
|
boost::program_options::variables_map cmdLineOptions;
|
||||||
|
|
||||||
@ -106,6 +105,10 @@ void CPregameServer::handleConnection(CConnection *cpc)
|
|||||||
auto unlock = vstd::makeUnlockGuard(mx);
|
auto unlock = vstd::makeUnlockGuard(mx);
|
||||||
while(state == RUNNING) boost::this_thread::sleep(boost::posix_time::milliseconds(50));
|
while(state == RUNNING) boost::this_thread::sleep(boost::posix_time::milliseconds(50));
|
||||||
}
|
}
|
||||||
|
else if(quitting) // Server must be stopped if host is leaving from lobby to avoid crash
|
||||||
|
{
|
||||||
|
end2 = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
@ -206,20 +209,29 @@ void CPregameServer::connectionAccepted(const boost::system::error_code& ec)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
logNetwork->info("We got a new connection! :)");
|
try
|
||||||
CConnection *pc = new CConnection(upcomingConnection, NAME);
|
{
|
||||||
initConnection(pc);
|
logNetwork->info("We got a new connection! :)");
|
||||||
upcomingConnection = nullptr;
|
std::string name = NAME;
|
||||||
|
CConnection *pc = new CConnection(upcomingConnection, name.append(" STATE_PREGAME"));
|
||||||
|
initConnection(pc);
|
||||||
|
upcomingConnection = nullptr;
|
||||||
|
|
||||||
startListeningThread(pc);
|
startListeningThread(pc);
|
||||||
|
|
||||||
*pc << (ui8)pc->connectionID << curmap;
|
*pc << (ui8)pc->connectionID << curmap;
|
||||||
|
|
||||||
announceTxt(pc->name + " joins the game");
|
announceTxt(pc->name + " joins the game");
|
||||||
auto pj = new PlayerJoined();
|
auto pj = new PlayerJoined();
|
||||||
pj->playerName = pc->name;
|
pj->playerName = pc->name;
|
||||||
pj->connectionID = pc->connectionID;
|
pj->connectionID = pc->connectionID;
|
||||||
toAnnounce.push_back(pj);
|
toAnnounce.push_back(pj);
|
||||||
|
}
|
||||||
|
catch(std::exception& e)
|
||||||
|
{
|
||||||
|
upcomingConnection = nullptr;
|
||||||
|
logNetwork->info("I guess it was just my imagination!");
|
||||||
|
}
|
||||||
|
|
||||||
start_async_accept();
|
start_async_accept();
|
||||||
}
|
}
|
||||||
@ -314,9 +326,28 @@ void CPregameServer::startListeningThread(CConnection * pc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
CVCMIServer::CVCMIServer()
|
CVCMIServer::CVCMIServer()
|
||||||
: io(new boost::asio::io_service()), acceptor(new TAcceptor(*io, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port))), firstConnection(nullptr)
|
: port(3030), io(new boost::asio::io_service()), firstConnection(nullptr)
|
||||||
{
|
{
|
||||||
logNetwork->trace("CVCMIServer created!");
|
logNetwork->trace("CVCMIServer created!");
|
||||||
|
if(cmdLineOptions.count("port"))
|
||||||
|
port = cmdLineOptions["port"].as<ui16>();
|
||||||
|
logNetwork->info("Port %d will be used", port);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
acceptor = new 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") && !cmdLineOptions.count("use-shm"))
|
||||||
|
{
|
||||||
|
logNetwork->error("Cant pass port number to client without shared memory!", port);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
acceptor = new 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);
|
||||||
}
|
}
|
||||||
CVCMIServer::~CVCMIServer()
|
CVCMIServer::~CVCMIServer()
|
||||||
{
|
{
|
||||||
@ -396,67 +427,85 @@ void CVCMIServer::start()
|
|||||||
#ifndef VCMI_ANDROID
|
#ifndef VCMI_ANDROID
|
||||||
ServerReady *sr = nullptr;
|
ServerReady *sr = nullptr;
|
||||||
intpr::mapped_region *mr;
|
intpr::mapped_region *mr;
|
||||||
try
|
if(cmdLineOptions.count("use-shm"))
|
||||||
{
|
{
|
||||||
intpr::shared_memory_object smo(intpr::open_only,"vcmi_memory",intpr::read_write);
|
try
|
||||||
smo.truncate(sizeof(ServerReady));
|
{
|
||||||
mr = new intpr::mapped_region(smo,intpr::read_write);
|
intpr::shared_memory_object smo(intpr::open_only,"vcmi_memory",intpr::read_write);
|
||||||
sr = reinterpret_cast<ServerReady*>(mr->get_address());
|
smo.truncate(sizeof(ServerReady));
|
||||||
}
|
mr = new intpr::mapped_region(smo,intpr::read_write);
|
||||||
catch(...)
|
sr = reinterpret_cast<ServerReady*>(mr->get_address());
|
||||||
{
|
}
|
||||||
intpr::shared_memory_object smo(intpr::create_only,"vcmi_memory",intpr::read_write);
|
catch(...)
|
||||||
smo.truncate(sizeof(ServerReady));
|
{
|
||||||
mr = new intpr::mapped_region(smo,intpr::read_write);
|
intpr::shared_memory_object smo(intpr::create_only,"vcmi_memory",intpr::read_write);
|
||||||
sr = new(mr->get_address())ServerReady();
|
smo.truncate(sizeof(ServerReady));
|
||||||
|
mr = new intpr::mapped_region(smo,intpr::read_write);
|
||||||
|
sr = new(mr->get_address())ServerReady();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
boost::system::error_code error;
|
boost::system::error_code error;
|
||||||
logNetwork->info("Listening for connections at port %d", acceptor->local_endpoint().port());
|
for (;;)
|
||||||
auto s = new boost::asio::ip::tcp::socket(acceptor->get_io_service());
|
{
|
||||||
boost::thread acc(std::bind(vaccept,acceptor,s,&error));
|
try
|
||||||
#ifndef VCMI_ANDROID
|
{
|
||||||
sr->setToTrueAndNotify();
|
auto s = new boost::asio::ip::tcp::socket(acceptor->get_io_service());
|
||||||
delete mr;
|
boost::thread acc(std::bind(vaccept,acceptor,s,&error));
|
||||||
|
#ifdef VCMI_ANDROID
|
||||||
|
{ // in block to clean-up vm helper after use, because we don't need to keep this thread attached to vm
|
||||||
|
CAndroidVMHelper envHelper;
|
||||||
|
envHelper.callStaticVoidMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "onServerReady");
|
||||||
|
logNetwork->info("Sending server ready message to client");
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
{ // in block to clean-up vm helper after use, because we don't need to keep this thread attached to vm
|
if(cmdLineOptions.count("use-shm"))
|
||||||
CAndroidVMHelper envHelper;
|
{
|
||||||
envHelper.callStaticVoidMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "onServerReady");
|
sr->setToTrueAndNotify(port);
|
||||||
logNetwork->info("Sending server ready message to client");
|
delete mr;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
acc.join();
|
acc.join();
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
logNetwork->warnStream() << "Got connection but there is an error " << error;
|
logNetwork->warnStream()<<"Got connection but there is an error " << error;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
logNetwork->info("We've accepted someone... ");
|
logNetwork->info("We've accepted someone... ");
|
||||||
firstConnection = new CConnection(s, NAME);
|
std::string name = NAME;
|
||||||
logNetwork->info("Got connection!");
|
firstConnection = new CConnection(s, name.append(" STATE_WAITING"));
|
||||||
while (!end2)
|
logNetwork->info("Got connection!");
|
||||||
{
|
while(!end2)
|
||||||
ui8 mode;
|
{
|
||||||
*firstConnection >> mode;
|
ui8 mode;
|
||||||
switch (mode)
|
*firstConnection >> mode;
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
firstConnection->close();
|
||||||
|
exit(0);
|
||||||
|
case 1:
|
||||||
|
firstConnection->close();
|
||||||
|
return;
|
||||||
|
case 2:
|
||||||
|
newGame();
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
loadGame();
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
newPregame();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch(std::exception& e)
|
||||||
{
|
{
|
||||||
case 0:
|
vstd::clear_pointer(firstConnection);
|
||||||
firstConnection->close();
|
logNetwork->info("I guess it was just my imagination!");
|
||||||
exit(0);
|
|
||||||
case 1:
|
|
||||||
firstConnection->close();
|
|
||||||
return;
|
|
||||||
case 2:
|
|
||||||
newGame();
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
loadGame();
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
newPregame();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -507,7 +556,9 @@ static void handleCommandOptions(int argc, char *argv[])
|
|||||||
opts.add_options()
|
opts.add_options()
|
||||||
("help,h", "display help and exit")
|
("help,h", "display help and exit")
|
||||||
("version,v", "display version information and exit")
|
("version,v", "display version information and exit")
|
||||||
("port", po::value<int>()->default_value(3030), "port at which server will listen to connections from client")
|
("run-by-client", "indicate that server launched by client on same machine")
|
||||||
|
("use-shm", "enable usage of shared memory")
|
||||||
|
("port", po::value<ui16>(), "port at which server will listen to connections from client")
|
||||||
("resultsFile", po::value<std::string>()->default_value("./results.txt"), "file to which the battle result will be appended. Used only in the DUEL mode.");
|
("resultsFile", po::value<std::string>()->default_value("./results.txt"), "file to which the battle result will be appended. Used only in the DUEL mode.");
|
||||||
|
|
||||||
if(argc > 1)
|
if(argc > 1)
|
||||||
@ -584,12 +635,7 @@ int main(int argc, char** argv)
|
|||||||
logConfig.configureDefault();
|
logConfig.configureDefault();
|
||||||
logGlobal->info(NAME);
|
logGlobal->info(NAME);
|
||||||
|
|
||||||
|
|
||||||
handleCommandOptions(argc, argv);
|
handleCommandOptions(argc, argv);
|
||||||
if (cmdLineOptions.count("port"))
|
|
||||||
port = cmdLineOptions["port"].as<int>();
|
|
||||||
logNetwork->info("Port %d will be used.", port);
|
|
||||||
|
|
||||||
preinitDLL(console);
|
preinitDLL(console);
|
||||||
settings.init();
|
settings.init();
|
||||||
logConfig.configure();
|
logConfig.configure();
|
||||||
@ -630,11 +676,9 @@ int main(int argc, char** argv)
|
|||||||
CAndroidVMHelper envHelper;
|
CAndroidVMHelper envHelper;
|
||||||
envHelper.callStaticVoidMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "killServer");
|
envHelper.callStaticVoidMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "killServer");
|
||||||
#endif
|
#endif
|
||||||
delete VLC;
|
vstd::clear_pointer(VLC);
|
||||||
VLC = nullptr;
|
|
||||||
CResourceHandler::clear();
|
CResourceHandler::clear();
|
||||||
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef VCMI_ANDROID
|
#ifdef VCMI_ANDROID
|
||||||
|
@ -43,6 +43,7 @@ typedef boost::asio::basic_stream_socket < boost::asio::ip::tcp , boost::asio::s
|
|||||||
|
|
||||||
class CVCMIServer
|
class CVCMIServer
|
||||||
{
|
{
|
||||||
|
ui16 port;
|
||||||
boost::asio::io_service *io;
|
boost::asio::io_service *io;
|
||||||
TAcceptor * acceptor;
|
TAcceptor * acceptor;
|
||||||
|
|
||||||
|
@ -65,6 +65,12 @@ bool CloseServer::applyGh( CGameHandler *gh )
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LeaveGame::applyGh( CGameHandler *gh )
|
||||||
|
{
|
||||||
|
gh->playerLeftGame(c->connectionID);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool EndTurn::applyGh( CGameHandler *gh )
|
bool EndTurn::applyGh( CGameHandler *gh )
|
||||||
{
|
{
|
||||||
PlayerColor player = GS(gh)->currentPlayer;
|
PlayerColor player = GS(gh)->currentPlayer;
|
||||||
|
Loading…
Reference in New Issue
Block a user