From 246a5ee541dbc4038a523614d96ab7e880701f57 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Wed, 3 Sep 2014 03:23:56 +1000 Subject: [PATCH] The server-side heartbeat is working and stable --- server/server_application.hpp | 1 + server/server_logic.cpp | 19 ++++++++++++ server/server_methods.cpp | 55 ++++++++++++++++++++++++++++++++++- todo.txt | 1 - 4 files changed, 74 insertions(+), 2 deletions(-) diff --git a/server/server_application.hpp b/server/server_application.hpp index df68357..105cffe 100644 --- a/server/server_application.hpp +++ b/server/server_application.hpp @@ -81,6 +81,7 @@ private: //utility methods //TODO: a function that only sends to characters in a certain proximity + void CleanupLostConnection(int index); void PumpPacket(SerialPacket* const); void PumpCharacterUnload(int uid); void CopyCharacterToPacket(CharacterPacket* const packet, int characterIndex); diff --git a/server/server_logic.cpp b/server/server_logic.cpp index 49dc68b..281c5b2 100644 --- a/server/server_logic.cpp +++ b/server/server_logic.cpp @@ -26,6 +26,7 @@ #include "utility.hpp" #include +#include #include #include @@ -144,6 +145,24 @@ void ServerApplication::Proc() { //update the internals //BUG: #30 Update the internals i.e. player positions + //TODO: This could be checked only every few seconds + //Check connections + for (auto& it : clientMap) { + if (std::chrono::steady_clock::now() - it.second.GetLastBeat() > std::chrono::seconds(5)) { + ServerPacket newPacket; + newPacket.type = SerialPacketType::PING; + network.SendTo(it.second.GetAddress(), &newPacket); + it.second.IncrementAttempts(); + } + + if (it.second.GetAttempts() > 2) { + CleanupLostConnection(it.first); + + //all iterators are invalid, so we can't continue + break; + } + } + //give the computer a break SDL_Delay(10); } diff --git a/server/server_methods.cpp b/server/server_methods.cpp index 390064f..bb3be96 100644 --- a/server/server_methods.cpp +++ b/server/server_methods.cpp @@ -34,7 +34,17 @@ void ServerApplication::HandlePing(ServerPacket* const argPacket) { } void ServerApplication::HandlePong(ServerPacket* const argPacket) { - //TODO: ServerApplications::HandlePong() + //find and update the specified client + + //BUGFIX: running multiple clients on one computer will result in matching host values; check the ports too + for (auto& it : clientMap) { + if (it.second.GetAddress().host == argPacket->srcAddress.host && + it.second.GetAddress().port == argPacket->srcAddress.port + ) { + it.second.ResetAttempts(); + break; + } + } } void ServerApplication::HandleBroadcastRequest(ServerPacket* const argPacket) { @@ -172,6 +182,8 @@ void ServerApplication::HandleCharacterNew(CharacterPacket* const argPacket) { return; } + //TODO: Make sure that a character's owner's account is loaded before continuing + //send this new character to all clients CharacterPacket newPacket; newPacket.type = SerialPacketType::CHARACTER_NEW; @@ -257,6 +269,47 @@ void ServerApplication::HandleSynchronize(ClientPacket* const argPacket) { //utility methods //------------------------- +void ServerApplication::CleanupLostConnection(int clientIndex) { + //NOTE: This assumes each player has only one account and character at a time + + //find the account + int accountIndex = -1; + for (auto& it : *accountMgr.GetContainer()) { + if (it.second.GetClientIndex() == clientIndex) { + accountIndex = it.first; + break; + } + } + + //find the character + int characterIndex = -1; + for (auto& it : *characterMgr.GetContainer()) { + if (it.second.GetOwner() == accountIndex) { + characterIndex = it.first; + break; + } + } + + //send a dissconnection message just in case + ClientPacket newPacket; + newPacket.type = SerialPacketType::DISCONNECT; + network.SendTo(clientMap[clientIndex].GetAddress(), &newPacket); + + //clean up this mess + characterMgr.UnloadCharacter(characterIndex); + accountMgr.UnloadAccount(accountIndex); + clientMap.erase(clientIndex); + + PumpCharacterUnload(characterIndex); + + //output a message + std::cerr << "Connection lost: " << std::endl; + std::cerr << "\tClient: " << clientIndex << std::endl; + std::cerr << "\tAccount: " << accountIndex << std::endl; + std::cerr << "\tCharacter: " << characterIndex << std::endl; + std::cout << clientMap.size() << " clients and " << accountMgr.GetContainer()->size() << " accounts total" << std::endl; +} + //TODO: a function that only sends to characters in a certain proximity void ServerApplication::PumpPacket(SerialPacket* const argPacket) { diff --git a/todo.txt b/todo.txt index aec3faf..e8af752 100644 --- a/todo.txt +++ b/todo.txt @@ -1,4 +1,3 @@ -TODO: Heartbeat systems TODO: Rejection messages TODO: The error handling is terrible TODO: Move the statistics into their own SQL table, instead of duplicating the structure a dozen times