Fixed some errors related to disconnecting

This commit is contained in:
Yousef Khadadeh 2025-12-09 17:20:27 +03:00
parent 9649135f43
commit 65436429b8
7 changed files with 119 additions and 56 deletions

View file

@ -45,12 +45,22 @@ void NetClient::update() {
if(isDisconnected)
return;
if(std::chrono::steady_clock::now() - lastMessageTime >= NetLibrary::TIMEOUT_DURATION) {
Logger::get().log("INFO", "Connection timed out");
Logger::get().log("INFO", "[NetClient::update] Connection timed out");
isDisconnected = true;
return;
}
parse_received_messages();
send_queued_messages();
try {
parse_received_messages();
send_queued_messages();
}
catch(const std::exception& e) {
Logger::get().log("INFO", "[NetClient::update] Exception thrown while parsing and sending messages: " + std::string(e.what()));
isDisconnected = true;
}
catch(...) {
Logger::get().log("INFO", "[NetClient::update] Unknown exception thrown while parsing and sending messages.");
isDisconnected = true;
}
}
void NetClient::parse_received_messages() {

View file

@ -26,8 +26,20 @@ void NetServer::update() {
if(client->setToDisconnect)
disconnectCallback(client);
else {
client->parse_received_messages(*this);
client->send_queued_messages(*this);
try {
client->parse_received_messages(*this);
client->send_queued_messages(*this);
}
catch(const std::exception& e) {
Logger::get().log("INFO", "[NetServer::update] Exception thrown while parsing and sending messages for a client: " + std::string(e.what()));
client->setToDisconnect = true;
disconnectCallback(client);
}
catch(...) {
Logger::get().log("INFO", "[NetServer::update] Unknown exception thrown while parsing and sending messages for a client.");
client->setToDisconnect = true;
disconnectCallback(client);
}
}
}
}

View file

