From 08670e5deeadb56376d2135e574cbe1920fa61fd Mon Sep 17 00:00:00 2001 From: Yousef Khadadeh Date: Mon, 22 Dec 2025 11:13:50 +0300 Subject: [PATCH] Can now move bookmarks in list --- .../NetworkingObjects/NetObjOrderedList.hpp | 45 ++++++++++++++++--- .../NetworkingObjects/NetObjOwnerPtr.decl.hpp | 1 + .../NetworkingObjects/NetObjOwnerPtr.impl.hpp | 16 +++++++ src/Bookmarks/BookmarkListItem.cpp | 5 +++ src/Bookmarks/BookmarkListItem.hpp | 1 + src/Bookmarks/BookmarkManager.cpp | 33 +++++++++++--- 6 files changed, 89 insertions(+), 12 deletions(-) diff --git a/include/Helpers/NetworkingObjects/NetObjOrderedList.hpp b/include/Helpers/NetworkingObjects/NetObjOrderedList.hpp index 8b9f173..6d26c25 100644 --- a/include/Helpers/NetworkingObjects/NetObjOrderedList.hpp +++ b/include/Helpers/NetworkingObjects/NetObjOrderedList.hpp @@ -68,8 +68,13 @@ namespace NetworkingObjects { ownerPtrOrderedList.emplace_back(newObjs[i].first, std::move(l.get_obj_man()->template make_obj_from_ptr(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 std::vector> insert_ordered_list_and_send_create(const NetObjTemporaryPtr>& l, std::vector>>& newObjPtrs) { + if(newObjPtrs.empty()) + return {}; + return l->insert_ordered_list(l, nullptr, newObjPtrs); + } + static void erase_unordered_set(const NetObjTemporaryPtr>& l, const std::unordered_set& ids, std::vector>* erasedObjects = nullptr) { + l->erase_by_unordered_set_ids(l, ids, erasedObjects); } static void erase(const NetObjTemporaryPtr>& l, uint32_t indexToErase) { l->erase_by_index(l, indexToErase); @@ -77,6 +82,7 @@ namespace NetworkingObjects { static uint32_t erase(const NetObjTemporaryPtr>& l, const NetObjID& id) { return l->erase_by_id(l, id); } + virtual void reassign_netobj_ids_call() = 0; typedef std::function& objInfo)> InsertCallback; typedef std::function& objInfo)> EraseCallback; @@ -108,7 +114,7 @@ namespace NetworkingObjects { 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_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 erase_by_unordered_set_ids(const NetObjTemporaryPtr>& l, std::unordered_set ids, std::vector>* erasedObjects) = 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; @@ -182,6 +188,13 @@ namespace NetworkingObjects { virtual bool empty() const override { return data.empty(); } + virtual void reassign_netobj_ids_call() override { + idToDataMap.clear(); + for(auto& d : data) { + d->obj.reassign_ids(); + idToDataMap[d->obj.get_net_id()] = d; + } + } protected: virtual NetObjOrderedListObjectInfoPtr insert(const NetObjTemporaryPtr>& l, const std::shared_ptr& clientInserting, uint32_t posToInsertAt, NetObjOwnerPtr newObj) override { posToInsertAt = std::min(posToInsertAt, data.size()); @@ -253,7 +266,7 @@ 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) { + virtual void erase_by_unordered_set_ids(const NetObjTemporaryPtr>& l, std::unordered_set ids, std::vector>* erasedObjects) { std::vector indicesToErase; std::erase_if(ids, [&](const NetObjID& id) { auto it = idToDataMap.find(id); @@ -268,6 +281,8 @@ namespace NetworkingObjects { std::sort(indicesToErase.begin(), indicesToErase.end()); for(uint32_t indexToErase : indicesToErase | std::views::reverse) { this->call_erase_callback(data[indexToErase]); + if(erasedObjects) + erasedObjects->emplace_back(std::move(data[indexToErase]->obj)); data.erase(data.begin() + indexToErase); } l.send_server_update_to_all_clients(RELIABLE_COMMAND_CHANNEL, [&indicesToErase](const NetObjTemporaryPtr>&, cereal::PortableBinaryOutputArchive& a) { @@ -325,7 +340,7 @@ namespace NetworkingObjects { case ObjPtrOrderedListCommand_CtoS::ERASE_MANY: { std::unordered_set idsToErase; a(idsToErase); - erase_by_unordered_set_ids(l, idsToErase); + erase_by_unordered_set_ids(l, idsToErase, nullptr); break; } } @@ -359,6 +374,16 @@ namespace NetworkingObjects { virtual bool empty() const override { return clientData.empty(); } + virtual void reassign_netobj_ids_call() override { + clientIdToDataMap.clear(); + clientJustInsertedSyncIgnore.clear(); + serverData.clear(); + for(auto& d : clientData) { + d->obj.reassign_ids(); + clientIdToDataMap[d->obj.get_net_id()] = d; + serverData.emplace_back(d->obj.get_net_id()); + } + } protected: virtual NetObjOrderedListObjectInfoPtr insert(const NetObjTemporaryPtr>& l, const std::shared_ptr&, uint32_t posToInsertAt, NetObjOwnerPtr newObj) { posToInsertAt = std::min(posToInsertAt, clientData.size()); @@ -428,7 +453,7 @@ namespace NetworkingObjects { set_positions_for_object_info_vector(clientData, iToErase); return iToErase; } - virtual void erase_by_unordered_set_ids(const NetObjTemporaryPtr>& l, std::unordered_set ids) { + virtual void erase_by_unordered_set_ids(const NetObjTemporaryPtr>& l, std::unordered_set ids, std::vector>* erasedObjects) { std::vector indicesToErase; std::erase_if(ids, [&](const NetObjID& id) { auto it = clientIdToDataMap.find(id); @@ -444,6 +469,8 @@ namespace NetworkingObjects { std::sort(indicesToErase.begin(), indicesToErase.end()); for(uint32_t indexToErase : indicesToErase | std::views::reverse) { this->call_erase_callback(clientData[indexToErase]); + if(erasedObjects) + erasedObjects->emplace_back(std::move(clientData[indexToErase]->obj)); clientData.erase(clientData.begin() + indexToErase); } l.send_client_update(RELIABLE_COMMAND_CHANNEL, [&ids](const NetObjTemporaryPtr>&, cereal::PortableBinaryOutputArchive& a) { @@ -453,8 +480,12 @@ namespace NetworkingObjects { } 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++) + serverData.clear(); + clientJustInsertedSyncIgnore.clear(); // Server will get the data and won't send back references to these objects, so dont ignore sync for these objects + for(size_t i = 0; i < clientData.size(); i++) { clientData[i]->obj.write_create_message(a); + serverData.emplace_back(clientData.back()->obj.get_net_id()); // We are the ones who made this list, so fill up + } } virtual void read_constructor(const NetObjTemporaryPtr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&) override { uint32_t constructedSize; diff --git a/include/Helpers/NetworkingObjects/NetObjOwnerPtr.decl.hpp b/include/Helpers/NetworkingObjects/NetObjOwnerPtr.decl.hpp index 7a98f9c..7fa1b73 100644 --- a/include/Helpers/NetworkingObjects/NetObjOwnerPtr.decl.hpp +++ b/include/Helpers/NetworkingObjects/NetObjOwnerPtr.decl.hpp @@ -18,6 +18,7 @@ namespace NetworkingObjects { NetObjManager* get_obj_man() const; NetObjID get_net_id() const; T* get() const; + void reassign_ids(); std::add_lvalue_reference_t operator*() const requires(!std::is_void_v); T* operator->() const; operator bool() const; diff --git a/include/Helpers/NetworkingObjects/NetObjOwnerPtr.impl.hpp b/include/Helpers/NetworkingObjects/NetObjOwnerPtr.impl.hpp index 25799e1..36f85b3 100644 --- a/include/Helpers/NetworkingObjects/NetObjOwnerPtr.impl.hpp +++ b/include/Helpers/NetworkingObjects/NetObjOwnerPtr.impl.hpp @@ -40,6 +40,22 @@ namespace NetworkingObjects { } } + template void NetObjOwnerPtr::reassign_ids() { + if(objMan && rawPtr) { + constexpr bool hasReassignNetObjIds = requires(T& t) { + t.reassign_netobj_ids_call(); + }; + auto it = objMan->objectData.find(id); + NetObjManager::SingleObjectData objData = it->second; + objData.p = rawPtr; + objMan->objectData.erase(it); + id = NetObjID::random_gen(); + objMan->objectData.emplace(id, objData); + if constexpr(hasReassignNetObjIds) + rawPtr->reassign_netobj_ids_call(); + } + } + template NetObjManager* NetObjOwnerPtr::get_obj_man() const { return objMan; } diff --git a/src/Bookmarks/BookmarkListItem.cpp b/src/Bookmarks/BookmarkListItem.cpp index 83d95cb..f313d20 100644 --- a/src/Bookmarks/BookmarkListItem.cpp +++ b/src/Bookmarks/BookmarkListItem.cpp @@ -20,6 +20,11 @@ BookmarkListItem::BookmarkListItem(NetworkingObjects::NetObjManager& netObjMan, bookmarkData = std::make_unique(initBookmarkData); } +void BookmarkListItem::reassign_netobj_ids_call() { + if(folderData) + folderData->folderList.reassign_ids(); +} + bool BookmarkListItem::is_folder() const { return folderData != nullptr; } diff --git a/src/Bookmarks/BookmarkListItem.hpp b/src/Bookmarks/BookmarkListItem.hpp index 8292a29..288b949 100644 --- a/src/Bookmarks/BookmarkListItem.hpp +++ b/src/Bookmarks/BookmarkListItem.hpp @@ -25,6 +25,7 @@ class BookmarkListItem { const std::string& get_name() const; static void register_class(NetworkingObjects::NetObjManager& netObjMan); static void set_name(const NetworkingObjects::NetObjTemporaryPtr& o, const std::string& newName); // Set once after editing is finished + void reassign_netobj_ids_call(); private: struct BookmarkFolderData { NetworkingObjects::NetObjOwnerPtr> folderList; diff --git a/src/Bookmarks/BookmarkManager.cpp b/src/Bookmarks/BookmarkManager.cpp index 0a4cce2..d7df633 100644 --- a/src/Bookmarks/BookmarkManager.cpp +++ b/src/Bookmarks/BookmarkManager.cpp @@ -56,8 +56,8 @@ void BookmarkManager::init() { void BookmarkManager::setup_list_gui(const std::string& id) { using namespace NetworkingObjects; if(bookmarkListRoot) { - std::optional toDeleteParent; - std::optional toDeleteObject; + std::optional toDeleteParent; + std::optional toDeleteObject; auto& gui = world.main.toolbar.gui; gui.tree_listing(id, bookmarkListRoot.get_net_id(), GUIStuff::TreeListing::DisplayData{ .getObjInListAtIndex = [&](NetObjID parentId, size_t index) -> std::optional { @@ -102,9 +102,32 @@ void BookmarkManager::setup_list_gui(const std::string& id) { } return false; }, - .moveObjectsToListAtIndex = [](NetworkingObjects::NetObjID listObj, size_t index, const std::vector& objsToInsert) { - static int i = 0; - std::cout << "Move happened! " << i++ << std::endl; + .moveObjectsToListAtIndex = [&](NetObjID listObj, size_t index, const std::vector& objsToInsert) { + std::unordered_map> toEraseMap; + uint32_t newIndex = index; + std::vector> toInsertObjPtrs; + auto& listPtr = world.netObjMan.get_obj_temporary_ref_from_id(listObj)->get_folder_list(); + + for(size_t i = 0; i < objsToInsert.size(); i++) { + toEraseMap[objsToInsert[i].parent].emplace(objsToInsert[i].object); + if(objsToInsert[i].parent == listObj && listPtr->get(objsToInsert[i].object)->pos <= index) + newIndex--; + } + + for(auto& [listToEraseFrom, setToErase] : toEraseMap) { + auto& listToEraseFromPtr = world.netObjMan.get_obj_temporary_ref_from_id(listToEraseFrom)->get_folder_list(); + listToEraseFromPtr->erase_unordered_set(listToEraseFromPtr, setToErase, &toInsertObjPtrs); + } + + std::vector>> toInsert; + for(uint32_t i = 0; i < objsToInsert.size(); i++) { + auto it = std::find_if(toInsertObjPtrs.begin(), toInsertObjPtrs.end(), [id = objsToInsert[i].object](NetObjOwnerPtr& objPtr) { + return objPtr.get_net_id() == id; + }); + toInsert.emplace_back(newIndex + i, std::move(*it)); + toInsert.back().second.reassign_ids(); + } + listPtr->insert_ordered_list_and_send_create(listPtr, toInsert); } }); if(toDeleteObject.has_value()) {