1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-25 22:42:04 +02:00

Full rework of pre-game interface and networking

New features for players:
* Loading for multiplayer. Any save could be used for multiplayer.
* Restart for multiplayer. All clients will restart together.
* Loading from single save.
* Hotseat mixed with network game. Multiple players per client.
* Now connection to server could be cancelled.
* Return to menu on disconnections instead of crashes.
* Restoring of last selected map, save or campaign on next run.

TLDR on important changes in engine code:
* UI: work with server separated from UI
* UI: all explitic blitting replaced with IntObject's
* UI: all new code use smart pointers instead of DISPOSE
* Gameplay always start through lobby controlled by server.
* Threads receiving netpacks now shared for lobby and gameplay.
* Campaigns: heroes for crossover now serialized as JsonNode.
This commit is contained in:
Arseniy Shestakov
2018-01-05 20:21:07 +03:00
parent 14f03e22da
commit ac66fc7f42
85 changed files with 8808 additions and 7938 deletions

View File

@@ -35,8 +35,9 @@ using namespace boost::asio::ip;
void CConnection::init()
{
boost::asio::ip::tcp::no_delay option(true);
socket->set_option(option);
socket->set_option(boost::asio::ip::tcp::no_delay(true));
socket->set_option(boost::asio::socket_base::send_buffer_size(4194304));
socket->set_option(boost::asio::socket_base::receive_buffer_size(4194304));
enableSmartPointerSerialization();
disableStackSendingByID();
@@ -50,25 +51,21 @@ void CConnection::init()
connected = true;
std::string pom;
//we got connection
oser & std::string("Aiya!\n") & name & myEndianess; //identify ourselves
iser & pom & pom & contactEndianess;
logNetwork->info("Established connection with %s", pom);
wmx = new boost::mutex();
rmx = new boost::mutex();
oser & std::string("Aiya!\n") & name & uuid & myEndianess; //identify ourselves
iser & pom & pom & contactUuid & contactEndianess;
logNetwork->info("Established connection with %s. UUID: %s", pom, contactUuid);
mutexRead = std::make_shared<boost::mutex>();
mutexWrite = std::make_shared<boost::mutex>();
handler = nullptr;
receivedStop = sendStop = false;
static int cid = 1;
connectionID = cid++;
iser.fileVersion = SERIALIZATION_VERSION;
}
CConnection::CConnection(std::string host, ui16 port, std::string Name)
:iser(this), oser(this), io_service(new asio::io_service), name(Name)
CConnection::CConnection(std::string host, ui16 port, std::string Name, std::string UUID)
: iser(this), oser(this), io_service(std::make_shared<asio::io_service>()), connectionID(0), name(Name), uuid(UUID)
{
int i;
boost::system::error_code error = asio::error::host_not_found;
socket = new tcp::socket(*io_service);
socket = std::make_shared<tcp::socket>(*io_service);
tcp::resolver resolver(*io_service);
tcp::resolver::iterator end, pom, endpoint_iterator = resolver.resolve(tcp::resolver::query(host, std::to_string(port)),error);
if(error)
@@ -114,25 +111,23 @@ connerror1:
logNetwork->error(error.message());
else
logNetwork->error("No error info. ");
delete io_service;
//delete socket;
throw std::runtime_error("Can't establish connection :(");
}
CConnection::CConnection(TSocket * Socket, std::string Name )
:iser(this), oser(this), socket(Socket),io_service(&Socket->get_io_service()), name(Name)//, send(this), rec(this)
CConnection::CConnection(std::shared_ptr<TSocket> Socket, std::string Name, std::string UUID)
: iser(this), oser(this), socket(Socket), io_service(&Socket->get_io_service()), connectionID(0), name(Name), uuid(UUID)
{
init();
}
CConnection::CConnection(TAcceptor * acceptor, boost::asio::io_service *Io_service, std::string Name)
: iser(this), oser(this), name(Name)//, send(this), rec(this)
CConnection::CConnection(std::shared_ptr<TAcceptor> acceptor, std::shared_ptr<boost::asio::io_service> Io_service, std::string Name, std::string UUID)
: iser(this), oser(this), connectionID(0), name(Name), uuid(UUID)
{
boost::system::error_code error = asio::error::host_not_found;
socket = new tcp::socket(*io_service);
socket = std::make_shared<tcp::socket>(*io_service);
acceptor->accept(*socket,error);
if (error)
{
logNetwork->error("Error on accepting: %s", error.message());
delete socket;
socket.reset();
throw std::runtime_error("Can't establish connection :(");
}
init();
@@ -171,12 +166,7 @@ CConnection::~CConnection()
if(handler)
handler->join();
delete handler;
close();
delete io_service;
delete wmx;
delete rmx;
}
template<class T>
@@ -193,7 +183,7 @@ void CConnection::close()
if(socket)
{
socket->close();
vstd::clear_pointer(socket);
socket.reset();
}
}
@@ -202,11 +192,6 @@ bool CConnection::isOpen() const
return socket && connected;
}
bool CConnection::isHost() const
{
return connectionID == 1;
}
void CConnection::reportState(vstd::CLoggerBase * out)
{
out->debug("CConnection");
@@ -219,19 +204,26 @@ void CConnection::reportState(vstd::CLoggerBase * out)
CPack * CConnection::retrievePack()
{
CPack *ret = nullptr;
boost::unique_lock<boost::mutex> lock(*rmx);
logNetwork->trace("Listening... ");
iser & ret;
logNetwork->trace("\treceived server message of type %s", (ret? typeid(*ret).name() : "nullptr"));
return ret;
CPack * pack = nullptr;
boost::unique_lock<boost::mutex> lock(*mutexRead);
iser & pack;
logNetwork->trace("\treceived CPack of type %s", (pack ? typeid(*pack).name() : "nullptr"));
if(pack == nullptr)
{
logNetwork->error("Received a nullptr CPack! You should check whether client and server ABI matches.");
}
else
{
pack->c = this->shared_from_this();
}
return pack;
}
void CConnection::sendPackToServer(const CPack &pack, PlayerColor player, ui32 requestID)
void CConnection::sendPack(const CPack * pack)
{
boost::unique_lock<boost::mutex> lock(*wmx);
logNetwork->trace("Sending to server a pack of type %s", typeid(pack).name());
oser & player & requestID & &pack; //packs has to be sent as polymorphic pointers!
boost::unique_lock<boost::mutex> lock(*mutexWrite);
logNetwork->trace("Sending a pack of type %s", typeid(*pack).name());
oser & pack;
}
void CConnection::disableStackSendingByID()
@@ -254,16 +246,7 @@ void CConnection::enableSmartPointerSerialization()
iser.smartPointerSerialization = oser.smartPointerSerialization = true;
}
void CConnection::prepareForSendingHeroes()
{
iser.loadedPointers.clear();
oser.savedPointers.clear();
disableSmartVectorMemberSerialization();
enableSmartPointerSerialization();
disableStackSendingByID();
}
void CConnection::enterPregameConnectionMode()
void CConnection::enterLobbyConnectionMode()
{
iser.loadedPointers.clear();
oser.savedPointers.clear();
@@ -271,6 +254,13 @@ void CConnection::enterPregameConnectionMode()
disableSmartPointerSerialization();
}
void CConnection::enterGameplayConnectionMode(CGameState * gs)
{
enableStackSendingByID();
disableSmartPointerSerialization();
addStdVecItems(gs);
}
void CConnection::disableSmartVectorMemberSerialization()
{
CSerializer::smartVectorMembersSerialization = false;
@@ -283,7 +273,7 @@ void CConnection::enableSmartVectorMemberSerializatoin()
std::string CConnection::toString() const
{
boost::format fmt("Connection with %s (ID: %d)");
fmt % name % connectionID;
return fmt.str();
boost::format fmt("Connection with %s (ID: %d UUID: %s)");
fmt % name % connectionID % uuid;
return fmt.str();
}