@ -101,19 +101,24 @@ namespace NetworkingObjects {
uint32_t actualPosToInsertAt = posToInsertAt = std::min<uint32_t>(posToInsertAt, data.size());
// Find duplicate. If found, erase the duplicate before inserting
std::shared_ptr<NetObjOrderedListObjectInfo<T>> newObjInfoPtr;
auto itObjAlreadyInData = idToDataMap.find(newObj.get_net_id());
if(itObjAlreadyInData != idToDataMap.end()) {
uint32_t posToErase = itObjAlreadyInData->second->pos;
newObjInfoPtr = data[posToErase];
data.erase(data.begin() + posToErase);
idToDataMap.erase(itObjAlreadyInData);
if(posToErase < actualPosToInsertAt) // Shift insert position if an element was erased before the insert position
actualPosToInsertAt--;
newObjInfoPtr->pos = actualPosToInsertAt;
data.insert(data.begin() + actualPosToInsertAt, newObjInfoPtr);
}
else {
// Insert the new object if no duplicate found
newObjInfoPtr = std::make_shared<NetObjOrderedListObjectInfo<T>>(newObj, 0, false);
data.insert(data.begin() + actualPosToInsertAt, newObjInfoPtr);
idToDataMap.emplace(newObjInfoPtr->obj.get_net_id(), newObjInfoPtr);
}
// Insert the new object
auto newObjInfoPtr = std::make_shared<NetObjOrderedListObjectInfo<T>>(newObj, actualPosToInsertAt, false);
data.insert(data.begin() + actualPosToInsertAt, newObjInfoPtr);
idToDataMap.emplace(newObjInfoPtr->obj.get_net_id(), newObjInfoPtr);
l.send_server_update_to_all_clients(RELIABLE_COMMAND_CHANNEL, [&newObjInfoPtr, posToInsertAt](const NetObjPtr<NetObjOrderedList<T>>&, cereal::PortableBinaryOutputArchive& a) {
a(ObjPtrOrderedListCommand_StoC::INSERT_SINGLE, posToInsertAt); // Dont send actual pos to insert at, since client will check for duplicates on its own and shift the index if necessary
newObjInfoPtr->obj.write_create_message(a);
@ -182,20 +187,28 @@ namespace NetworkingObjects {
virtual void insert(const NetObjPtr<NetObjOrderedList<T>>& l, uint32_t posToInsertAt, const NetObjPtr<T>& newObj) {
uint32_t actualPosToInsertAt = posToInsertAt = std::min<uint32_t>(posToInsertAt, clientData.size());
// Find duplicate. If found, erase the duplicate before inserting
NetObjOrderedListObjectInfoPtr<T> newObjInfoPtr;
auto itObjAlreadyInData = clientIdToDataMap.find(newObj.get_net_id());
if(itObjAlreadyInData != clientIdToDataMap.end()) {
uint32_t posToErase = itObjAlreadyInData->second->pos;
newObjInfoPtr = clientData[posToErase];
clientData.erase(clientData.begin() + posToErase);
clientIdToDataMap.erase(itObjAlreadyInData);
if(posToErase < actualPosToInsertAt) // Shift insert position if an element was erased before the insert position
actualPosToInsertAt--;
clientData.insert(clientData.begin() + actualPosToInsertAt, newObjInfoPtr);
}
else {
auto serverIt = serverIdToDataMap.find(newObj.get_net_id()); // No duplicate in client data, but check if it's already in server data
if(serverIt != serverIdToDataMap.end())
newObjInfoPtr = serverIt->second;
else
newObjInfoPtr = std::make_shared<NetObjOrderedListObjectInfo<T>>(newObj, 0, true);
clientData.insert(clientData.begin() + actualPosToInsertAt, newObjInfoPtr);
clientIdToDataMap.emplace(newObjInfoPtr->obj.get_net_id(), newObjInfoPtr);
}
// Insert the new object
auto newObjInfoPtr = std::make_shared<NetObjOrderedListObjectInfo<T>>(newObj, actualPosToInsertAt, false);
clientData.insert(clientData.begin() + actualPosToInsertAt, newObjInfoPtr);
clientIdToDataMap.emplace(newObjInfoPtr->obj.get_net_id(), newObjInfoPtr);
newObjInfoPtr->syncIgnore = true;
l.send_client_update(RELIABLE_COMMAND_CHANNEL, [&newObjInfoPtr, posToInsertAt](const NetObjPtr<NetObjOrderedList<T>>&, cereal::PortableBinaryOutputArchive& a) {
a(ObjPtrOrderedListCommand_CtoS::INSERT_SINGLE, posToInsertAt); // Don't put actual pos to insert at, since the server will check for duplicates and might shift the index on its own
newObjInfoPtr->obj.write_create_message(a);
@ -235,26 +248,43 @@ namespace NetworkingObjects {
a(c);
switch(c) {
case ObjPtrOrderedListCommand_StoC::INSERT_SINGLE: {
uint32_t newPos;
a(newPos);
auto toInsert = std::make_shared<NetObjOrderedListObjectInfo<T>>(l.get_obj_man()->template read_create_message<T>(a, nullptr), newPos, false);
auto it = serverIdToDataMap.find(toInsert->obj.get_net_id());
uint32_t newServerPos;
a(newServerPos);
auto objToInsert = l.get_obj_man()->template read_create_message<T>(a, nullptr);
auto it = serverIdToDataMap.find(objToInsert.get_net_id());
if(it != serverIdToDataMap.end()) {
uint32_t posToErase = it->second->pos;
serverData.erase(serverData.begin() + posToErase);
serverIdToDataMap.erase(it);
if(posToErase < newPos)
newPos--; // Shift if there was a duplicate before this
uint32_t serverPosErased = std::numeric_limits<uint32_t>::max();
std::erase_if(serverData, [&](auto& objInfo) {
if(objToInsert.get_net_id() == objInfo->obj.get_net_id()) {
serverPosErased = &objInfo - &serverData[0];
return true;
}
return false;
});
assert(serverPosErased != std::numeric_limits<uint32_t>::max());
if(serverPosErased < newServerPos)
newServerPos--; // Shift if there was a duplicate before this
//it->second->pos = newServerPos; // NOTE: DO NOT set the pos variable here, as pos is reserved for the position in the client vector
serverData.insert(serverData.begin() + newServerPos, it->second);
}
else {
NetObjOrderedListObjectInfoPtr<T> objInfoToInsert;
auto clientIt = clientIdToDataMap.find(objToInsert.get_net_id());
if(clientIt != clientIdToDataMap.end())
objInfoToInsert = clientIt->second;
else
objInfoToInsert = std::make_shared<NetObjOrderedListObjectInfo<T>>(objToInsert, 0, false);
objInfoToInsert->syncIgnore = false;
serverData.insert(serverData.begin() + newServerPos, objInfoToInsert);
serverIdToDataMap.emplace(objInfoToInsert->obj.get_net_id(), objInfoToInsert);
}
serverIdToDataMap.emplace(toInsert->obj.get_net_id(), toInsert);
serverData.insert(serverData.begin() + newPos, toInsert);
break;
}
case ObjPtrOrderedListCommand_StoC::ERASE_SINGLE: {
uint32_t posToErase;
a(posToErase);
NetObjID objID = serverData[posToErase]->obj.get_net_id();
serverData.erase(serverData.begin() + posToErase);
uint32_t serverPosToErase;
a(serverPosToErase);
NetObjID objID = serverData[serverPosToErase]->obj.get_net_id();
serverData.erase(serverData.begin() + serverPosToErase);
serverIdToDataMap.erase(objID);
break;
}

View file

@ -3,6 +3,7 @@
#include "Server/CommandList.hpp"
#include <chrono>
#include "World.hpp"
#include <Helpers/Logger.hpp>
void ConnectionManager::init_local_p2p(World& initWorld, const std::string& serverLocalID) {
localServer = std::make_unique<MainServer>(initWorld, serverLocalID);
@ -18,8 +19,9 @@ void ConnectionManager::connect_p2p(World& initWorld, const std::string& serverF
}
void ConnectionManager::update() {
if(localServer)
if(localServer) {
localServer->update();
}
if(client) {
client->update();
if(std::chrono::steady_clock::now() - lastKeepAliveTime > std::chrono::seconds(2)) {

View file

@ -96,6 +96,10 @@ void MainProgram::update() {
setTabToClose.reset();
}
std::erase_if(worlds, [&](const std::shared_ptr<World>& w) {
return w->setToDestroy;
});
if(worldIndex >= worlds.size())
worldIndex = worlds.size() - 1;
if(worlds.size() == 0)

View file

@ -77,11 +77,6 @@ World::World(MainProgram& initMain, OpenWorldInfo& worldInfo):
stringListTest->emplace_back_direct(stringListTest, "Hello");
stringListTest = netObjMan.make_obj<NetObjOrderedList<std::string>>();
stringListTest->emplace_back_direct(stringListTest, "World!");
//stringListTest->emplace_back_direct(stringListTest, "World");
//stringListTest->emplace_back_direct(stringListTest, "Test");
//for(const NetObjOrderedListObjectInfoPtr<std::string>& o : stringListTest->get_data())
// std::cout << "At position: " << o->get_pos() << " we have string: \"" << *o->get_obj() << "\" with object id " << o->get_obj().get_net_id().to_string() << std::endl;
}
}
@ -103,9 +98,10 @@ void World::init_client_callbacks() {
drawProg.initialize_draw_data(message);
message(bMan, gridMan);
stringListTest = netObjMan.read_create_message<NetworkingObjects::NetObjOrderedList<std::string>>(message, nullptr);
std::cout << "Client print: " << std::endl;
for(const NetworkingObjects::NetObjOrderedListObjectInfoPtr<std::string>& o : stringListTest->get_data())
std::cout << "At position: " << o->get_pos() << " we have string: \"" << *o->get_obj() << "\" with object id " << o->get_obj().get_net_id().to_string() << std::endl;
//std::cout << "============================================" << std::endl;
//std::cout << "Client print: " << std::endl;
//for(const NetworkingObjects::NetObjOrderedListObjectInfoPtr<std::string>& o : stringListTest->get_data())
// std::cout << "At position: " << o->get_pos() << " we have string: \"" << *o->get_obj() << "\" with object id " << o->get_obj().get_net_id().to_string() << std::endl;
}
nextClientID = get_max_id(ownID);
clientStillConnecting = false;
@ -120,11 +116,13 @@ void World::init_client_callbacks() {
add_chat_message(clients[id].displayName, "joined", Toolbar::ChatMessage::Type::JOIN);
});
con.client_add_recv_callback(CLIENT_UPDATE_NETWORK_OBJECT, [&](cereal::PortableBinaryInputArchive& message) {
if(!con.host_exists()) { // Dont update a direct connected client (which is just the server)
if(!con.host_exists() && !clientStillConnecting) { // Dont update a direct connected client (which is just the server), and dont process these until the CLIENT_INITIAL_DATA message is received first
netObjMan.read_update_message(message, nullptr);
std::cout << "Client print update: " << std::endl;
for(const NetworkingObjects::NetObjOrderedListObjectInfoPtr<std::string>& o : stringListTest->get_data())
std::cout << "At position: " << o->get_pos() << " we have string: \"" << *o->get_obj() << "\" with object id " << o->get_obj().get_net_id().to_string() << std::endl;
//std::cout << "============================================\n";
//std::cout << "Client print update: \n";
//for(const NetworkingObjects::NetObjOrderedListObjectInfoPtr<std::string>& o : stringListTest->get_data())
// std::cout << "At position: " << o->get_pos() << " we have string: \"" << *o->get_obj() << "\" with object id " << o->get_obj().get_net_id().to_string() << '\n';
//std::cout << std::endl;
}
});
con.client_add_recv_callback(CLIENT_USER_DISCONNECT, [&](cereal::PortableBinaryInputArchive& message) {
@ -180,13 +178,6 @@ size_t strToAddNum = 0;
void World::focus_update() {
con.update();
//testTimer++;
//if(testTimer == 1000) {
// std::cout << "added: " << strToAddNum << std::endl;
// stringListTest->emplace_back_direct(stringListTest, std::to_string(strToAddNum++));
// testTimer = 0;
//}
if(con.is_host_disconnected()) {
Logger::get().log("USERINFO", "Host connection failed");
clientStillConnecting = false;
@ -198,11 +189,8 @@ void World::focus_update() {
if(con.is_client_disconnected()) {
Logger::get().log("USERINFO", "Client connection failed");
clientStillConnecting = false;
clients.clear();
netSource.clear();
conType = CONNECTIONTYPE_LOCAL;
con = ConnectionManager();
setToDestroy = true;
return;
}
if(!clientStillConnecting) {
@ -220,6 +208,17 @@ void World::focus_update() {
}
con.client_send_items_to_server(UNRELIABLE_COMMAND_CHANNEL, SERVER_MOVE_SCREEN_MOUSE, main.input.mouse.pos);
drawProg.update();
testTimer++;
if(testTimer == 1) {
std::string strToAdd = (netObjMan.is_server() ? "Server " : "Client ") + std::to_string(strToAddNum++);
//std::cout << "============================================\n";
//std::cout << "Added: " << strToAdd << std::endl;
stringListTest->emplace_back_direct(stringListTest, strToAdd);
//for(const NetworkingObjects::NetObjOrderedListObjectInfoPtr<std::string>& o : stringListTest->get_data())
// std::cout << "At position: " << o->get_pos() << " we have string: \"" << *o->get_obj() << "\" with object id " << o->get_obj().get_net_id().to_string() << std::endl;
testTimer = 0;
}
}
drawData.cam.update_main(*this);
@ -247,6 +246,10 @@ void World::redo_with_checks() {
void World::unfocus_update() {
con.update();
if(con.is_client_disconnected()) {
Logger::get().log("USERINFO", "Client connection failed");
setToDestroy = true;
}
}
void World::set_canvas_background_color(const Vector3f& newBackColor, bool sendChangeOverNetwork) {

View file

@ -106,6 +106,8 @@ class World {
void scale_up_step();
uint64_t canvasScale = 0;
bool setToDestroy = false;
private:
ClientPortionID get_max_id(ServerPortionID serverID);