diff --git a/include/Helpers/NetworkingObjects/NetObjOrderedList.hpp b/include/Helpers/NetworkingObjects/NetObjOrderedList.hpp index 7b66bc9..649e8cd 100644 --- a/include/Helpers/NetworkingObjects/NetObjOrderedList.hpp +++ b/include/Helpers/NetworkingObjects/NetObjOrderedList.hpp @@ -2,20 +2,29 @@ #include "Helpers/Networking/NetLibrary.hpp" #include "NetObjOwnerPtr.hpp" #include "NetObjTemporaryPtr.hpp" +#include "NetObjWeakPtr.hpp" #include "NetObjID.hpp" -#include "cereal/archives/portable_binary.hpp" +#include +#include +#include #include "NetObjManagerTypeList.hpp" +#include namespace NetworkingObjects { enum class ObjPtrOrderedListCommand_StoC : uint8_t { INSERT_SINGLE_CONSTRUCT, INSERT_SINGLE_REFERENCE, - ERASE_SINGLE + INSERT_MANY_CONSTRUCT, + INSERT_MANY_REFERENCE, + ERASE_SINGLE, + ERASE_MANY }; enum class ObjPtrOrderedListCommand_CtoS : uint8_t { INSERT_SINGLE, - ERASE_SINGLE + INSERT_MANY, + ERASE_SINGLE, + ERASE_MANY }; template struct NetObjOrderedListObjectInfo { @@ -51,21 +60,34 @@ namespace NetworkingObjects { NetObjOwnerPtr newObjOwner = l.get_obj_man()->template make_obj(newObj); return l->insert(l, nullptr, posToInsertAt, std::move(newObjOwner)); } + static std::vector*> insert_ordered_list_and_send_create(const NetObjTemporaryPtr>& l, const std::vector>& newObjs) { + if(newObjs.empty()) + return {}; + std::vector>> ownerPtrOrderedList; + for(uint32_t i = 0; i < static_cast(newObjs.size()); i++) + ownerPtrOrderedList.emplace_back(newObjs[i].first, std::move(l.get_obj_man()->template make_obj(newObjs[i].second))); + return l->insert_ordered_list(l, nullptr, ownerPtrOrderedList); + } + static void erase_unordered_set(const NetObjTemporaryPtr>& l, const std::unordered_set& ids) { + l->erase_by_unordered_set_ids(l, ids); + } static void erase(const NetObjTemporaryPtr>& l, uint32_t indexToErase) { l->erase_by_index(l, indexToErase); } - static uint32_t erase(const NetObjTemporaryPtr>& l, const NetObjTemporaryPtr& p) { - return l->erase_by_ptr(l, p); + static uint32_t erase(const NetObjTemporaryPtr>& l, const NetObjID& id) { + return l->erase_by_id(l, id); } - virtual bool contains(const NetObjTemporaryPtr& p) const = 0; + virtual bool contains(const NetObjID& p) const = 0; virtual uint32_t size() const = 0; virtual const NetObjOrderedListObjectInfoPtr& at(uint32_t index) const = 0; virtual bool empty() const = 0; virtual ~NetObjOrderedList() {} protected: virtual const NetObjOrderedListObjectInfoPtr& insert(const NetObjTemporaryPtr>& l, const std::shared_ptr& clientInserting, uint32_t posToInsertAt, NetObjOwnerPtr newObj) = 0; + virtual std::vector*> insert_ordered_list(const NetObjTemporaryPtr>& l, const std::shared_ptr& clientInserting, std::vector>>& newObj) = 0; virtual void erase_by_index(const NetObjTemporaryPtr>& l, uint32_t indexToErase) = 0; - virtual uint32_t erase_by_ptr(const NetObjTemporaryPtr>& l, const NetObjTemporaryPtr& p) = 0; + virtual uint32_t erase_by_id(const NetObjTemporaryPtr>& l, const NetObjID& id) = 0; + virtual void erase_by_unordered_set_ids(const NetObjTemporaryPtr>& l, std::unordered_set ids) = 0; virtual void write_constructor(const NetObjTemporaryPtr>& l, cereal::PortableBinaryOutputArchive& a) = 0; virtual void read_update(const NetObjTemporaryPtr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&) = 0; virtual void read_constructor(const NetObjTemporaryPtr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&) = 0; @@ -85,8 +107,8 @@ namespace NetworkingObjects { template class NetObjOrderedListServer : public NetObjOrderedList { public: NetObjOrderedListServer() {} - virtual bool contains(const NetObjTemporaryPtr& p) const override { - return idToDataMap.contains(p.get_net_id()); + virtual bool contains(const NetObjID& id) const override { + return idToDataMap.contains(id); } virtual uint32_t size() const override { return data.size(); @@ -113,6 +135,30 @@ namespace NetworkingObjects { set_positions_for_object_info_vector(data, posToInsertAt); return data[posToInsertAt]; } + virtual std::vector*> insert_ordered_list(const NetObjTemporaryPtr>& l, const std::shared_ptr& clientInserting, std::vector>>& newObjs) override { + std::vector*> toRet; + for(auto& [pos, newObj] : newObjs) { + uint32_t posToInsertAt = std::min(pos, data.size()); + auto newObjInfoPtr = std::make_shared>(std::move(newObj), 0); + data.insert(data.begin() + posToInsertAt, newObjInfoPtr); + idToDataMap.emplace(newObjInfoPtr->obj.get_net_id(), newObjInfoPtr); + toRet.emplace_back(&data[posToInsertAt]); + } + l.send_server_update_to_all_clients_except(clientInserting, RELIABLE_COMMAND_CHANNEL, [&toRet](const NetObjTemporaryPtr>&, cereal::PortableBinaryOutputArchive& a) { + a(ObjPtrOrderedListCommand_StoC::INSERT_MANY_CONSTRUCT, static_cast(toRet.size())); + for(const NetObjOrderedListObjectInfoPtr* objInfo : toRet) { + a((*objInfo)->pos); + (*objInfo)->obj.write_create_message(a); + } + }); + l.send_server_update_to_client(clientInserting, RELIABLE_COMMAND_CHANNEL, [&toRet](const NetObjTemporaryPtr>&, cereal::PortableBinaryOutputArchive& a) { + a(ObjPtrOrderedListCommand_StoC::INSERT_MANY_REFERENCE, static_cast(toRet.size())); + for(const NetObjOrderedListObjectInfoPtr* objInfo : toRet) + a((*objInfo)->pos, (*objInfo)->obj.get_net_id()); + }); + set_positions_for_object_info_vector(data, newObjs[0].first); + return toRet; + } virtual void erase_by_index(const NetObjTemporaryPtr>& l, uint32_t indexToErase) override { if(data.empty()) return; @@ -125,10 +171,10 @@ namespace NetworkingObjects { idToDataMap.erase(idToErase); set_positions_for_object_info_vector(data, indexToErase); } - virtual uint32_t erase_by_ptr(const NetObjTemporaryPtr>& l, const NetObjTemporaryPtr& p) override { + virtual uint32_t erase_by_id(const NetObjTemporaryPtr>& l, const NetObjID& id) override { if(data.empty()) return std::numeric_limits::max(); - auto it = idToDataMap.find(p.get_net_id()); + auto it = idToDataMap.find(id); if(it == idToDataMap.end()) return std::numeric_limits::max(); uint32_t indexToErase = it->second->pos; @@ -140,6 +186,26 @@ namespace NetworkingObjects { set_positions_for_object_info_vector(data, indexToErase); return indexToErase; } + virtual void erase_by_unordered_set_ids(const NetObjTemporaryPtr>& l, std::unordered_set ids) { + std::vector indicesToErase; + std::erase_if(ids, [&](const NetObjID& id) { + auto it = idToDataMap.find(id); + if(it == idToDataMap.end()) + return true; + indicesToErase.emplace_back(it->second->pos); + idToDataMap.erase(it); // Erase here since we already have the iterator + return false; + }); + if(ids.empty()) + return; + std::sort(indicesToErase.begin(), indicesToErase.end()); + for(uint32_t indexToErase : indicesToErase | std::views::reverse) + data.erase(data.begin() + indexToErase); + l.send_server_update_to_all_clients(RELIABLE_COMMAND_CHANNEL, [&indicesToErase](const NetObjTemporaryPtr>&, cereal::PortableBinaryOutputArchive& a) { + a(ObjPtrOrderedListCommand_StoC::ERASE_MANY, indicesToErase); + }); + set_positions_for_object_info_vector(data, indicesToErase.front()); + } virtual void write_constructor(const NetObjTemporaryPtr>& l, cereal::PortableBinaryOutputArchive& a) override { a(static_cast(data.size())); for(size_t i = 0; i < data.size(); i++) @@ -161,18 +227,38 @@ namespace NetworkingObjects { ObjPtrOrderedListCommand_CtoS command; a(command); switch(command) { - case ObjPtrOrderedListCommand_CtoS::INSERT_SINGLE: + case ObjPtrOrderedListCommand_CtoS::INSERT_SINGLE: { uint32_t newPos; a(newPos); insert(l, c, newPos, l.get_obj_man()->template read_create_message(a, c)); break; - case ObjPtrOrderedListCommand_CtoS::ERASE_SINGLE: + } + case ObjPtrOrderedListCommand_CtoS::INSERT_MANY: { + std::vector>> newObjs; + uint32_t newObjsSize; + a(newObjsSize); + for(uint32_t i = 0; i < newObjsSize; i++) { + uint32_t pos; + a(pos); + newObjs.emplace_back(pos, l.get_obj_man()->template read_create_message(a, c)); + } + insert_ordered_list(l, c, newObjs); + break; + } + case ObjPtrOrderedListCommand_CtoS::ERASE_SINGLE: { NetObjID idToErase; a(idToErase); auto it = idToDataMap.find(idToErase); if(it != idToDataMap.end()) erase_by_index(l, it->second->pos); break; + } + case ObjPtrOrderedListCommand_CtoS::ERASE_MANY: { + std::unordered_set idsToErase; + a(idsToErase); + erase_by_unordered_set_ids(l, idsToErase); + break; + } } } private: @@ -183,8 +269,8 @@ namespace NetworkingObjects { template class NetObjOrderedListClient : public NetObjOrderedList { public: NetObjOrderedListClient() {} - virtual bool contains(const NetObjTemporaryPtr& p) const override { - return clientIdToDataMap.contains(p.get_net_id()); + virtual bool contains(const NetObjID& id) const override { + return clientIdToDataMap.contains(id); } virtual uint32_t size() const override { return clientData.size(); @@ -209,6 +295,26 @@ namespace NetworkingObjects { set_positions_for_object_info_vector(clientData, posToInsertAt); return clientData[posToInsertAt]; } + virtual std::vector*> insert_ordered_list(const NetObjTemporaryPtr>& l, const std::shared_ptr& clientInserting, std::vector>>& newObjs) override { + std::vector*> toRet; + for(auto& [pos, newObj] : newObjs) { + uint32_t posToInsertAt = std::min(pos, clientData.size()); + auto newObjInfoPtr = std::make_shared>(std::move(newObj), 0); + clientData.insert(clientData.begin() + posToInsertAt, newObjInfoPtr); + clientIdToDataMap.emplace(newObjInfoPtr->obj.get_net_id(), newObjInfoPtr); + clientJustInsertedSyncIgnore.emplace(newObjInfoPtr->obj.get_net_id(), newObjInfoPtr); + toRet.emplace_back(&clientData[posToInsertAt]); + } + l.send_client_update(RELIABLE_COMMAND_CHANNEL, [&toRet](const NetObjTemporaryPtr>&, cereal::PortableBinaryOutputArchive& a) { + a(ObjPtrOrderedListCommand_CtoS::INSERT_MANY, static_cast(toRet.size())); + for(const NetObjOrderedListObjectInfoPtr* objInfo : toRet) { + a((*objInfo)->pos); + (*objInfo)->obj.write_create_message(a); + } + }); + set_positions_for_object_info_vector(clientData, newObjs[0].first); + return toRet; + } virtual void erase_by_index(const NetObjTemporaryPtr>& l, uint32_t indexToErase) override { if(clientData.empty()) return; @@ -219,23 +325,48 @@ namespace NetworkingObjects { }); uint32_t iToErase = p->pos; clientIdToDataMap.erase(p->obj.get_net_id()); + clientJustInsertedSyncIgnore.erase(p->obj.get_net_id()); clientData.erase(clientData.begin() + iToErase); set_positions_for_object_info_vector(clientData, iToErase); } - virtual uint32_t erase_by_ptr(const NetObjTemporaryPtr>& l, const NetObjTemporaryPtr& p) override { + virtual uint32_t erase_by_id(const NetObjTemporaryPtr>& l, const NetObjID& id) override { if(clientData.empty()) return std::numeric_limits::max(); - l.send_client_update(RELIABLE_COMMAND_CHANNEL, [&p](const NetObjTemporaryPtr>&, cereal::PortableBinaryOutputArchive& a) { - a(ObjPtrOrderedListCommand_CtoS::ERASE_SINGLE, p.get_net_id()); + auto it = clientIdToDataMap.find(id); + if(it == clientIdToDataMap.end()) + return std::numeric_limits::max(); + l.send_client_update(RELIABLE_COMMAND_CHANNEL, [&id](const NetObjTemporaryPtr>&, cereal::PortableBinaryOutputArchive& a) { + a(ObjPtrOrderedListCommand_CtoS::ERASE_SINGLE, id); }); - auto it = clientIdToDataMap.find(p.get_net_id()); uint32_t iToErase = it->second->pos; auto toRet = clientData[iToErase]; clientIdToDataMap.erase(it); + clientJustInsertedSyncIgnore.erase(id); clientData.erase(clientData.begin() + iToErase); set_positions_for_object_info_vector(clientData, iToErase); return iToErase; } + virtual void erase_by_unordered_set_ids(const NetObjTemporaryPtr>& l, std::unordered_set ids) { + std::vector indicesToErase; + std::erase_if(ids, [&](const NetObjID& id) { + auto it = clientIdToDataMap.find(id); + if(it == clientIdToDataMap.end()) + return true; + indicesToErase.emplace_back(it->second->pos); + clientIdToDataMap.erase(it); // Erase here since we already have the iterator + clientJustInsertedSyncIgnore.erase(id); + return false; + }); + if(ids.empty()) + return; + std::sort(indicesToErase.begin(), indicesToErase.end()); + for(uint32_t indexToErase : indicesToErase | std::views::reverse) + clientData.erase(clientData.begin() + indexToErase); + l.send_server_update_to_all_clients(RELIABLE_COMMAND_CHANNEL, [&ids](const NetObjTemporaryPtr>&, cereal::PortableBinaryOutputArchive& a) { + a(ObjPtrOrderedListCommand_CtoS::ERASE_MANY, ids); + }); + set_positions_for_object_info_vector(clientData, indicesToErase.front()); + } virtual void write_constructor(const NetObjTemporaryPtr>& l, cereal::PortableBinaryOutputArchive& a) override { a(static_cast(clientData.size())); for(size_t i = 0; i < clientData.size(); i++) @@ -257,15 +388,6 @@ namespace NetworkingObjects { ObjPtrOrderedListCommand_StoC c; a(c); switch(c) { - case ObjPtrOrderedListCommand_StoC::INSERT_SINGLE_REFERENCE: { - NetObjID newObjID; - uint32_t newServerPos; - a(newServerPos, newObjID); - serverData.insert(serverData.begin() + newServerPos, newObjID); - clientJustInsertedSyncIgnore.erase(newObjID); - sync(std::unordered_map>()); - break; - } case ObjPtrOrderedListCommand_StoC::INSERT_SINGLE_CONSTRUCT: { uint32_t newServerPos; a(newServerPos); @@ -278,6 +400,43 @@ namespace NetworkingObjects { sync(serverNewObjects); break; } + case ObjPtrOrderedListCommand_StoC::INSERT_SINGLE_REFERENCE: { + NetObjID newObjID; + uint32_t newServerPos; + a(newServerPos, newObjID); + serverData.insert(serverData.begin() + newServerPos, newObjID); + clientJustInsertedSyncIgnore.erase(newObjID); + sync(std::unordered_map>()); + break; + } + case ObjPtrOrderedListCommand_StoC::INSERT_MANY_CONSTRUCT: { + std::unordered_map> serverNewObjects; + uint32_t newObjsSize; + a(newObjsSize); + for(uint32_t i = 0; i < newObjsSize; i++) { + uint32_t newServerPos; + a(newServerPos); + auto objInfoToInsert = std::make_shared>(l.get_obj_man()->template read_create_message(a, nullptr), 0); + serverData.insert(serverData.begin() + newServerPos, objInfoToInsert->obj.get_net_id()); + clientJustInsertedSyncIgnore.erase(objInfoToInsert->obj.get_net_id()); + serverNewObjects.emplace(objInfoToInsert->obj.get_net_id(), objInfoToInsert); + } + sync(serverNewObjects); + break; + } + case ObjPtrOrderedListCommand_StoC::INSERT_MANY_REFERENCE: { + uint32_t newObjsSize; + a(newObjsSize); + for(uint32_t i = 0; i < newObjsSize; i++) { + NetObjID newObjID; + uint32_t newServerPos; + a(newServerPos, newObjID); + serverData.insert(serverData.begin() + newServerPos, newObjID); + clientJustInsertedSyncIgnore.erase(newObjID); + } + sync(std::unordered_map>()); + break; + } case ObjPtrOrderedListCommand_StoC::ERASE_SINGLE: { uint32_t serverPosToErase; a(serverPosToErase); @@ -293,6 +452,28 @@ namespace NetworkingObjects { } break; } + case ObjPtrOrderedListCommand_StoC::ERASE_MANY: { + std::vector serverPositionsToErase; + a(serverPositionsToErase); + std::vector clientIndicesToErase; + for(uint32_t serverPosToErase : serverPositionsToErase | std::views::reverse) { + NetObjID objID = serverData[serverPosToErase]; + serverData.erase(serverData.begin() + serverPosToErase); + auto it = clientIdToDataMap.find(objID); + if(it != clientIdToDataMap.end()) { + clientIdToDataMap.erase(it); + clientJustInsertedSyncIgnore.erase(objID); + clientIndicesToErase.emplace_back(it->second->pos); + } + } + std::sort(clientIndicesToErase.begin(), clientIndicesToErase.end()); + if(clientIndicesToErase.empty()) + break; + for(uint32_t indexToErase : clientIndicesToErase | std::views::reverse) + clientData.erase(clientData.begin() + indexToErase); + set_positions_for_object_info_vector(clientData, clientIndicesToErase.front()); + break; + } } } private: diff --git a/src/CanvasComponents/BrushStrokeCanvasComponent.cpp b/src/CanvasComponents/BrushStrokeCanvasComponent.cpp index 3efd85a..863752d 100644 --- a/src/CanvasComponents/BrushStrokeCanvasComponent.cpp +++ b/src/CanvasComponents/BrushStrokeCanvasComponent.cpp @@ -367,9 +367,6 @@ void BrushStrokeCanvasComponent::add_precheck_aabb_level(size_t level, const std } } -void BrushStrokeCanvasComponent::update(DrawingProgram& drawP) { -} - bool BrushStrokeCanvasComponent::collides_within_coords(const SCollision::ColliderCollection& checkAgainst) const { if(!SCollision::collide(checkAgainst, bounds)) return false; diff --git a/src/CanvasComponents/BrushStrokeCanvasComponent.hpp b/src/CanvasComponents/BrushStrokeCanvasComponent.hpp index 8bb81fd..f2bbf10 100644 --- a/src/CanvasComponents/BrushStrokeCanvasComponent.hpp +++ b/src/CanvasComponents/BrushStrokeCanvasComponent.hpp @@ -33,7 +33,6 @@ class BrushStrokeCanvasComponent : public CanvasComponent { private: virtual void draw(SkCanvas* canvas, const DrawData& drawData) const override; virtual void initialize_draw_data(DrawingProgram& drawP) override; - virtual void update(DrawingProgram& drawP) override; virtual bool collides_within_coords(const SCollision::ColliderCollection& checkAgainst) const override; void create_collider(); diff --git a/src/CanvasComponents/EllipseCanvasComponent.cpp b/src/CanvasComponents/EllipseCanvasComponent.cpp index 4cf97e4..2f3a68f 100644 --- a/src/CanvasComponents/EllipseCanvasComponent.cpp +++ b/src/CanvasComponents/EllipseCanvasComponent.cpp @@ -2,10 +2,7 @@ #include "Helpers/ConvertVec.hpp" #include "Helpers/SCollision.hpp" #include - -#ifndef IS_SERVER #include "../DrawCollision.hpp" -#endif CanvasComponent::CompType EllipseCanvasComponent::get_type() const { return CompType::ELLIPSE;