diff --git a/include/Helpers/NetworkingObjects/NetObjManager.cpp b/include/Helpers/NetworkingObjects/NetObjManager.cpp index 73f57fd..47e15d2 100644 --- a/include/Helpers/NetworkingObjects/NetObjManager.cpp +++ b/include/Helpers/NetworkingObjects/NetObjManager.cpp @@ -8,6 +8,9 @@ namespace NetworkingObjects { typeList(initTypeList), nextTypeID(0) {} + bool NetObjManager::is_server() const { + return isServer; + } void NetObjManager::read_update_message(cereal::PortableBinaryInputArchive& a, const std::shared_ptr& clientReceivedFrom) { NetObjID id; a(id); diff --git a/include/Helpers/NetworkingObjects/NetObjManager.hpp b/include/Helpers/NetworkingObjects/NetObjManager.hpp index b22f64d..6cde3b8 100644 --- a/include/Helpers/NetworkingObjects/NetObjManager.hpp +++ b/include/Helpers/NetworkingObjects/NetObjManager.hpp @@ -21,21 +21,17 @@ namespace NetworkingObjects { void read_update_message(cereal::PortableBinaryInputArchive& a, const std::shared_ptr& clientReceivedFrom); void set_client(std::shared_ptr initClient, MessageCommandType initUpdateCommandID); void set_server(std::shared_ptr initServer, MessageCommandType initUpdateCommandID); + bool is_server() const; template NetObjPtr read_create_message(cereal::PortableBinaryInputArchive& a, const std::shared_ptr& clientReceivedFrom) { NetObjID id; NetTypeIDType typeID; a(id, typeID); auto& netTypeIDData = typeList->netTypeIDData[typeID]; - std::shared_ptr sharedPtr = isServer ? netTypeIDData.allocatorFuncServer() : netTypeIDData.allocatorFuncClient(); - auto [it, placed] = objectData.emplace(id, SingleObjectData{.netTypeID = typeID, .p = sharedPtr}); - if(!placed) - throw std::runtime_error("[NetObjManager::read_create_message] ID Collision on object creation"); if(isServer) - netTypeIDData.readConstructorFuncServer(NetObjPtr(this, id, sharedPtr), a, clientReceivedFrom); + return netTypeIDData.readConstructorFuncServer(*this, a, clientReceivedFrom).cast(); else - netTypeIDData.readConstructorFuncClient(NetObjPtr(this, id, sharedPtr), a, clientReceivedFrom); - return NetObjPtr(this, id, std::static_pointer_cast(sharedPtr)); + return netTypeIDData.readConstructorFuncClient(*this, a, clientReceivedFrom).cast(); } template NetObjPtr read_get_obj_from_message(cereal::PortableBinaryInputArchive& a) { NetObjID id; @@ -48,14 +44,14 @@ namespace NetworkingObjects { template NetObjPtr make_obj(Args&&... items) { auto sharedPtr = std::make_shared(items...); NetObjID newID = idGen->gen(); - if(!objectData.emplace(newID, SingleObjectData{.netTypeID = isServer ? typeList->typeIndexDataServer[std::type_index(typeid(T))].netTypeID : typeList->typeIndexDataClient[std::type_index(typeid(T))].netTypeID, .p = std::static_pointer_cast(sharedPtr)}).second) + if(!objectData.emplace(newID, SingleObjectData{.netTypeID = isServer ? typeList->typeIndexDataServer[std::type_index(typeid(T*))].netTypeID : typeList->typeIndexDataClient[std::type_index(typeid(T*))].netTypeID, .p = std::static_pointer_cast(sharedPtr)}).second) throw std::runtime_error("[NetObjManager::make_obj] ID Collision"); return NetObjPtr(this, newID, sharedPtr); } template NetObjPtr obj_from_ptr(T* p) { std::shared_ptr sharedPtr(p); NetObjID newID = idGen->gen(); - if(!objectData.emplace(newID, SingleObjectData{.netTypeID = isServer ? typeList->typeIndexDataServer[std::type_index(typeid(T))].netTypeID : typeList->typeIndexDataClient[std::type_index(typeid(T))].netTypeID, .p = std::static_pointer_cast(sharedPtr)}).second) + if(!objectData.emplace(newID, SingleObjectData{.netTypeID = isServer ? typeList->typeIndexDataServer[std::type_index(typeid(T*))].netTypeID : typeList->typeIndexDataClient[std::type_index(typeid(T*))].netTypeID, .p = std::static_pointer_cast(sharedPtr)}).second) throw std::runtime_error("[NetObjManager::obj_from_ptr] ID Collision"); return NetObjPtr(this, newID, sharedPtr); } diff --git a/include/Helpers/NetworkingObjects/NetObjManagerTypeList.hpp b/include/Helpers/NetworkingObjects/NetObjManagerTypeList.hpp index dae80cf..5161ccc 100644 --- a/include/Helpers/NetworkingObjects/NetObjManagerTypeList.hpp +++ b/include/Helpers/NetworkingObjects/NetObjManagerTypeList.hpp @@ -10,47 +10,36 @@ class NetObjManagerTypeList { public: template struct ServerClientClassFunctions { std::function&, cereal::PortableBinaryOutputArchive&)> writeConstructorFuncClient; - std::function&, cereal::PortableBinaryInputArchive&, const std::shared_ptr&)> readConstructorFuncClient; + std::function(NetObjManager&, cereal::PortableBinaryInputArchive&, const std::shared_ptr&)> readConstructorFuncClient; std::function&, cereal::PortableBinaryInputArchive&, const std::shared_ptr&)> readUpdateFuncClient; std::function&, cereal::PortableBinaryOutputArchive&)> writeConstructorFuncServer; - std::function&, cereal::PortableBinaryInputArchive&, const std::shared_ptr&)> readConstructorFuncServer; + std::function(NetObjManager&, cereal::PortableBinaryInputArchive&, const std::shared_ptr&)> readConstructorFuncServer; std::function&, cereal::PortableBinaryInputArchive&, const std::shared_ptr&)> readUpdateFuncServer; }; - template void register_class(const ServerClientClassFunctions& funcs) { + template void register_class(const ServerClientClassFunctions& funcs) { netTypeIDData[nextNetTypeID] = NetTypeIDContainer { - .readConstructorFuncClient = [f = funcs.readConstructorFuncClient](const NetObjPtr& obj, cereal::PortableBinaryInputArchive& message, const std::shared_ptr& c) { - if(f) - f(obj.cast(), message, c); - }, + .readConstructorFuncClient = funcs.readConstructorFuncClient, .readUpdateFuncClient = [f = funcs.readUpdateFuncClient](const NetObjPtr& obj, cereal::PortableBinaryInputArchive& message, const std::shared_ptr& c) { if(f) - f(obj.cast(), message, c); - }, - .allocatorFuncClient = []() { return std::static_pointer_cast(std::make_shared()); }, - - .readConstructorFuncServer = [f = funcs.readConstructorFuncServer](const NetObjPtr& obj, cereal::PortableBinaryInputArchive& message, const std::shared_ptr& c) { - if(f) - f(obj.cast(), message, c); + f(obj.cast(), message, c); }, + .readConstructorFuncServer = funcs.readConstructorFuncServer, .readUpdateFuncServer = [f = funcs.readUpdateFuncServer](const NetObjPtr& obj, cereal::PortableBinaryInputArchive& message, const std::shared_ptr& c) { if(f) - f(obj.cast(), message, c); + f(obj.cast(), message, c); }, - .allocatorFuncServer = []() { return std::static_pointer_cast(std::make_shared()); } }; - typeIndexDataClient[std::type_index(typeid(ClientActualType))] = TypeIndexContainer{ + typeIndexDataClient[std::type_index(typeid(ClientT*))] = TypeIndexContainer{ .netTypeID = nextNetTypeID, .writeConstructorFunc = [f = funcs.writeConstructorFuncClient](const NetObjPtr& obj, cereal::PortableBinaryOutputArchive& message) { - if(f) - f(obj.cast(), message); + f(obj.cast(), message); }, }; - typeIndexDataServer[std::type_index(typeid(ServerActualType))] = TypeIndexContainer{ + typeIndexDataServer[std::type_index(typeid(ServerT*))] = TypeIndexContainer{ .netTypeID = nextNetTypeID, .writeConstructorFunc = [f = funcs.writeConstructorFuncServer](const NetObjPtr& obj, cereal::PortableBinaryOutputArchive& message) { - if(f) - f(obj.cast(), message); + f(obj.cast(), message); }, }; nextNetTypeID++; @@ -64,17 +53,16 @@ class NetObjManagerTypeList { std::function&, cereal::PortableBinaryOutputArchive&)> writeConstructorFunc; }; + // std::type_index in this case is the typeinfo for the POINTER of the type in question. This ensures that we get a mapping for the exact type that was registered, not for a child of the type in case of inheritance std::unordered_map typeIndexDataClient; std::unordered_map typeIndexDataServer; struct NetTypeIDContainer { - std::function&, cereal::PortableBinaryInputArchive&, const std::shared_ptr&)> readConstructorFuncClient; + std::function(NetObjManager&, cereal::PortableBinaryInputArchive&, const std::shared_ptr&)> readConstructorFuncClient; std::function&, cereal::PortableBinaryInputArchive&, const std::shared_ptr&)> readUpdateFuncClient; - std::function()> allocatorFuncClient; - std::function&, cereal::PortableBinaryInputArchive&, const std::shared_ptr&)> readConstructorFuncServer; + std::function(NetObjManager&, cereal::PortableBinaryInputArchive&, const std::shared_ptr&)> readConstructorFuncServer; std::function&, cereal::PortableBinaryInputArchive&, const std::shared_ptr&)> readUpdateFuncServer; - std::function()> allocatorFuncServer; }; std::unordered_map netTypeIDData; diff --git a/include/Helpers/NetworkingObjects/NetObjOrderedList.hpp b/include/Helpers/NetworkingObjects/NetObjOrderedList.hpp index b7ed193..e3c90ae 100644 --- a/include/Helpers/NetworkingObjects/NetObjOrderedList.hpp +++ b/include/Helpers/NetworkingObjects/NetObjOrderedList.hpp @@ -71,15 +71,13 @@ namespace NetworkingObjects { virtual void erase_by_ptr(const NetObjPtr>& l, const NetObjOrderedListObjectInfoPtr& p) = 0; virtual void write_constructor(const NetObjPtr>& l, cereal::PortableBinaryOutputArchive& a) = 0; virtual void read_update(const NetObjPtr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&) = 0; - virtual void read_constructor(const NetObjPtr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&) = 0; + virtual void read_constructor_post_allocation(const NetObjPtr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&) = 0; private: template friend void register_ordered_list_class(NetObjManagerTypeList& t); static void write_constructor_func(const NetObjPtr>& l, cereal::PortableBinaryOutputArchive& a) { l->write_constructor(l, a); } - static void read_constructor_func(const NetObjPtr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr& c) { - l->read_constructor(l, a, c); - } + static NetObjPtr read_constructor_func(NetObjManager& objMan, cereal::PortableBinaryInputArchive& a, const std::shared_ptr& c); static void read_update_func(const NetObjPtr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr& c) { l->read_update(l, a, c); } @@ -111,7 +109,6 @@ namespace NetworkingObjects { }); } virtual void erase_by_index(const NetObjPtr>& l, uint32_t indexToErase) override { - NetObjOrderedListObjectInfoPtr& objToErase = data[indexToErase]; l.send_server_update_to_all_clients(RELIABLE_COMMAND_CHANNEL, [indexToErase](const NetObjPtr>&, cereal::PortableBinaryOutputArchive& a) { a(ObjPtrOrderedListCommand_StoC::ERASE_SINGLE, indexToErase); }); @@ -122,18 +119,18 @@ namespace NetworkingObjects { l.send_server_update_to_all_clients(RELIABLE_COMMAND_CHANNEL, [indexToErase = p->pos](const NetObjPtr>&, cereal::PortableBinaryOutputArchive& a) { a(ObjPtrOrderedListCommand_StoC::ERASE_SINGLE, indexToErase); }); - data.erase(data.begin() + p->pos); - set_positions_for_object_info_vector(data, p->pos); + uint32_t iToErase = p->pos; // We only have a reference to the pointer, so erasing it might destroy the pointer object. Save the index before erasing + data.erase(data.begin() + iToErase); + set_positions_for_object_info_vector(data, iToErase); } virtual void write_constructor(const NetObjPtr>& l, cereal::PortableBinaryOutputArchive& a) override { } - virtual void read_constructor(const NetObjPtr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr& c) override { + virtual void read_constructor_post_allocation(const NetObjPtr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr& c) override { } virtual void read_update(const NetObjPtr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr& c) override { ObjPtrOrderedListCommand_CtoS command; a(command); switch(command) { -//cereal::PortableBinaryInputArchive& a, const std::shared_ptr& clientReceivedFrom case ObjPtrOrderedListCommand_CtoS::INSERT_SINGLE: uint32_t newPos; a(newPos); @@ -142,7 +139,13 @@ namespace NetworkingObjects { case ObjPtrOrderedListCommand_CtoS::ERASE_SINGLE: NetObjID idToErase; a(idToErase); - insert(l, newPos, l.get_obj_man()->template read_create_message(a, c)); + std::erase_if(data, [&](NetObjOrderedListObjectInfoPtr& o) { + if(o->obj.get_net_id() == idToErase) { + erase_by_ptr(l, o); + return true; + } + return false; + }); break; } } @@ -169,20 +172,39 @@ namespace NetworkingObjects { virtual void insert(const NetObjPtr>& l, uint32_t posToInsertAt, const NetObjPtr& newObj) { } virtual void erase_by_index(const NetObjPtr>& l, uint32_t indexToErase) override { + indexToErase = std::min(indexToErase, clientData.size()); + auto& newObjInfoPtr = clientData[indexToErase]; + l.send_server_update_to_all_clients(RELIABLE_COMMAND_CHANNEL, [&newObjInfoPtr](const NetObjPtr>&, cereal::PortableBinaryOutputArchive& a) { + a(ObjPtrOrderedListCommand_CtoS::ERASE_SINGLE, newObjInfoPtr->obj.get_net_id()); + }); + clientData.erase(clientData.begin() + indexToErase); + set_positions_for_object_info_vector(clientData, indexToErase); } virtual void erase_by_ptr(const NetObjPtr>& l, const NetObjOrderedListObjectInfoPtr& p) override { + l.send_server_update_to_all_clients(RELIABLE_COMMAND_CHANNEL, [&p](const NetObjPtr>&, cereal::PortableBinaryOutputArchive& a) { + a(ObjPtrOrderedListCommand_CtoS::ERASE_SINGLE, p->obj.get_net_id()); + }); + uint32_t iToErase = p->pos; + clientData.erase(clientData.begin() + iToErase); + set_positions_for_object_info_vector(clientData, iToErase); } virtual void write_constructor(const NetObjPtr>& l, cereal::PortableBinaryOutputArchive& a) override { } - virtual void read_constructor(const NetObjPtr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&) override { + virtual void read_constructor_post_allocation(const NetObjPtr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&) override { } virtual void read_update(const NetObjPtr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&) override { ObjPtrOrderedListCommand_StoC c; a(c); switch(c) { case ObjPtrOrderedListCommand_StoC::INSERT_SINGLE: + uint32_t newPos; + a(newPos); + serverData.insert(serverData.begin() + newPos, std::make_shared>(l.get_obj_man()->template read_create_message(a, nullptr), newPos, false)); break; case ObjPtrOrderedListCommand_StoC::ERASE_SINGLE: + uint32_t posToErase; + a(posToErase); + serverData.erase(serverData.begin() + posToErase); break; } } @@ -191,8 +213,14 @@ namespace NetworkingObjects { std::vector> clientData; }; + template NetObjPtr NetObjOrderedList::read_constructor_func(NetObjManager& objMan, cereal::PortableBinaryInputArchive& a, const std::shared_ptr& c) { + NetObjPtr> allocatedPtr = objMan.is_server() ? objMan.make_obj>().template cast>() : objMan.make_obj>().template cast>(); + allocatedPtr->read_constructor_post_allocation(allocatedPtr, a, c); + return allocatedPtr.template cast(); + } + template void register_ordered_list_class(NetObjManagerTypeList& t) { - t.register_class, NetObjOrderedList, NetObjOrderedListClient, NetObjOrderedListServer>({ + t.register_class, NetObjOrderedList>({ .writeConstructorFuncClient = NetObjOrderedList::write_constructor_func, .readConstructorFuncClient = NetObjOrderedList::read_constructor_func, .readUpdateFuncClient = NetObjOrderedList::read_update_func, diff --git a/include/Helpers/NetworkingObjects/NetObjPtr.impl.hpp b/include/Helpers/NetworkingObjects/NetObjPtr.impl.hpp index a3a6027..a0946b0 100644 --- a/include/Helpers/NetworkingObjects/NetObjPtr.impl.hpp +++ b/include/Helpers/NetworkingObjects/NetObjPtr.impl.hpp @@ -90,7 +90,7 @@ namespace NetworkingObjects { } template void NetObjPtr::write_create_message(cereal::PortableBinaryOutputArchive& a) const { - auto& typeIndexData = objMan->isServer ? objMan->typeList->typeIndexDataServer[std::type_index(typeid(T))] : objMan->typeList->typeIndexDataClient[std::type_index(typeid(T))]; + auto& typeIndexData = objMan->isServer ? objMan->typeList->typeIndexDataServer[std::type_index(typeid(T*))] : objMan->typeList->typeIndexDataClient[std::type_index(typeid(T*))]; a(id, typeIndexData.netTypeID); typeIndexData.writeConstructorFunc(this->cast(), a); }