Added net ordered list test, and fixed ordering issues with list

This commit is contained in:
Yousef Khadadeh 2026-01-05 12:43:40 +03:00
parent 8611a2e6bb
commit 6e13c5742e
5 changed files with 137 additions and 17 deletions

View file

@ -11,6 +11,14 @@
#include <limits>
#include <list>
//#define ENABLE_NETOBJ_ORDERED_LIST_VERBOSE_DEBUG
#ifdef ENABLE_NETOBJ_ORDERED_LIST_VERBOSE_DEBUG
#define NETOBJ_ORDERED_LIST_VERBOSE_DEBUG(data, idMap) netobj_ordered_list_debug_check(data, idMap)
#else
#define NETOBJ_ORDERED_LIST_VERBOSE_DEBUG(data, idMap)
#endif
namespace NetworkingObjects {
enum class ObjPtrOrderedListCommand_StoC : uint8_t {
INSERT_LIST_CONSTRUCT,
@ -49,6 +57,37 @@ namespace NetworkingObjects {
}
}
#ifdef ENABLE_NETOBJ_ORDERED_LIST_VERBOSE_DEBUG
template <typename T> void netobj_ordered_list_debug_check(const std::list<NetObjOrderedListObjectInfo<T>>& l, const std::unordered_map<NetObjID, NetObjOrderedListIterator<T>>& idMap) {
uint32_t i = 0;
std::cout << "[netobj_ordered_list_debug_check] Debug print start\n";
for(auto& o : l) {
std::cout << "Pos " << o.pos << " with id " << o.obj.get_net_id().to_string() << '\n';
if(o.pos != i)
throw std::runtime_error("[netobj_ordered_list_debug_check] Position values are incorrect!");
++i;
auto it = idMap.find(o.obj.get_net_id());
if(it == idMap.end())
throw std::runtime_error("[netobj_ordered_list_debug_check] Could not find element in ID Map!");
if(&(*it->second) != &o)
throw std::runtime_error("[netobj_ordered_list_debug_check] ID Map and list point to different objects!");
}
if(l.size() != idMap.size()) {
std::cout << "ID map size: " << idMap.size() << " list size: " << l.size() << '\n';
throw std::runtime_error("[netobj_ordered_list_debug_check] ID map and list have different sizes!");
}
std::cout << "[netobj_ordered_list_debug_check] Debug print end" << std::endl;
}
#endif
template <typename T> void refresh_positions_complete(std::list<NetObjOrderedListObjectInfo<T>>& l) {
uint32_t i = 0;
for(auto& c : l) {
c.pos = i;
++i;
}
}
template <typename T> class NetObjOrderedList {
public:
// Don't use this function unless you're sure that class T isn't a base class
@ -301,6 +340,7 @@ namespace NetworkingObjects {
a(idPosition, newObjIt->obj.get_net_id());
});
this->call_insert_callback_list(toRet);
NETOBJ_ORDERED_LIST_VERBOSE_DEBUG(data, idToDataMap);
return toRet;
}
virtual void erase_it_list(const NetObjTemporaryPtr<NetObjOrderedList<T>>& l, const std::vector<NetObjOrderedListIterator<T>>& itList, std::vector<NetObjOwnerPtr<T>>* erasedObjects) {
@ -338,11 +378,13 @@ namespace NetworkingObjects {
});
set_position_obj_info_list<T>(smallestPosIt, data.end());
NETOBJ_ORDERED_LIST_VERBOSE_DEBUG(data, idToDataMap);
}
virtual void write_constructor(const NetObjTemporaryPtr<NetObjOrderedList<T>>& l, cereal::PortableBinaryOutputArchive& a) override {
a(static_cast<uint32_t>(data.size()));
for(auto& c : data)
c.obj.write_create_message(a);
NETOBJ_ORDERED_LIST_VERBOSE_DEBUG(data, idToDataMap);
}
virtual void read_constructor(const NetObjTemporaryPtr<NetObjOrderedList<T>>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>& c) override {
uint32_t constructedSize;
@ -353,6 +395,7 @@ namespace NetworkingObjects {
auto it = data.emplace(data.end(), l.get_obj_man()->template read_create_message<T>(a, c), i);
idToDataMap.emplace(data.back().obj.get_net_id(), it);
}
NETOBJ_ORDERED_LIST_VERBOSE_DEBUG(data, idToDataMap);
// Dont send the object data to all clients in the constructor, as the function that called read_create_message is also the one that will decide where to send the data of the constructed object
}
virtual void read_update(const NetObjTemporaryPtr<NetObjOrderedList<T>>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>& c) override {
@ -373,17 +416,9 @@ namespace NetworkingObjects {
newObjs.emplace_back(NetObjOrderedListIterator<T>(), l.get_obj_man()->template read_create_message<T>(a, c));
}
uint32_t currentIndex = data.size();
NetObjOrderedListIterator<T> currentIt = data.end();
for(std::pair<std::pair<NetObjOrderedListIterator<T>, NetObjOwnerPtr<T>>&, uint32_t&> elem : (std::views::zip(newObjs, insertIndices) | std::views::reverse)) {
uint32_t index = elem.second;
auto& it = elem.first.first;
while(currentIndex != index) {
--currentIndex;
--currentIt;
}
it = currentIt;
}
std::vector<NetObjOrderedListIterator<T>> itList = this->at_ordered_indices(insertIndices);
for(size_t i = 0; i < itList.size(); i++)
newObjs[i].first = itList[i];
insert_ordered_list(l, c, newObjs);
break;
@ -445,6 +480,7 @@ namespace NetworkingObjects {
}
});
this->call_insert_callback_list(toRet);
NETOBJ_ORDERED_LIST_VERBOSE_DEBUG(clientData, clientIdToDataMap);
return toRet;
}
virtual void erase_it_list(const NetObjTemporaryPtr<NetObjOrderedList<T>>& l, const std::vector<NetObjOrderedListIterator<T>>& itList, std::vector<NetObjOwnerPtr<T>>* erasedObjects) {
@ -481,6 +517,7 @@ namespace NetworkingObjects {
});
set_position_obj_info_list<T>(smallestPosIt, clientData.end());
NETOBJ_ORDERED_LIST_VERBOSE_DEBUG(clientData, clientIdToDataMap);
}
virtual void write_constructor(const NetObjTemporaryPtr<NetObjOrderedList<T>>& l, cereal::PortableBinaryOutputArchive& a) override {
a(static_cast<uint32_t>(clientData.size()));
@ -491,6 +528,7 @@ namespace NetworkingObjects {
auto serverIt = serverData.emplace(serverData.end(), c.obj.get_net_id()); // We are the ones who made this list, so fill up
serverIdToDataMap.emplace(c.obj.get_net_id(), serverIt);
}
NETOBJ_ORDERED_LIST_VERBOSE_DEBUG(clientData, clientIdToDataMap);
}
virtual void read_constructor(const NetObjTemporaryPtr<NetObjOrderedList<T>>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>&) override {
uint32_t constructedSize;
@ -505,6 +543,7 @@ namespace NetworkingObjects {
auto serverIt = serverData.emplace(serverData.end(), clientIt->obj.get_net_id());
serverIdToDataMap.emplace(clientIt->obj.get_net_id(), serverIt);
}
NETOBJ_ORDERED_LIST_VERBOSE_DEBUG(clientData, clientIdToDataMap);
}
virtual void read_update(const NetObjTemporaryPtr<NetObjOrderedList<T>>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>&) override {
ObjPtrOrderedListCommand_StoC c;
@ -515,17 +554,18 @@ namespace NetworkingObjects {
a(newObjsSize);
std::vector<NetworkingObjects::NetObjID> idsBeforeElements;
std::vector<std::list<NetObjID>::iterator> serverInsertIts;
std::vector<std::pair<NetObjOrderedListIterator<T>, NetObjOwnerPtr<T>>> newObjs;
for(uint32_t i = 0; i < newObjsSize; i++) {
auto& idBeforeElement = idsBeforeElements.emplace_back();
a(idBeforeElement);
newObjs.emplace_back(get_client_iterator_from_server_previous_net_obj_id(idBeforeElement), l.get_obj_man()->template read_create_message<T>(a, nullptr));
serverInsertIts.emplace_back(get_server_iterator_from_server_previous_net_obj_id(idBeforeElement));
}
for(uint32_t i = 0; i < newObjsSize; i++) {
auto serverInsertAtIt = get_server_iterator_from_server_previous_net_obj_id(idsBeforeElements[i]);
auto serverIt = serverData.emplace(serverInsertAtIt, newObjs[i].second.get_net_id());
auto serverIt = serverData.emplace(serverInsertIts[i], newObjs[i].second.get_net_id());
serverIdToDataMap.emplace(newObjs[i].second.get_net_id(), serverIt);
}
@ -539,9 +579,11 @@ namespace NetworkingObjects {
if(i == 0)
firstInsertedIt = newObjIt;
}
set_position_obj_info_list<T>(firstInsertedIt, clientData.end());
this->call_insert_callback_list(insertedIterators);
NETOBJ_ORDERED_LIST_VERBOSE_DEBUG(clientData, clientIdToDataMap);
break;
}
case ObjPtrOrderedListCommand_StoC::INSERT_LIST_REFERENCE: {
@ -551,6 +593,7 @@ namespace NetworkingObjects {
struct PerElementData {
NetworkingObjects::NetObjID idBeforeElement;
NetworkingObjects::NetObjID refID;
std::list<NetObjID>::iterator serverInsertIt;
bool foundInClient;
NetObjOrderedListIterator<T> clientObjectIt;
NetObjOrderedListIterator<T> clientInsertPosIt;
@ -560,6 +603,7 @@ namespace NetworkingObjects {
for(uint32_t i = 0; i < newObjsSize; i++) {
auto& elemData = receivedElements.emplace_back();
a(elemData.idBeforeElement, elemData.refID);
elemData.serverInsertIt = get_server_iterator_from_server_previous_net_obj_id(elemData.idBeforeElement);
}
std::list<NetObjOrderedListObjectInfo<T>> referredToObjectData;
@ -577,7 +621,7 @@ namespace NetworkingObjects {
if(startRefreshFrom != clientData.end())
startRefreshFrom->pos = elemData.clientObjectIt->pos;
}
referredToObjectData.splice(referredToObjectData.end(), clientData, elemData.clientObjectIt, std::next(elemData.clientObjectIt));
referredToObjectData.splice(referredToObjectData.end(), clientData, elemData.clientObjectIt);
clientIdToDataMap.erase(clientIdToDataMapIt);
elemData.foundInClient = true;
}
@ -586,6 +630,7 @@ namespace NetworkingObjects {
}
set_position_obj_info_list<T>(startRefreshFrom, clientData.end());
NETOBJ_ORDERED_LIST_VERBOSE_DEBUG(clientData, clientIdToDataMap);
for(auto& elemData : receivedElements) {
if(elemData.foundInClient)
@ -593,8 +638,7 @@ namespace NetworkingObjects {
}
for(auto& elemData : receivedElements) {
auto serverInsertAtIt = get_server_iterator_from_server_previous_net_obj_id(elemData.idBeforeElement);
auto serverIt = serverData.emplace(serverInsertAtIt, elemData.refID);
auto serverIt = serverData.emplace(elemData.serverInsertIt, elemData.refID);
serverIdToDataMap.emplace(elemData.refID, serverIt);
}
@ -607,7 +651,7 @@ namespace NetworkingObjects {
firstInsertedActualPos = elemData.clientInsertPosIt->pos;
firstInsertedIt = elemData.clientObjectIt;
}
clientData.splice(elemData.clientInsertPosIt, referredToObjectData, elemData.clientObjectIt, std::next(elemData.clientObjectIt));
clientData.splice(elemData.clientInsertPosIt, referredToObjectData, elemData.clientObjectIt);
clientIdToDataMap.emplace(elemData.clientObjectIt->obj.get_net_id(), elemData.clientObjectIt);
}
@ -626,6 +670,7 @@ namespace NetworkingObjects {
actualPos++;
}
}
NETOBJ_ORDERED_LIST_VERBOSE_DEBUG(clientData, clientIdToDataMap);
break;
}
case ObjPtrOrderedListCommand_StoC::ERASE_ID_LIST: {
@ -655,6 +700,7 @@ namespace NetworkingObjects {
}
set_position_obj_info_list<T>(smallestPosIt, clientData.end());
NETOBJ_ORDERED_LIST_VERBOSE_DEBUG(clientData, clientIdToDataMap);
break;
}
}