diff --git a/CMakeLists.txt b/CMakeLists.txt index 80d17d4..7bc3472 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,6 +79,9 @@ set(sources "src/main.cpp" "src/DrawingProgram/EllipseDrawEditTool.cpp" "src/DrawingProgram/RectDrawEditTool.cpp" "src/DrawingProgram/TextBoxEditTool.cpp" + #"src/CanvasComponents/CanvasComponentContainer.cpp" + #"src/CanvasComponents/CanvasComponentBrushStroke.cpp" + #"src/CanvasComponents/CanvasComponent.cpp" "src/DrawComponents/DrawEllipse.cpp" "src/DrawComponents/DrawRectangle.cpp" "src/DrawComponents/DrawImage.cpp" diff --git a/include/Helpers/NetworkingObjects/DelayUpdateSerializedClassManager.hpp b/include/Helpers/NetworkingObjects/DelayUpdateSerializedClassManager.hpp index 20c7528..8f8326f 100644 --- a/include/Helpers/NetworkingObjects/DelayUpdateSerializedClassManager.hpp +++ b/include/Helpers/NetworkingObjects/DelayUpdateSerializedClassManager.hpp @@ -9,16 +9,16 @@ namespace NetworkingObjects { public: template void register_class(NetObjManagerTypeList& t) { t.register_class({ - .writeConstructorFuncClient = [&](const NetObjPtr& o, cereal::PortableBinaryOutputArchive& a){client_write_func(std::nullopt, o, a);}, - .readConstructorFuncClient = [&](const NetObjPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&){delay_read_func(o, a);}, - .readUpdateFuncClient = [&](const NetObjPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&){delay_read_func(o, a);}, - .writeConstructorFuncServer = [&](const NetObjPtr& o, cereal::PortableBinaryOutputArchive& a){server_write_func(o, a);}, - .readConstructorFuncServer = [&](const NetObjPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&){delay_read_func(o, a);}, - .readUpdateFuncServer = [&](const NetObjPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&){server_read_update_func(o, a);} + .writeConstructorFuncClient = [&](const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a){client_write_func(std::nullopt, o, a);}, + .readConstructorFuncClient = [&](const NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&){delay_read_func_constructor(o, a);}, + .readUpdateFuncClient = [&](const NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&){delay_read_func(o, a);}, + .writeConstructorFuncServer = [&](const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a){server_write_func(o, a);}, + .readConstructorFuncServer = [&](const NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&){delay_read_func_constructor(o, a);}, + .readUpdateFuncServer = [&](const NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&){server_read_update_func(o, a);} }); } - template void send_update_to_all(const NetworkingObjects::NetObjPtr& o, bool finalUpdate) { - o.send_update_to_all(finalUpdate ? RELIABLE_COMMAND_CHANNEL : UNRELIABLE_COMMAND_CHANNEL, [&](const NetObjPtr& o, cereal::PortableBinaryOutputArchive& a) { + template void send_update_to_all(const NetworkingObjects::NetObjTemporaryPtr& o, bool finalUpdate) { + o.send_update_to_all(finalUpdate ? RELIABLE_COMMAND_CHANNEL : UNRELIABLE_COMMAND_CHANNEL, [&](const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a) { if(o.get_obj_man()->is_server()) server_write_func(o, a); else @@ -27,7 +27,7 @@ namespace NetworkingObjects { } void update(); private: - template void client_write_func(std::optional finalUpdate, const NetObjPtr& o, cereal::PortableBinaryOutputArchive& a) { + template void client_write_func(std::optional finalUpdate, const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a) { if(finalUpdate.has_value()) a(finalUpdate.value()); a(*o); @@ -35,10 +35,11 @@ namespace NetworkingObjects { if(it == updatingObjs.end()) { UpdatingObject toAdd; toAdd.objToUpdateCurrentData = std::static_pointer_cast(std::make_shared(*o)); + toAdd.doLastAssignment = std::make_shared(true); toAdd.lastUpdateTimePoint = std::chrono::steady_clock::now(); - toAdd.setDataAfterTimeout = [oWeak = NetObjWeakPtr(o), currentData = toAdd.objToUpdateCurrentData]() { - NetObjPtr oLock = oWeak.lock(); - if(oLock) + toAdd.setDataAfterTimeout = [oWeak = NetObjWeakPtr(o), currentData = toAdd.objToUpdateCurrentData, doLastAssignment = toAdd.doLastAssignment]() { + NetObjTemporaryPtr oLock = oWeak.lock(); + if(oLock && *doLastAssignment) *oLock = *std::static_pointer_cast(currentData); }; updatingObjs.emplace(o.get_net_id(), toAdd); @@ -49,28 +50,34 @@ namespace NetworkingObjects { } } - template void delay_read_func(const NetObjPtr& o, cereal::PortableBinaryInputArchive& a) { + template void delay_read_func_constructor(const NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a) { + a(*o); + } + + template void delay_read_func(const NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a) { auto it = updatingObjs.find(o.get_net_id()); if(it == updatingObjs.end()) a(*o); else { auto& [netID, updatingObjData] = *it; a(*std::static_pointer_cast(updatingObjData.objToUpdateCurrentData)); + *updatingObjData.doLastAssignment = true; } } - template void server_write_func(const NetObjPtr& o, cereal::PortableBinaryOutputArchive& a) { + template void server_write_func(const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a) { a(*o); auto it = updatingObjs.find(o.get_net_id()); if(it == updatingObjs.end()) { UpdatingObject toAdd; toAdd.objToUpdateCurrentData = std::static_pointer_cast(std::make_shared(*o)); toAdd.lastUpdateTimePoint = std::chrono::steady_clock::now(); - toAdd.setDataAfterTimeout = [oWeak = NetObjWeakPtr(o), currentData = toAdd.objToUpdateCurrentData]() { - NetObjPtr oLock = oWeak.lock(); - if(oLock) { + toAdd.doLastAssignment = std::make_shared(false); + toAdd.setDataAfterTimeout = [oWeak = NetObjWeakPtr(o), currentData = toAdd.objToUpdateCurrentData, doLastAssignment = toAdd.doLastAssignment]() { + NetObjTemporaryPtr oLock = oWeak.lock(); + if(oLock && *doLastAssignment) { *oLock = *std::static_pointer_cast(currentData); - oLock.send_server_update_to_all_clients(RELIABLE_COMMAND_CHANNEL, [](const NetObjPtr& o, cereal::PortableBinaryOutputArchive& a) { + oLock.send_server_update_to_all_clients(RELIABLE_COMMAND_CHANNEL, [](const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a) { a(*o); }); } @@ -81,26 +88,29 @@ namespace NetworkingObjects { auto& [netID, updatingObjData] = *it; updatingObjData.lastUpdateTimePoint = std::chrono::steady_clock::now(); *std::static_pointer_cast(updatingObjs[o.get_net_id()].objToUpdateCurrentData) = *o; + *updatingObjData.doLastAssignment = false; } } - template void server_read_update_func(const NetObjPtr& o, cereal::PortableBinaryInputArchive& a) { + template void server_read_update_func(const NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a) { auto it = updatingObjs.find(o.get_net_id()); bool finalUpdate; if(it == updatingObjs.end()) { a(finalUpdate, *o); - o.send_server_update_to_all_clients(finalUpdate ? RELIABLE_COMMAND_CHANNEL : UNRELIABLE_COMMAND_CHANNEL, [](const NetObjPtr& o, cereal::PortableBinaryOutputArchive& a) { + o.send_server_update_to_all_clients(finalUpdate ? RELIABLE_COMMAND_CHANNEL : UNRELIABLE_COMMAND_CHANNEL, [](const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a) { a(*o); }); } else { auto& [netID, updatingObjData] = *it; a(finalUpdate, *std::static_pointer_cast(updatingObjData.objToUpdateCurrentData)); + *updatingObjData.doLastAssignment = true; } } struct UpdatingObject { std::shared_ptr objToUpdateCurrentData; + std::shared_ptr doLastAssignment; std::chrono::steady_clock::time_point lastUpdateTimePoint; std::function setDataAfterTimeout; }; diff --git a/include/Helpers/NetworkingObjects/NetObjGenericSerializedClass.hpp b/include/Helpers/NetworkingObjects/NetObjGenericSerializedClass.hpp index 5c12b93..3fbc143 100644 --- a/include/Helpers/NetworkingObjects/NetObjGenericSerializedClass.hpp +++ b/include/Helpers/NetworkingObjects/NetObjGenericSerializedClass.hpp @@ -1,34 +1,38 @@ #pragma once -#include "NetObjPtr.hpp" +#include "NetObjTemporaryPtr.hpp" #include "cereal/archives/portable_binary.hpp" #include namespace NetworkingObjects { - template void default_serialize_write_func(const NetObjPtr& o, cereal::PortableBinaryOutputArchive& a) { + template void default_serialize_write_func(const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a) { a(*o); } - template void default_serialize_read_func(const NetObjPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&) { + template void default_serialize_read_func_client(const NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&) { + a(*o); + } + + template void default_serialize_read_constructor_func(NetObjManager*, const std::shared_ptr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&) { a(*o); } template void register_generic_serialized_class(NetObjManagerTypeList& t) { t.register_class({ .writeConstructorFuncClient = default_serialize_write_func, - .readConstructorFuncClient = default_serialize_read_func, - .readUpdateFuncClient = default_serialize_read_func, + .readConstructorFuncClient = default_serialize_read_constructor_func, + .readUpdateFuncClient = default_serialize_read_func_client, .writeConstructorFuncServer = default_serialize_write_func, - .readConstructorFuncServer = default_serialize_read_func, - .readUpdateFuncServer = [](const NetObjPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&) { + .readConstructorFuncServer = default_serialize_read_constructor_func, + .readUpdateFuncServer = [](const NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&) { a(*o); - o.send_server_update_to_all_clients(RELIABLE_COMMAND_CHANNEL, [](const NetObjPtr& o, cereal::PortableBinaryOutputArchive& a) { + o.send_server_update_to_all_clients(RELIABLE_COMMAND_CHANNEL, [](const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a) { a(*o); }); }, }); } - template void generic_serialized_class_send_update_to_all(const NetworkingObjects::NetObjPtr& o) { + template void generic_serialized_class_send_update_to_all(const NetworkingObjects::NetObjTemporaryPtr& o) { o.send_update_to_all(RELIABLE_COMMAND_CHANNEL, default_serialize_write_func); } } diff --git a/include/Helpers/NetworkingObjects/NetObjManager.cpp b/include/Helpers/NetworkingObjects/NetObjManager.cpp index ea38ec2..24390d1 100644 --- a/include/Helpers/NetworkingObjects/NetObjManager.cpp +++ b/include/Helpers/NetworkingObjects/NetObjManager.cpp @@ -1,5 +1,5 @@ #include "NetObjManager.hpp" -#include "NetObjPtr.hpp" +#include "NetObjTemporaryPtr.hpp" namespace NetworkingObjects { NetObjManager::NetObjManager(std::shared_ptr initTypeList, bool initIsServer): @@ -16,7 +16,7 @@ namespace NetworkingObjects { auto it = objectData.find(id); if(it == objectData.end()) return; - typeList->get_net_type_data(isServer, it->second.netTypeID).readUpdateFunc(NetObjPtr(this, id, it->second.p), a, clientReceivedFrom); + typeList->get_net_type_data(isServer, it->second.netTypeID).readUpdateFunc(NetObjTemporaryPtr(this, id, it->second.p), a, clientReceivedFrom); } void NetObjManager::set_client(std::shared_ptr initClient, MessageCommandType initUpdateCommandID) { client = initClient; diff --git a/include/Helpers/NetworkingObjects/NetObjManager.hpp b/include/Helpers/NetworkingObjects/NetObjManager.hpp index abe9a0e..a92f6c4 100644 --- a/include/Helpers/NetworkingObjects/NetObjManager.hpp +++ b/include/Helpers/NetworkingObjects/NetObjManager.hpp @@ -12,7 +12,8 @@ #include "../Networking/NetLibrary.hpp" #include "Helpers/NetworkingObjects/NetObjID.hpp" #include "NetObjManagerTypeList.hpp" -#include "NetObjPtr.decl.hpp" +#include "NetObjOwnerPtr.decl.hpp" +#include "NetObjTemporaryPtr.decl.hpp" #include "../Networking/NetServer.hpp" namespace NetworkingObjects { @@ -23,14 +24,17 @@ namespace NetworkingObjects { 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) { + template NetObjOwnerPtr read_create_message(cereal::PortableBinaryInputArchive& a, const std::shared_ptr& clientReceivedFrom) { NetObjID id; a(id); - NetObjPtr newPtr = make_obj_with_id_might_already_exist(id); - typeList->get_type_index_data(isServer).readConstructorFunc(newPtr.template cast(), a, clientReceivedFrom); + auto it = objectData.find(id); + if(it != objectData.end()) + throw std::runtime_error("[NetObjManager::read_create_message] Attempted to create an object with a used ID"); + NetObjOwnerPtr newPtr = emplace_raw_ptr(id, typeList->get_type_index_data(isServer).allocatorFunc()); + typeList->get_type_index_data(isServer).readConstructorFunc(newPtr, a, clientReceivedFrom); return newPtr; } - template NetObjPtr read_get_obj_from_message(cereal::PortableBinaryInputArchive& a) { + template NetObjTemporaryPtr read_get_obj_ref_from_message(cereal::PortableBinaryInputArchive& a) { NetObjID id; a(id); auto it = objectData.find(id); @@ -38,42 +42,96 @@ namespace NetworkingObjects { return NetObjPtr(); return NetObjPtr(this, id, std::static_pointer_cast(it->second.p)); } - template NetObjPtr make_obj() { - return emplace_shared_ptr(NetObjID::random_gen(), std::static_pointer_cast(typeList->get_type_index_data(isServer).allocatorFunc())); + template NetObjOwnerPtr make_obj() { + return emplace_raw_ptr(NetObjID::random_gen(), typeList->get_type_index_data(isServer).allocatorFunc()); } // Don't use this function unless you're sure that class T isn't a base class - template NetObjPtr make_obj_direct(Args&&... items) { - return emplace_shared_ptr(NetObjID::random_gen(), std::make_shared(items...)); + template NetObjOwnerPtr make_obj_direct(Args&&... items) { + return emplace_raw_ptr(NetObjID::random_gen(), new T(items...)); } - template NetObjPtr obj_from_ptr(T* p) { - return emplace_shared_ptr(NetObjID::random_gen(), std::shared_ptr(p)); + template NetObjOwnerPtr obj_from_ptr(T* p) { + return emplace_raw_ptr(NetObjID::random_gen(), p); } - template NetObjPtr get_obj_from_id(NetObjID id) { + template NetObjOwnerPtr get_obj_ref_from_id(NetObjID id) { auto it = objectData.find(id); if(it == objectData.end()) throw std::runtime_error("[NetObjManager::get_obj_from_id] ID doesn't exist"); return NetObjPtr(this, id, std::static_pointer_cast(it->second.p)); } private: - template NetObjPtr make_obj_with_id_might_already_exist(NetObjID id) { - auto alreadyExistsIt = objectData.find(id); - if(alreadyExistsIt != objectData.end()) - return NetObjPtr(this, id, std::static_pointer_cast(alreadyExistsIt->second.p)); - return emplace_shared_ptr(id, std::static_pointer_cast(typeList->get_type_index_data(isServer).allocatorFunc())); + template NetObjOwnerPtr emplace_raw_ptr(NetObjID id, T* rawPtr) { + if(!objectData.emplace(id, SingleObjectData{.netTypeID = typeList->get_type_index_data(isServer).netTypeID, .p = rawPtr}).second) + throw std::runtime_error("[NetObjManager::emplace_raw_ptr] ID Collision"); + return NetObjOwnerPtr(this, id, rawPtr); } - template NetObjPtr emplace_shared_ptr(NetObjID id, const std::shared_ptr& sharedPtr) { - if(!objectData.emplace(id, SingleObjectData{.netTypeID = typeList->get_type_index_data(isServer).netTypeID, .p = std::static_pointer_cast(sharedPtr)}).second) - throw std::runtime_error("[NetObjManager::emplace_shared_ptr] ID Collision"); - return NetObjPtr(this, id, sharedPtr); + template static void send_update_to_all(const NetObjTemporaryPtr& ptr, const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) { + if(ptr.get_obj_man()->isServer) + NetObjManager::send_server_update_to_all_clients(ptr, channel, sendUpdateFunc); + else + NetObjManager::send_client_update(ptr, channel, sendUpdateFunc); } - template friend class NetObjPtr; + template static void send_client_update(const NetObjTemporaryPtr& ptr, const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) { + if(ptr.get_obj_man()->client && !ptr.get_obj_man()->client->is_disconnected()) { + auto ss(std::make_shared()); + { + cereal::PortableBinaryOutputArchive m(*ss); + m(ptr.get_obj_man()->updateCommandID, ptr.get_net_id()); + sendUpdateFunc(ptr, m); + } + ptr.get_obj_man()->client->send_string_stream_to_server(channel, ss); + } + } + + template static void send_server_update_to_client(const NetObjTemporaryPtr& ptr, const std::shared_ptr& clientToSendTo, const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) { + if(ptr.get_obj_man()->server && !ptr.get_obj_man()->server->is_disconnected()) { + auto ss(std::make_shared()); + { + cereal::PortableBinaryOutputArchive m(*ss); + m(ptr.get_obj_man()->updateCommandID, ptr.get_net_id()); + sendUpdateFunc(ptr, m); + } + ptr.get_obj_man()->server->send_string_stream_to_client(clientToSendTo, channel, ss); + } + } + + template static void send_server_update_to_all_clients_except(const NetObjTemporaryPtr& ptr, const std::shared_ptr& clientToNotSendTo, const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) { + if(ptr.get_obj_man()->server && !ptr.get_obj_man()->server->is_disconnected()) { + auto ss(std::make_shared()); + { + cereal::PortableBinaryOutputArchive m(*ss); + m(ptr.get_obj_man()->updateCommandID, ptr.get_net_id()); + sendUpdateFunc(ptr, m); + } + ptr.get_obj_man()->server->send_string_stream_to_all_clients_except(clientToNotSendTo, channel, ss); + } + } + + template static void send_server_update_to_all_clients(const NetObjTemporaryPtr& ptr, const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) { + if(ptr.get_obj_man()->server && !ptr.get_obj_man()->server->is_disconnected()) { + auto ss(std::make_shared()); + { + cereal::PortableBinaryOutputArchive m(*ss); + m(ptr.get_obj_man()->updateCommandID, ptr.get_net_id()); + sendUpdateFunc(ptr, m); + } + ptr.get_obj_man()->server->send_string_stream_to_all_clients(channel, ss); + } + } + + template static void write_create_message(const NetObjTemporaryPtr& ptr, cereal::PortableBinaryOutputArchive& a) { + a(ptr.get_obj_man()->id); + ptr.get_obj_man()->typeList->template get_type_index_data(ptr.get_obj_man()->isServer).writeConstructorFunc(ptr, a); + } + + template friend class NetObjOwnerPtr; + template friend class NetObjTemporaryPtr; template friend class NetObjWeakPtr; struct SingleObjectData { NetTypeIDType netTypeID; - std::shared_ptr p; + void* p; }; bool isServer; diff --git a/include/Helpers/NetworkingObjects/NetObjManagerTypeList.hpp b/include/Helpers/NetworkingObjects/NetObjManagerTypeList.hpp index 9f47fe4..ca98bfb 100644 --- a/include/Helpers/NetworkingObjects/NetObjManagerTypeList.hpp +++ b/include/Helpers/NetworkingObjects/NetObjManagerTypeList.hpp @@ -1,7 +1,7 @@ #pragma once #include "../Networking/NetLibrary.hpp" #include -#include "NetObjPtr.decl.hpp" +#include "NetObjTemporaryPtr.decl.hpp" #include "../Networking/NetServer.hpp" namespace NetworkingObjects { @@ -9,48 +9,48 @@ namespace NetworkingObjects { class NetObjManagerTypeList { public: template struct ServerClientClassFunctions { - std::function&, cereal::PortableBinaryOutputArchive&)> writeConstructorFuncClient; - std::function&, cereal::PortableBinaryInputArchive&, const std::shared_ptr&)> readConstructorFuncClient; - std::function&, cereal::PortableBinaryInputArchive&, const std::shared_ptr&)> readUpdateFuncClient; + std::function&, cereal::PortableBinaryOutputArchive&)> writeConstructorFuncClient; + std::function&, 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&, cereal::PortableBinaryInputArchive&, const std::shared_ptr&)> readUpdateFuncServer; + std::function&, cereal::PortableBinaryOutputArchive&)> writeConstructorFuncServer; + std::function&, cereal::PortableBinaryInputArchive&, const std::shared_ptr&)> readConstructorFuncServer; + std::function&, cereal::PortableBinaryInputArchive&, const std::shared_ptr&)> readUpdateFuncServer; }; template void register_class(const ServerClientClassFunctions& funcs) { typeIndexFunctionsClient[std::type_index(typeid(ClientT*))] = TypeIndexFunctions { - .readConstructorFunc = [f = funcs.readConstructorFuncClient](const NetObjPtr& obj, cereal::PortableBinaryInputArchive& message, const std::shared_ptr& c) { + .readConstructorFunc = [f = funcs.readConstructorFuncClient](const NetObjTemporaryPtr& obj, cereal::PortableBinaryInputArchive& message, const std::shared_ptr& c) { if(f) f(obj.cast(), message, c); }, - .writeConstructorFunc = [f = funcs.writeConstructorFuncClient](const NetObjPtr& obj, cereal::PortableBinaryOutputArchive& message) { + .writeConstructorFunc = [f = funcs.writeConstructorFuncClient](const NetObjTemporaryPtr& obj, cereal::PortableBinaryOutputArchive& message) { f(obj.cast(), message); }, - .allocatorFunc = []() { return std::make_shared(); }, + .allocatorFunc = []() { return static_cast(new ClientAllocatedType); }, .netTypeID = netTypeID }; typeIndexFunctionsServer[std::type_index(typeid(ServerT*))] = TypeIndexFunctions { - .readConstructorFunc = [f = funcs.readConstructorFuncServer](const NetObjPtr& obj, cereal::PortableBinaryInputArchive& message, const std::shared_ptr& c) { + .readConstructorFunc = [f = funcs.readConstructorFuncServer](const NetObjTemporaryPtr& obj, cereal::PortableBinaryInputArchive& message, const std::shared_ptr& c) { if(f) f(obj.cast(), message, c); }, - .writeConstructorFunc = [f = funcs.writeConstructorFuncServer](const NetObjPtr& obj, cereal::PortableBinaryOutputArchive& message) { + .writeConstructorFunc = [f = funcs.writeConstructorFuncServer](const NetObjTemporaryPtr& obj, cereal::PortableBinaryOutputArchive& message) { f(obj.cast(), message); }, - .allocatorFunc = []() { return std::make_shared(); }, + .allocatorFunc = []() { return static_cast(new ServerAllocatedType); }, .netTypeID = netTypeID }; netTypeIDFunctionsClient[netTypeID] = NetTypeIDFunctions { - .readUpdateFunc = [f = funcs.readUpdateFuncClient](const NetObjPtr& obj, cereal::PortableBinaryInputArchive& message, const std::shared_ptr& c) { + .readUpdateFunc = [f = funcs.readUpdateFuncClient](const NetObjTemporaryPtr& obj, cereal::PortableBinaryInputArchive& message, const std::shared_ptr& c) { if(f) f(obj.cast(), message, c); } }; netTypeIDFunctionsServer[netTypeID] = NetTypeIDFunctions { - .readUpdateFunc = [f = funcs.readUpdateFuncServer](const NetObjPtr& obj, cereal::PortableBinaryInputArchive& message, const std::shared_ptr& c) { + .readUpdateFunc = [f = funcs.readUpdateFuncServer](const NetObjTemporaryPtr& obj, cereal::PortableBinaryInputArchive& message, const std::shared_ptr& c) { if(f) f(obj.cast(), message, c); } @@ -60,14 +60,14 @@ class NetObjManagerTypeList { } struct TypeIndexFunctions { - std::function&, cereal::PortableBinaryInputArchive&, const std::shared_ptr&)> readConstructorFunc; - std::function&, cereal::PortableBinaryOutputArchive&)> writeConstructorFunc; - std::function()> allocatorFunc; + std::function&, cereal::PortableBinaryInputArchive&, const std::shared_ptr&)> readConstructorFunc; + std::function&, cereal::PortableBinaryOutputArchive&)> writeConstructorFunc; + std::function allocatorFunc; NetTypeIDType netTypeID; }; struct NetTypeIDFunctions { - std::function&, cereal::PortableBinaryInputArchive&, const std::shared_ptr&)> readUpdateFunc; + std::function&, cereal::PortableBinaryInputArchive&, const std::shared_ptr&)> readUpdateFunc; }; template const TypeIndexFunctions& get_type_index_data(bool isServer) { diff --git a/include/Helpers/NetworkingObjects/NetObjOrderedList.hpp b/include/Helpers/NetworkingObjects/NetObjOrderedList.hpp index 2b44b5a..dfdb2ca 100644 --- a/include/Helpers/NetworkingObjects/NetObjOrderedList.hpp +++ b/include/Helpers/NetworkingObjects/NetObjOrderedList.hpp @@ -1,13 +1,15 @@ #pragma once #include "Helpers/Networking/NetLibrary.hpp" -#include "NetObjPtr.hpp" +#include "NetObjOwnerPtr.hpp" +#include "NetObjTemporaryPtr.hpp" #include "NetObjID.hpp" #include "cereal/archives/portable_binary.hpp" #include "NetObjManagerTypeList.hpp" namespace NetworkingObjects { enum class ObjPtrOrderedListCommand_StoC : uint8_t { - INSERT_SINGLE, + INSERT_SINGLE_CONSTRUCT, + INSERT_SINGLE_REFERENCE, ERASE_SINGLE }; @@ -17,15 +19,13 @@ namespace NetworkingObjects { }; template struct NetObjOrderedListObjectInfo { - NetObjOrderedListObjectInfo(const NetObjPtr& iObj, uint32_t iPos, bool iSyncIgnore): - obj(iObj), - pos(iPos), - syncIgnore(iSyncIgnore) + NetObjOrderedListObjectInfo(NetObjOwnerPtr iObj, uint32_t iPos): + obj(std::move(iObj)), + pos(iPos) {} NetObjOrderedListObjectInfo() = delete; - NetObjPtr obj; + NetObjOwnerPtr obj; uint32_t pos; - bool syncIgnore; }; template using NetObjOrderedListObjectInfoPtr = std::shared_ptr>; @@ -39,44 +39,45 @@ namespace NetworkingObjects { template class NetObjOrderedList { public: // Don't use this function unless you're sure that class T isn't a base class - template NetObjPtr emplace_back_direct(const NetObjPtr>& l, Args&&... items) { - NetObjPtr newObj = l.get_obj_man()->template make_obj_direct(items...); - l->insert(l, l->size(), newObj); - return newObj; + template NetObjTemporaryPtr emplace_back_direct(const NetObjTemporaryPtr>& l, Args&&... items) { + NetObjOwnerPtr newObj = l.get_obj_man()->template make_obj_direct(items...); + NetObjTemporaryPtr tempPtr(newObj); + l->insert(l, nullptr, l->size(), std::move(newObj)); + return tempPtr; } - static void push_back_and_send_create(const NetObjPtr>& l, const NetObjPtr& newObj) { - l->insert(l, l->size(), newObj); + static void push_back_and_send_create(const NetObjTemporaryPtr>& l, T* newObj) { + l->insert(l, nullptr, l->size(), newObj); } - static void insert_and_send_create(const NetObjPtr>& l, uint32_t posToInsertAt, const NetObjPtr& newObj) { - l->insert(l, posToInsertAt, newObj); + static void insert_and_send_create(const NetObjTemporaryPtr>& l, uint32_t posToInsertAt, const NetObjTemporaryPtr& newObj) { + l->insert(l, nullptr, posToInsertAt, newObj); } - static NetObjPtr erase(const NetObjPtr>& l, uint32_t indexToErase) { + static void erase(const NetObjTemporaryPtr>& l, uint32_t indexToErase) { return l->erase_by_index(l, indexToErase); } - static uint32_t erase(const NetObjPtr>& l, const NetObjPtr& p) { + static uint32_t erase(const NetObjTemporaryPtr>& l, const NetObjTemporaryPtr& p) { return l->erase_by_ptr(l, p); } - virtual bool contains(const NetObjPtr& p) const = 0; + virtual bool contains(const NetObjTemporaryPtr& p) const = 0; virtual uint32_t size() const = 0; - virtual const NetObjPtr& at(uint32_t index) const = 0; + virtual const NetObjOwnerPtr& at(uint32_t index) const = 0; virtual bool empty() const = 0; virtual ~NetObjOrderedList() {} protected: - virtual void insert(const NetObjPtr>& l, uint32_t posToInsertAt, const NetObjPtr& newObj) = 0; - virtual NetObjPtr erase_by_index(const NetObjPtr>& l, uint32_t indexToErase) = 0; - virtual uint32_t erase_by_ptr(const NetObjPtr>& l, const NetObjPtr& 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 insert(const NetObjTemporaryPtr>& l, const std::shared_ptr& clientInserting, uint32_t posToInsertAt, NetObjOwnerPtr 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 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(NetObjManager* objMan, const std::shared_ptr>& 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) { + static void write_constructor_func(const NetObjTemporaryPtr>& 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) { + static void read_constructor_func(const NetObjTemporaryPtr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr& c) { l->read_constructor(l, a, c); } - static void read_update_func(const NetObjPtr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr& c) { + static void read_update_func(const NetObjTemporaryPtr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr& c) { l->read_update(l, a, c); } }; @@ -84,62 +85,46 @@ namespace NetworkingObjects { template class NetObjOrderedListServer : public NetObjOrderedList { public: NetObjOrderedListServer() {} - virtual bool contains(const NetObjPtr& p) const override { + virtual bool contains(const NetObjTemporaryPtr& p) const override { return idToDataMap.contains(p.get_net_id()); } virtual uint32_t size() const override { return data.size(); } - virtual const NetObjPtr& at(uint32_t index) const override { + virtual const NetObjOwnerPtr& at(uint32_t index) const override { return data[index]->obj; } virtual bool empty() const override { return data.empty(); } protected: - virtual void insert(const NetObjPtr>& l, uint32_t posToInsertAt, const NetObjPtr& newObj) override { - uint32_t actualPosToInsertAt = posToInsertAt = std::min(posToInsertAt, data.size()); - - // Find duplicate. If found, erase the duplicate before inserting - std::shared_ptr> 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); - 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>(newObj, 0, 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>&, 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 + virtual void insert(const NetObjTemporaryPtr>& l, const std::shared_ptr& clientInserting, uint32_t posToInsertAt, NetObjOwnerPtr newObj) override { + posToInsertAt = std::min(posToInsertAt, 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); + l.send_server_update_to_all_clients_except(clientInserting, RELIABLE_COMMAND_CHANNEL, [&newObjInfoPtr, posToInsertAt](const NetObjTemporaryPtr>&, cereal::PortableBinaryOutputArchive& a) { + a(ObjPtrOrderedListCommand_StoC::INSERT_SINGLE_CONSTRUCT, posToInsertAt); newObjInfoPtr->obj.write_create_message(a); }); - set_positions_for_object_info_vector(data, actualPosToInsertAt); + l.send_server_update_to_client(clientInserting, RELIABLE_COMMAND_CHANNEL, [&newObjInfoPtr, posToInsertAt](const NetObjTemporaryPtr>&, cereal::PortableBinaryOutputArchive& a) { + a(ObjPtrOrderedListCommand_StoC::INSERT_SINGLE_REFERENCE, posToInsertAt, newObjInfoPtr->obj.get_net_id()); + }); + set_positions_for_object_info_vector(data, posToInsertAt); } - virtual NetObjPtr erase_by_index(const NetObjPtr>& l, uint32_t indexToErase) override { + virtual void erase_by_index(const NetObjTemporaryPtr>& l, uint32_t indexToErase) override { if(data.empty()) - return {}; + return; indexToErase = std::min(indexToErase, data.size() - 1); - l.send_server_update_to_all_clients(RELIABLE_COMMAND_CHANNEL, [indexToErase](const NetObjPtr>&, cereal::PortableBinaryOutputArchive& a) { + l.send_server_update_to_all_clients(RELIABLE_COMMAND_CHANNEL, [indexToErase](const NetObjTemporaryPtr>&, cereal::PortableBinaryOutputArchive& a) { a(ObjPtrOrderedListCommand_StoC::ERASE_SINGLE, indexToErase); }); NetObjID idToErase = data[indexToErase]->obj.get_net_id(); - NetObjPtr toRet = data[indexToErase]->obj; data.erase(data.begin() + indexToErase); idToDataMap.erase(idToErase); set_positions_for_object_info_vector(data, indexToErase); - return toRet; } - virtual uint32_t erase_by_ptr(const NetObjPtr>& l, const NetObjPtr& p) override { + virtual uint32_t erase_by_ptr(const NetObjTemporaryPtr>& l, const NetObjTemporaryPtr& p) override { if(data.empty()) return std::numeric_limits::max(); auto it = idToDataMap.find(p.get_net_id()); @@ -148,37 +133,37 @@ namespace NetworkingObjects { uint32_t indexToErase = it->second->pos; data.erase(data.begin() + indexToErase); idToDataMap.erase(it); - l.send_server_update_to_all_clients(RELIABLE_COMMAND_CHANNEL, [indexToErase](const NetObjPtr>&, cereal::PortableBinaryOutputArchive& a) { + l.send_server_update_to_all_clients(RELIABLE_COMMAND_CHANNEL, [indexToErase](const NetObjTemporaryPtr>&, cereal::PortableBinaryOutputArchive& a) { a(ObjPtrOrderedListCommand_StoC::ERASE_SINGLE, indexToErase); }); set_positions_for_object_info_vector(data, indexToErase); return indexToErase; } - virtual void write_constructor(const NetObjPtr>& l, cereal::PortableBinaryOutputArchive& a) override { + 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++) data[i]->obj.write_create_message(a); } - virtual void read_constructor(const NetObjPtr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr& c) override { + virtual void read_constructor(NetObjManager* objMan, const std::shared_ptr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr& c) override { uint32_t constructedSize; a(constructedSize); data.clear(); idToDataMap.clear(); for(uint32_t i = 0; i < constructedSize; i++) { - data.emplace_back(std::make_shared>(l.get_obj_man()->template read_create_message(a, c), static_cast(data.size()), false)); + data.emplace_back(std::make_shared>(objMan->template read_create_message(a, c), static_cast(data.size()))); idToDataMap.emplace(data.back()->obj.get_net_id(), data.back()); } // 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 // Example: the INSERT_SINGLE command in read_update, if it was inserting another NetObjOrderedList, would first construct the list using read_create_message, then it will call insert() to send it to clients } - virtual void read_update(const NetObjPtr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr& c) override { + virtual void read_update(const NetObjTemporaryPtr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr& c) override { ObjPtrOrderedListCommand_CtoS command; a(command); switch(command) { case ObjPtrOrderedListCommand_CtoS::INSERT_SINGLE: uint32_t newPos; a(newPos); - insert(l, newPos, l.get_obj_man()->template read_create_message(a, c)); + insert(l, c, newPos, l.get_obj_man()->template read_create_message(a, c)); break; case ObjPtrOrderedListCommand_CtoS::ERASE_SINGLE: NetObjID idToErase; @@ -197,75 +182,51 @@ namespace NetworkingObjects { template class NetObjOrderedListClient : public NetObjOrderedList { public: NetObjOrderedListClient() {} - virtual bool contains(const NetObjPtr& p) const override { + virtual bool contains(const NetObjTemporaryPtr& p) const override { return clientIdToDataMap.contains(p.get_net_id()); } virtual uint32_t size() const override { return clientData.size(); } - virtual const NetObjPtr& at(uint32_t index) const override { + virtual const NetObjOwnerPtr& at(uint32_t index) const override { return clientData[index]->obj; } virtual bool empty() const override { return clientData.empty(); } protected: - virtual void insert(const NetObjPtr>& l, uint32_t posToInsertAt, const NetObjPtr& newObj) { - uint32_t actualPosToInsertAt = posToInsertAt = std::min(posToInsertAt, clientData.size()); - - NetObjOrderedListObjectInfoPtr 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); - 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>(newObj, 0, true); - 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>&, cereal::PortableBinaryOutputArchive& a) { + virtual void insert(const NetObjTemporaryPtr>& l, const std::shared_ptr&, uint32_t posToInsertAt, NetObjOwnerPtr newObj) { + posToInsertAt = std::min(posToInsertAt, 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); + l.send_client_update(RELIABLE_COMMAND_CHANNEL, [&newObjInfoPtr, posToInsertAt](const NetObjTemporaryPtr>&, 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); }); - set_positions_for_object_info_vector(clientData, actualPosToInsertAt); + set_positions_for_object_info_vector(clientData, posToInsertAt); } - virtual NetObjPtr erase_by_index(const NetObjPtr>& l, uint32_t indexToErase) override { + virtual void erase_by_index(const NetObjTemporaryPtr>& l, uint32_t indexToErase) override { if(clientData.empty()) - return {}; + return; indexToErase = std::min(indexToErase, clientData.size() - 1); auto p = clientData[indexToErase]; - l.send_client_update(RELIABLE_COMMAND_CHANNEL, [&p](const NetObjPtr>&, cereal::PortableBinaryOutputArchive& a) { + l.send_client_update(RELIABLE_COMMAND_CHANNEL, [&p](const NetObjTemporaryPtr>&, cereal::PortableBinaryOutputArchive& a) { a(ObjPtrOrderedListCommand_CtoS::ERASE_SINGLE, p->obj.get_net_id()); }); - p->syncIgnore = true; uint32_t iToErase = p->pos; clientIdToDataMap.erase(p->obj.get_net_id()); clientData.erase(clientData.begin() + iToErase); set_positions_for_object_info_vector(clientData, iToErase); - return p->obj; } - virtual uint32_t erase_by_ptr(const NetObjPtr>& l, const NetObjPtr& p) override { + virtual uint32_t erase_by_ptr(const NetObjTemporaryPtr>& l, const NetObjTemporaryPtr& p) override { if(clientData.empty()) return std::numeric_limits::max(); - auto it = clientIdToDataMap.find(p.get_net_id()); - if(it == clientIdToDataMap.end()) - return std::numeric_limits::max(); - l.send_client_update(RELIABLE_COMMAND_CHANNEL, [&p](const NetObjPtr>&, cereal::PortableBinaryOutputArchive& a) { + l.send_client_update(RELIABLE_COMMAND_CHANNEL, [&p](const NetObjTemporaryPtr>&, cereal::PortableBinaryOutputArchive& a) { a(ObjPtrOrderedListCommand_CtoS::ERASE_SINGLE, p.get_net_id()); }); - it->second->syncIgnore = true; + auto it = clientIdToDataMap.find(p.get_net_id()); uint32_t iToErase = it->second->pos; auto toRet = clientData[iToErase]; clientIdToDataMap.erase(it); @@ -273,104 +234,96 @@ namespace NetworkingObjects { set_positions_for_object_info_vector(clientData, iToErase); return iToErase; } - virtual void write_constructor(const NetObjPtr>& l, cereal::PortableBinaryOutputArchive& a) override { + 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++) clientData[i]->obj.write_create_message(a); } - virtual void read_constructor(const NetObjPtr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&) override { + virtual void read_constructor(NetObjManager* objMan, const std::shared_ptr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&) override { uint32_t constructedSize; a(constructedSize); clientData.clear(); serverData.clear(); - serverIdToDataMap.clear(); clientIdToDataMap.clear(); for(uint32_t i = 0; i < constructedSize; i++) { - serverData.emplace_back(std::make_shared>(l.get_obj_man()->template read_create_message(a, nullptr), static_cast(serverData.size()), false)); - serverIdToDataMap.emplace(serverData.back()->obj.get_net_id(), serverData.back()); + clientData.emplace_back(std::make_shared>(objMan->template read_create_message(a, nullptr), static_cast(serverData.size()))); + clientIdToDataMap.emplace_back(clientData.back()->obj.get_net_id(), serverData.back()); + serverData.emplace_back(clientData.back()->obj.get_net_id()); } - clientData = serverData; - clientIdToDataMap = serverIdToDataMap; } - virtual void read_update(const NetObjPtr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&) override { + virtual void read_update(const NetObjTemporaryPtr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&) override { ObjPtrOrderedListCommand_StoC c; a(c); switch(c) { - case ObjPtrOrderedListCommand_StoC::INSERT_SINGLE: { + case ObjPtrOrderedListCommand_StoC::INSERT_SINGLE_REFERENCE: { + NetObjID newObjID; + uint32_t newServerPos; + a(newServerPos, newObjID); + serverData.insert(serverData.begin() + newServerPos, newObjID); + clientJustInsertedSyncIgnore.erase(newObjID); + sync(); + break; + } + case ObjPtrOrderedListCommand_StoC::INSERT_SINGLE_CONSTRUCT: { uint32_t newServerPos; a(newServerPos); - auto objToInsert = l.get_obj_man()->template read_create_message(a, nullptr); - auto it = serverIdToDataMap.find(objToInsert.get_net_id()); - if(it != serverIdToDataMap.end()) { - uint32_t serverPosErased = std::numeric_limits::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::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 objInfoToInsert; - auto clientIt = clientIdToDataMap.find(objToInsert.get_net_id()); - if(clientIt != clientIdToDataMap.end()) - objInfoToInsert = clientIt->second; - else - objInfoToInsert = std::make_shared>(objToInsert, 0, false); - objInfoToInsert->syncIgnore = false; - serverData.insert(serverData.begin() + newServerPos, objInfoToInsert); - serverIdToDataMap.emplace(objInfoToInsert->obj.get_net_id(), objInfoToInsert); - } + 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()); + sync(); break; } case ObjPtrOrderedListCommand_StoC::ERASE_SINGLE: { uint32_t serverPosToErase; a(serverPosToErase); - NetObjID objID = serverData[serverPosToErase]->obj.get_net_id(); + NetObjID objID = serverData[serverPosToErase]; serverData.erase(serverData.begin() + serverPosToErase); - serverIdToDataMap.erase(objID); + auto it = clientIdToDataMap.find(objID); + if(it != clientIdToDataMap.end()) { + uint32_t clientPosToErase = it->second->pos; + clientIdToDataMap.erase(it); + clientJustInsertedSyncIgnore.erase(objID); + clientData.erase(clientData.begin() + clientPosToErase); + set_positions_for_object_info_vector(clientData, clientPosToErase); + } break; } } - sync(); } private: + void sync(const std::unordered_map>& newServerObjects) { + std::map> ignoredToReinsert; + for(auto& [netID, objInfoPtr] : clientJustInsertedSyncIgnore) + ignoredToReinsert.emplace(objInfoPtr->pos, objInfoPtr); - void sync() { - std::vector>> ignoredToReinsert; - for(uint32_t i = 0; i < static_cast(clientData.size()); i++) - if(clientData[i]->syncIgnore) - ignoredToReinsert.emplace_back(std::pair>{i, clientData[i]}); - clientData = serverData; - clientIdToDataMap = serverIdToDataMap; - std::erase_if(clientData, [&](const auto& obj) { - if(obj->syncIgnore) { - clientIdToDataMap.erase(obj->obj.get_net_id()); - return true; + clientData.clear(); + for(const NetObjID& id : serverData) { + auto itFoundInClient = clientIdToDataMap.find(id); + if(itFoundInClient != clientIdToDataMap.end()) + clientData.emplace_back(itFoundInClient->second); + else { + auto itFoundInServer = newServerObjects.find(id); + if(itFoundInServer != newServerObjects.end()) { + clientData.emplace_back(itFoundInServer->second); + clientIdToDataMap.emplace(itFoundInServer->first, itFoundInServer->second); + } } - return false; - }); - for(auto& p : ignoredToReinsert) { - if(p.first > clientData.size()) - clientData.emplace_back(p.second); - else - clientData.insert(clientData.begin() + p.first, p.second); - clientIdToDataMap.emplace(p.second->obj.get_net_id(), p.second); } + + for(auto& [pos, objInfoPtr] : ignoredToReinsert) { + if(pos > clientData.size()) + clientData.emplace_back(objInfoPtr); + else + clientData.insert(clientData.begin() + pos, objInfoPtr); + } + set_positions_for_object_info_vector(clientData); } - std::vector> serverData; - std::unordered_map> serverIdToDataMap; - + std::vector serverData; std::vector> clientData; std::unordered_map> clientIdToDataMap; + std::unordered_map> clientJustInsertedSyncIgnore; }; template void register_ordered_list_class(NetObjManagerTypeList& t) { diff --git a/include/Helpers/NetworkingObjects/NetObjOwnerPtr.decl.hpp b/include/Helpers/NetworkingObjects/NetObjOwnerPtr.decl.hpp new file mode 100644 index 0000000..bcb3f52 --- /dev/null +++ b/include/Helpers/NetworkingObjects/NetObjOwnerPtr.decl.hpp @@ -0,0 +1,40 @@ +#pragma once +#include "NetObjID.hpp" +#include +#include +#include "../Networking/NetServer.hpp" + +namespace NetworkingObjects { + class NetObjManager; + template class NetObjTemporaryPtr; + template class NetObjOwnerPtr { + public: + NetObjOwnerPtr(); + NetObjOwnerPtr(const NetObjOwnerPtr& other) = delete; + NetObjOwnerPtr(NetObjOwnerPtr&& other); + NetObjOwnerPtr& operator=(const NetObjOwnerPtr& other) = delete; + NetObjOwnerPtr& operator=(NetObjOwnerPtr&& other); + ~NetObjOwnerPtr(); + NetObjManager* get_obj_man() const; + NetObjID get_net_id() const; + T* get() const; + std::add_lvalue_reference_t operator*() const requires(!std::is_void_v); + T* operator->() const; + operator bool() const; + std::strong_ordering operator<=>(const NetObjOwnerPtr& rhs) const; + void send_client_update(const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) const; + void send_server_update_to_client(const std::shared_ptr& clientToSendTo, const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) const; + void send_server_update_to_all_clients_except(const std::shared_ptr& clientToNotSendTo, const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) const; + void send_server_update_to_all_clients(const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) const; + void send_update_to_all(const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) const; + void write_create_message(cereal::PortableBinaryOutputArchive& a) const; + private: + friend class NetObjManager; + template friend class NetObjTemporaryPtr; + + NetObjOwnerPtr(NetObjManager* initObjMan, NetObjID initID, T* initRawPtr); + NetObjManager* objMan; + NetObjID id; + T* rawPtr; + }; +} diff --git a/include/Helpers/NetworkingObjects/NetObjOwnerPtr.hpp b/include/Helpers/NetworkingObjects/NetObjOwnerPtr.hpp new file mode 100644 index 0000000..c4aab5d --- /dev/null +++ b/include/Helpers/NetworkingObjects/NetObjOwnerPtr.hpp @@ -0,0 +1,3 @@ +#pragma once +#include "NetObjOwnerPtr.decl.hpp" +#include "NetObjOwnerPtr.impl.hpp" diff --git a/include/Helpers/NetworkingObjects/NetObjOwnerPtr.impl.hpp b/include/Helpers/NetworkingObjects/NetObjOwnerPtr.impl.hpp new file mode 100644 index 0000000..2c1e5d2 --- /dev/null +++ b/include/Helpers/NetworkingObjects/NetObjOwnerPtr.impl.hpp @@ -0,0 +1,99 @@ +#pragma once +#include +#include +#include +#include +#include +#include "NetObjOwnerPtr.decl.hpp" +#include "NetObjTemporaryPtr.hpp" +#include "NetObjManager.hpp" +#include "NetObjManagerTypeList.hpp" + +namespace NetworkingObjects { + template NetObjOwnerPtr::NetObjOwnerPtr(): + objMan(nullptr), + rawPtr(nullptr) + {} + + template NetObjOwnerPtr::NetObjOwnerPtr(NetObjOwnerPtr&& other): + objMan(other.objMan), + id(other.id), + rawPtr(other.rawPtr) + { + other.objMan = nullptr; + other.rawPtr = nullptr; + } + + template NetObjOwnerPtr& NetObjOwnerPtr::operator=(NetObjOwnerPtr&& other) { + objMan = other.objMan; + id = other.id; + rawPtr = other.rawPtr; + other.objMan = nullptr; + other.rawPtr = nullptr; + } + + template NetObjOwnerPtr::~NetObjOwnerPtr() { + if(objMan && rawPtr) { + auto it = objMan->objectData.find(id); + delete static_cast(it->second.p); + objMan->objectData.erase(it); + } + } + + template NetObjManager* NetObjOwnerPtr::get_obj_man() const { + return objMan; + } + + template NetObjID NetObjOwnerPtr::get_net_id() const { + return id; + } + + template T* NetObjOwnerPtr::get() const { + return rawPtr; + } + + template std::add_lvalue_reference_t NetObjOwnerPtr::operator*() const requires(!std::is_void_v) { + return *rawPtr; + } + + template T* NetObjOwnerPtr::operator->() const { + return rawPtr; + } + + template NetObjOwnerPtr::operator bool() const { + return rawPtr; + } + + template std::strong_ordering NetObjOwnerPtr::operator<=>(const NetObjOwnerPtr& rhs) const { + return rawPtr <=> rhs.rawPtr; + } + + template void NetObjOwnerPtr::send_client_update(const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) const { + NetObjManager::send_client_update(*this, channel, sendUpdateFunc); + } + + template void NetObjOwnerPtr::send_server_update_to_all_clients(const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) const { + NetObjManager::send_server_update_to_all_clients(*this, channel, sendUpdateFunc); + } + + template void NetObjOwnerPtr::send_server_update_to_client(const std::shared_ptr& clientToSendTo, const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) const { + NetObjManager::send_server_update_to_client(*this, clientToSendTo, channel, sendUpdateFunc); + } + template void NetObjOwnerPtr::send_server_update_to_all_clients_except(const std::shared_ptr& clientToNotSendTo, const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) const { + NetObjManager::send_server_update_to_all_clients_except(*this, clientToNotSendTo, channel, sendUpdateFunc); + } + + template void NetObjOwnerPtr::send_update_to_all(const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) const { + NetObjManager::send_update_to_all(*this, channel, sendUpdateFunc); + } + + template void NetObjOwnerPtr::write_create_message(cereal::PortableBinaryOutputArchive& a) const { + NetObjManager::write_create_message(*this, a); + } + + template NetObjOwnerPtr::NetObjOwnerPtr(NetObjManager* initObjMan, NetObjID initID, T* initRawPtr): + objMan(initObjMan), + id(initID), + rawPtr(initRawPtr) + {} +} diff --git a/include/Helpers/NetworkingObjects/NetObjPtr.decl.hpp b/include/Helpers/NetworkingObjects/NetObjPtr.decl.hpp deleted file mode 100644 index f999063..0000000 --- a/include/Helpers/NetworkingObjects/NetObjPtr.decl.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once -#include "NetObjID.hpp" -#include -#include - -namespace NetworkingObjects { - class NetObjManager; - template class NetObjPtr { - public: - NetObjPtr(); - NetObjPtr(const NetObjPtr& other); - NetObjPtr& operator=(const NetObjPtr& other); - ~NetObjPtr(); - template NetObjPtr cast() const; - NetObjManager* get_obj_man() const; - NetObjID get_net_id() const; - T* get() const; - std::add_lvalue_reference_t operator*() const requires(!std::is_void_v); - T* operator->() const; - operator bool() const; - std::strong_ordering operator<=>(const NetObjPtr& rhs) const; - void send_client_update(const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) const; - void send_server_update_to_all_clients(const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) const; - void send_update_to_all(const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) const; - void write_create_message(cereal::PortableBinaryOutputArchive& a) const; - private: - friend class NetObjManager; - template friend class NetObjPtr; - template friend class NetObjWeakPtr; - - NetObjPtr(NetObjManager* initObjMan, NetObjID initID, const std::shared_ptr& initPtr); - NetObjManager* objMan; - NetObjID id; - std::shared_ptr sharedPtr; - }; -} diff --git a/include/Helpers/NetworkingObjects/NetObjPtr.hpp b/include/Helpers/NetworkingObjects/NetObjPtr.hpp deleted file mode 100644 index bc9aaf5..0000000 --- a/include/Helpers/NetworkingObjects/NetObjPtr.hpp +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once -#include "NetObjPtr.decl.hpp" -#include "NetObjPtr.impl.hpp" diff --git a/include/Helpers/NetworkingObjects/NetObjPtr.impl.hpp b/include/Helpers/NetworkingObjects/NetObjPtr.impl.hpp deleted file mode 100644 index 776229a..0000000 --- a/include/Helpers/NetworkingObjects/NetObjPtr.impl.hpp +++ /dev/null @@ -1,109 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include "NetObjPtr.decl.hpp" -#include "NetObjManager.hpp" -#include "NetObjManagerTypeList.hpp" - -namespace NetworkingObjects { - template NetObjPtr::NetObjPtr(): - objMan(nullptr), - sharedPtr(nullptr) - {} - template NetObjPtr::NetObjPtr(const NetObjPtr& other): - objMan(other.objMan), - id(other.id), - sharedPtr(other.sharedPtr) - {} - template NetObjPtr& NetObjPtr::operator=(const NetObjPtr& other) { - if(this != &other) { - if(sharedPtr && sharedPtr.use_count() == 2) - objMan->objectData.erase(id); - objMan = other.objMan; - id = other.id; - sharedPtr = other.sharedPtr; - } - return *this; - } - template NetObjPtr::~NetObjPtr() { - if(sharedPtr && sharedPtr.use_count() == 2) - objMan->objectData.erase(id); - } - - template template NetObjPtr NetObjPtr::cast() const { - return NetObjPtr(objMan, id, std::static_pointer_cast(sharedPtr)); - } - - template NetObjManager* NetObjPtr::get_obj_man() const { - return objMan; - } - - template NetObjID NetObjPtr::get_net_id() const { - return id; - } - - template T* NetObjPtr::get() const { - return sharedPtr.get(); - } - - template std::add_lvalue_reference_t NetObjPtr::operator*() const requires(!std::is_void_v) { - return *sharedPtr; - } - - template T* NetObjPtr::operator->() const { - return sharedPtr.get(); - } - - template NetObjPtr::operator bool() const { - return sharedPtr != nullptr; - } - - template std::strong_ordering NetObjPtr::operator<=>(const NetObjPtr& rhs) const { - return sharedPtr <=> rhs.sharedPtr; - } - - template void NetObjPtr::send_client_update(const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) const { - if(objMan->client && !objMan->client->is_disconnected()) { - auto ss(std::make_shared()); - { - cereal::PortableBinaryOutputArchive m(*ss); - m(objMan->updateCommandID, id); - sendUpdateFunc(*this, m); - } - objMan->client->send_string_stream_to_server(channel, ss); - } - } - - template void NetObjPtr::send_server_update_to_all_clients(const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) const { - if(objMan->server && !objMan->server->is_disconnected()) { - auto ss(std::make_shared()); - { - cereal::PortableBinaryOutputArchive m(*ss); - m(objMan->updateCommandID, id); - sendUpdateFunc(*this, m); - } - objMan->server->send_string_stream_to_all_clients(channel, ss); - } - } - - template void NetObjPtr::send_update_to_all(const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) const { - if(objMan->is_server()) - send_server_update_to_all_clients(channel, sendUpdateFunc); - else - send_client_update(channel, sendUpdateFunc); - } - - template void NetObjPtr::write_create_message(cereal::PortableBinaryOutputArchive& a) const { - a(id); - objMan->typeList->get_type_index_data(objMan->isServer).writeConstructorFunc(this->cast(), a); - } - - template NetObjPtr::NetObjPtr(NetObjManager* initObjMan, NetObjID initID, const std::shared_ptr& initPtr): - objMan(initObjMan), - id(initID), - sharedPtr(initPtr) - {} -} diff --git a/include/Helpers/NetworkingObjects/NetObjTemporaryPtr.decl.hpp b/include/Helpers/NetworkingObjects/NetObjTemporaryPtr.decl.hpp new file mode 100644 index 0000000..4bfa5f0 --- /dev/null +++ b/include/Helpers/NetworkingObjects/NetObjTemporaryPtr.decl.hpp @@ -0,0 +1,39 @@ +#pragma once +#include "NetObjID.hpp" +#include +#include +#include "NetObjOwnerPtr.decl.hpp" +#include "../Networking/NetServer.hpp" + +namespace NetworkingObjects { + class NetObjManager; + template class NetObjTemporaryPtr { + public: + NetObjTemporaryPtr(); + NetObjTemporaryPtr(const NetObjTemporaryPtr& other); + NetObjTemporaryPtr(const NetObjOwnerPtr& owner); + NetObjTemporaryPtr& operator=(const NetObjTemporaryPtr& other); + template NetObjTemporaryPtr cast() const; + NetObjManager* get_obj_man() const; + NetObjID get_net_id() const; + T* get() const; + std::add_lvalue_reference_t operator*() const requires(!std::is_void_v); + T* operator->() const; + operator bool() const; + std::strong_ordering operator<=>(const NetObjTemporaryPtr& rhs) const; + void send_client_update(const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) const; + void send_server_update_to_client(const std::shared_ptr& clientToSendTo, const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) const; + void send_server_update_to_all_clients_except(const std::shared_ptr& clientToNotSendTo, const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) const; + void send_server_update_to_all_clients(const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) const; + void send_update_to_all(const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) const; + void write_create_message(cereal::PortableBinaryOutputArchive& a) const; + private: + friend class NetObjManager; + template friend class NetObjWeakPtr; + NetObjTemporaryPtr(NetObjManager* initObjMan, NetObjID initID, T* initRawPtr); + + NetObjManager* objMan; + NetObjID id; + T* rawPtr; + }; +} diff --git a/include/Helpers/NetworkingObjects/NetObjTemporaryPtr.hpp b/include/Helpers/NetworkingObjects/NetObjTemporaryPtr.hpp new file mode 100644 index 0000000..bc380d0 --- /dev/null +++ b/include/Helpers/NetworkingObjects/NetObjTemporaryPtr.hpp @@ -0,0 +1,3 @@ +#pragma once +#include "NetObjTemporaryPtr.decl.hpp" +#include "NetObjTemporaryPtr.impl.hpp" diff --git a/include/Helpers/NetworkingObjects/NetObjTemporaryPtr.impl.hpp b/include/Helpers/NetworkingObjects/NetObjTemporaryPtr.impl.hpp new file mode 100644 index 0000000..f0a8ad4 --- /dev/null +++ b/include/Helpers/NetworkingObjects/NetObjTemporaryPtr.impl.hpp @@ -0,0 +1,95 @@ +#pragma once +#include +#include +#include +#include +#include +#include "NetObjTemporaryPtr.decl.hpp" +#include "NetObjManager.hpp" +#include "NetObjManagerTypeList.hpp" + +namespace NetworkingObjects { + template NetObjTemporaryPtr::NetObjTemporaryPtr(): + objMan(nullptr), + rawPtr(nullptr) + {} + template NetObjTemporaryPtr::NetObjTemporaryPtr(const NetObjTemporaryPtr& other): + objMan(other.objMan), + id(other.id), + rawPtr(other.rawPtr) + {} + template NetObjTemporaryPtr::NetObjTemporaryPtr(const NetObjOwnerPtr& owner): + objMan(owner.objMan), + id(owner.id), + rawPtr(owner.rawPtr) + {} + + template NetObjTemporaryPtr& NetObjTemporaryPtr::operator=(const NetObjTemporaryPtr& other) { + objMan = other.objMan; + id = other.id; + rawPtr = other.rawPtr; + return *this; + } + template template NetObjTemporaryPtr NetObjTemporaryPtr::cast() const { + return NetObjPtr(objMan, id, static_cast(rawPtr)); + } + + template NetObjManager* NetObjTemporaryPtr::get_obj_man() const { + return objMan; + } + + template NetObjID NetObjTemporaryPtr::get_net_id() const { + return id; + } + + template T* NetObjTemporaryPtr::get() const { + return rawPtr; + } + + template std::add_lvalue_reference_t NetObjTemporaryPtr::operator*() const requires(!std::is_void_v) { + return *rawPtr; + } + + template T* NetObjTemporaryPtr::operator->() const { + return rawPtr; + } + + template NetObjTemporaryPtr::operator bool() const { + return rawPtr; + } + + template std::strong_ordering NetObjTemporaryPtr::operator<=>(const NetObjTemporaryPtr& rhs) const { + return rawPtr <=> rhs.rawPtr; + } + + template void NetObjTemporaryPtr::send_client_update(const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) const { + NetObjManager::send_client_update(*this, channel, sendUpdateFunc); + } + + template void NetObjTemporaryPtr::send_server_update_to_all_clients(const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) const { + NetObjManager::send_server_update_to_all_clients(*this, channel, sendUpdateFunc); + } + + + template void NetObjTemporaryPtr::send_server_update_to_client(const std::shared_ptr& clientToSendTo, const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) const { + NetObjManager::send_server_update_to_client(*this, clientToSendTo, channel, sendUpdateFunc); + } + template void NetObjTemporaryPtr::send_server_update_to_all_clients_except(const std::shared_ptr& clientToNotSendTo, const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) const { + NetObjManager::send_server_update_to_all_clients_except(*this, clientToNotSendTo, channel, sendUpdateFunc); + } + + template void NetObjTemporaryPtr::send_update_to_all(const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) const { + NetObjManager::send_update_to_all(*this, channel, sendUpdateFunc); + } + + template void NetObjTemporaryPtr::write_create_message(cereal::PortableBinaryOutputArchive& a) const { + NetObjManager::write_create_message(*this, a); + } + + template NetObjTemporaryPtr::NetObjTemporaryPtr(NetObjManager* initObjMan, NetObjID initID, T* initRawPtr): + objMan(initObjMan), + id(initID), + rawPtr(initRawPtr) + {} +} + diff --git a/include/Helpers/NetworkingObjects/NetObjWeakPtr.hpp b/include/Helpers/NetworkingObjects/NetObjWeakPtr.hpp index b9fe6c6..e6145de 100644 --- a/include/Helpers/NetworkingObjects/NetObjWeakPtr.hpp +++ b/include/Helpers/NetworkingObjects/NetObjWeakPtr.hpp @@ -1,7 +1,9 @@ #pragma once #include "NetObjID.hpp" #include "NetObjManager.hpp" -#include "NetObjPtr.decl.hpp" +#include "NetObjOwnerPtr.decl.hpp" +#include "NetObjTemporaryPtr.decl.hpp" +#include namespace NetworkingObjects { template class NetObjWeakPtr { @@ -14,10 +16,22 @@ namespace NetworkingObjects { objMan(other.objMan), id(other.id) {} - NetObjWeakPtr(const NetObjPtr& other): + NetObjWeakPtr(const NetObjOwnerPtr& other): objMan(other.objMan), id(other.id) {} + NetObjWeakPtr(const NetObjTemporaryPtr& other): + objMan(other.objMan), + id(other.id) + {} + NetObjWeakPtr& operator=(const NetObjOwnerPtr& other) { + objMan = other.objMan; + id = other.id; + } + NetObjWeakPtr& operator=(const NetObjTemporaryPtr& other) { + objMan = other.objMan; + id = other.id; + } NetObjWeakPtr& operator=(const NetObjWeakPtr& other) { objMan = other.objMan; id = other.id; @@ -26,17 +40,15 @@ namespace NetworkingObjects { return NetObjWeakPtr(objMan, id); } bool expired() const { - if(!objMan) - return true; - auto it = objMan->objectData.find(id); - return it == objMan->objectData.end(); + return !objMan || objMan->objectData.contains(id); } - NetObjPtr lock() const { + NetObjTemporaryPtr lock() const { + if(!objMan) + return NetObjTemporaryPtr(); auto it = objMan->objectData.find(id); if(it == objMan->objectData.end()) - return NetObjPtr(); - else - return NetObjPtr(objMan, id, std::static_pointer_cast(it->second.p)); + return NetObjTemporaryPtr(); + return NetObjTemporaryPtr(objMan, id, static_cast(it->second.p)); } NetObjManager* get_obj_man() const { return objMan; @@ -56,7 +68,6 @@ namespace NetworkingObjects { id(initID) {} - template friend class NetObjPtr; NetObjManager* objMan; NetObjID id; }; diff --git a/src/BookmarkManager.cpp b/src/BookmarkManager.cpp index 433f680..30c6522 100644 --- a/src/BookmarkManager.cpp +++ b/src/BookmarkManager.cpp @@ -23,32 +23,15 @@ void BookmarkManager::init() { } void BookmarkManager::add_bookmark(const std::string& name) { - NetworkingObjects::NetObjPtr bookmarkPtr = bookmarks->emplace_back_direct(bookmarks, Bookmark{name, world.drawData.cam.c, world.main.window.size.cast()}); - uint32_t pos = bookmarks->size() - 1; - world.undo.push({[&bookmarks = bookmarks, bookmarkPtr](){ - bookmarks->erase(bookmarks, bookmarkPtr); - return true; - }, - [&bookmarks = bookmarks, bookmarkPtr, pos]() { - bookmarks->insert_and_send_create(bookmarks, pos, bookmarkPtr); - return true; - }}); + bookmarks->emplace_back_direct(bookmarks, Bookmark{name, world.drawData.cam.c, world.main.window.size.cast()}); } void BookmarkManager::remove_bookmark(uint32_t bookmarkIndex) { - NetworkingObjects::NetObjPtr bookmarkPtr = bookmarks->erase(bookmarks, bookmarkIndex); - world.undo.push({[&bookmarks = bookmarks, bookmarkPtr, bookmarkIndex]() { - bookmarks->insert_and_send_create(bookmarks, bookmarkIndex, bookmarkPtr); - return true; - }, - [&bookmarks = bookmarks, bookmarkPtr](){ - bookmarks->erase(bookmarks, bookmarkPtr); - return true; - }}); + bookmarks->erase(bookmarks, bookmarkIndex); } void BookmarkManager::jump_to_bookmark(uint32_t bookmarkIndex) { - const NetworkingObjects::NetObjPtr& b = bookmarks->at(bookmarkIndex); + auto& b = bookmarks->at(bookmarkIndex); world.drawData.cam.smooth_move_to(world, b->coords, b->windowSize.cast()); } diff --git a/src/BookmarkManager.hpp b/src/BookmarkManager.hpp index 02ebe33..389a8bd 100644 --- a/src/BookmarkManager.hpp +++ b/src/BookmarkManager.hpp @@ -41,7 +41,7 @@ class BookmarkManager { } } - NetworkingObjects::NetObjPtr> bookmarks; + NetworkingObjects::NetObjOwnerPtr> bookmarks; private: World& world; }; diff --git a/src/CanvasComponents/CanvasComponent.cpp b/src/CanvasComponents/CanvasComponent.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/CanvasComponents/CanvasComponent.hpp b/src/CanvasComponents/CanvasComponent.hpp new file mode 100644 index 0000000..8808aad --- /dev/null +++ b/src/CanvasComponents/CanvasComponent.hpp @@ -0,0 +1,20 @@ +#pragma once +#include +#include +#include + +class CanvasComponent { + public: + enum class CompType : uint8_t { + BRUSHSTROKE = 0, + RECTANGLE, + ELLIPSE, + TEXTBOX, + IMAGE + }; + protected: + virtual void write_update() const; + virtual void read_update(); + virtual void save_file(cereal::PortableBinaryOutputArchive& a) const; + virtual void load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version); +}; diff --git a/src/CanvasComponents/CanvasComponentBrushStroke.cpp b/src/CanvasComponents/CanvasComponentBrushStroke.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/CanvasComponents/CanvasComponentBrushStroke.hpp b/src/CanvasComponents/CanvasComponentBrushStroke.hpp new file mode 100644 index 0000000..93848b6 --- /dev/null +++ b/src/CanvasComponents/CanvasComponentBrushStroke.hpp @@ -0,0 +1,62 @@ +#pragma once +#include "CanvasComponent.hpp" +#include "Helpers/SCollision.hpp" +#include +#include +#include + +struct DrawBrushStrokePoint { + Vector2f pos; + float width; + + template void serialize(Archive& a) { + a(pos, width); + } +}; + +class CanvasComponentBrushStroke : public CanvasComponent { + public: + constexpr static float DRAW_MINIMUM_LIMIT = 0.3; + + virtual DrawComponentType get_type() const override; + virtual void write_update(cereal::PortableBinaryOutputArchive& a) const override; + virtual void read_update(cereal::PortableBinaryInputArchive& a) override; + virtual void save_file(cereal::PortableBinaryOutputArchive& a) const override; + virtual void load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version) override; + + struct Data { + std::vector points; + Vector4f color; + bool hasRoundCaps; + }; + std::shared_ptr d = std::make_shared(); // It's a pointer here since brush strokes cant be edited + +#ifndef IS_SERVER + virtual std::shared_ptr copy(DrawingProgram& drawP) const override; + virtual std::shared_ptr deep_copy(DrawingProgram& drawP) const override; + + virtual void draw(SkCanvas* canvas, const DrawData& drawData) override; + virtual void initialize_draw_data(DrawingProgram& drawP) override; + virtual void update(DrawingProgram& drawP) override; + virtual bool collides_within_coords(const SCollision::ColliderCollection& checkAgainst) override; + void create_collider(); + virtual void update_from_delayed_ptr(const std::shared_ptr& delayedUpdatePtr) override; + + virtual SCollision::AABB get_obj_coord_bounds() const override; + + std::shared_ptr brushPath; + SCollision::AABB bounds; + + std::array, 2> brushPathLOD; + private: + std::vector every_nth_point_include_front_and_back(const std::vector& pts, size_t n); + + void add_precheck_aabb_level(size_t level, const std::vector>& levelArray); + std::vector> precheckAABBLevels; + void create_triangles(const std::function& passTriangleFunc, const std::vector& smoothedPoints, size_t skipVertexCount, std::shared_ptr bPath); + std::vector get_wedge_indices(const std::vector& points); + std::vector smooth_points(size_t beginIndex, size_t endIndex, unsigned numOfDivisions); + std::vector smooth_points_avg(size_t beginIndex, size_t endIndex, unsigned numOfDivisions); +#endif +}; + diff --git a/src/CanvasComponents/CanvasComponentContainer.cpp b/src/CanvasComponents/CanvasComponentContainer.cpp new file mode 100644 index 0000000..48a218f --- /dev/null +++ b/src/CanvasComponents/CanvasComponentContainer.cpp @@ -0,0 +1,41 @@ +#include "CanvasComponentContainer.hpp" + +CanvasComponentContainer::CanvasComponentContainer() { } + +CanvasComponentContainer::CanvasComponentContainer(CanvasComponent::CompType type) { + allocate_comp(type); +} + +void CanvasComponentContainer::register_class(NetworkingObjects::NetObjManagerTypeList& t) { + t.register_class({ + }); +} + +std::unique_ptr CanvasComponentContainer::allocate_comp(CanvasComponent::CompType type) { + switch(type) { + case CanvasComponent::CompType::BRUSHSTROKE: + return std::make_unique(); + case CanvasComponent::CompType::RECTANGLE: + return std::make_unique(); + case CanvasComponent::CompType::ELLIPSE: + return std::make_unique(); + case CanvasComponent::CompType::TEXTBOX: + return std::make_unique(); + case CanvasComponent::CompType::IMAGE: + return std::make_unique(); + } +} + +void CanvasComponentContainer::save_file(cereal::PortableBinaryOutputArchive& a) const { +} + +void CanvasComponentContainer::load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version) { +} + +const std::unique_ptr& CanvasComponentContainer::get_comp() { + return comp; +} + +const CoordSpaceHelper& CanvasComponentContainer::get_coords() { + return coords; +} diff --git a/src/CanvasComponents/CanvasComponentContainer.hpp b/src/CanvasComponents/CanvasComponentContainer.hpp new file mode 100644 index 0000000..a1c4ecd --- /dev/null +++ b/src/CanvasComponents/CanvasComponentContainer.hpp @@ -0,0 +1,20 @@ +#pragma once +#include "../CoordSpaceHelper.hpp" +#include "CanvasComponent.hpp" +#include +#include "../VersionConstants.hpp" + +class CanvasComponentContainer { + public: + CanvasComponentContainer(); + CanvasComponentContainer(CanvasComponent::CompType type); + static void register_class(NetworkingObjects::NetObjManagerTypeList& t); + void save_file(cereal::PortableBinaryOutputArchive& a) const; + void load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version); + const std::unique_ptr& get_comp(); + const CoordSpaceHelper& get_coords(); + private: + std::unique_ptr allocate_comp(CanvasComponent::CompType type); + std::unique_ptr comp; + CoordSpaceHelper coords; +}; diff --git a/src/DrawingProgram/DrawingProgram.cpp b/src/DrawingProgram/DrawingProgram.cpp index 52b1e83..94aa235 100644 --- a/src/DrawingProgram/DrawingProgram.cpp +++ b/src/DrawingProgram/DrawingProgram.cpp @@ -283,7 +283,7 @@ void DrawingProgram::tool_options_gui() { } } -void DrawingProgram::modify_grid(const NetworkingObjects::NetObjPtr& gridToModify) { +void DrawingProgram::modify_grid(const NetworkingObjects::NetObjWeakPtr& gridToModify) { std::unique_ptr newTool(std::make_unique(*this)); newTool->set_grid(gridToModify); switch_to_tool_ptr(std::move(newTool)); diff --git a/src/DrawingProgram/DrawingProgram.hpp b/src/DrawingProgram/DrawingProgram.hpp index f59efd6..a095e29 100644 --- a/src/DrawingProgram/DrawingProgram.hpp +++ b/src/DrawingProgram/DrawingProgram.hpp @@ -2,7 +2,7 @@ #include "../DrawData.hpp" #include "DrawingProgramCache.hpp" #include "GridModifyTool.hpp" -#include +#include #include "PanCanvasTool.hpp" #include "ZoomCanvasTool.hpp" #include "cereal/archives/portable_binary.hpp" @@ -64,7 +64,7 @@ class DrawingProgram { void clear_draw_cache(); - void modify_grid(const NetworkingObjects::NetObjPtr& gridToModify); + void modify_grid(const NetworkingObjects::NetObjWeakPtr& gridToModify); private: std::optional badFrametimeTimePoint; diff --git a/src/DrawingProgram/GridModifyTool.cpp b/src/DrawingProgram/GridModifyTool.cpp index da5c01f..8f5705a 100644 --- a/src/DrawingProgram/GridModifyTool.cpp +++ b/src/DrawingProgram/GridModifyTool.cpp @@ -3,6 +3,7 @@ #include "../MainProgram.hpp" #include "../DrawData.hpp" #include "Helpers/Networking/NetLibrary.hpp" +#include "Helpers/NetworkingObjects/NetObjTemporaryPtr.decl.hpp" #include #include #include @@ -14,10 +15,11 @@ GridModifyTool::GridModifyTool(DrawingProgram& initDrawP): { } -void GridModifyTool::set_grid(const NetObjPtr& newGrid) { +void GridModifyTool::set_grid(const NetObjWeakPtr& newGrid) { grid = newGrid; - if(drawP.world.gridMan.grids->contains(grid)) { - WorldGrid& g = *grid; + NetworkingObjects::NetObjTemporaryPtr gLock = grid.lock(); + if(gLock) { + WorldGrid& g = *gLock; oldGrid = g; CoordSpaceHelper newCam; newCam.inverseScale = g.size / WorldScalar(WorldGrid::GRID_UNIT_PIXEL_SIZE); @@ -35,8 +37,9 @@ void GridModifyTool::gui_toolbox() { Toolbar& t = drawP.world.main.toolbar; t.gui.push_id("Grid modify tool"); t.gui.text_label_centered("Edit Grid"); - if(drawP.world.gridMan.grids->contains(grid)) { - WorldGrid& g = *grid; + NetworkingObjects::NetObjTemporaryPtr gLock = grid.lock(); + if(gLock) { + WorldGrid& g = *gLock; t.gui.input_text_field("grid name", "Name", &g.name); t.gui.checkbox_field("Visible", "Visible", &g.visible); t.gui.checkbox_field("Display in Front", "Display in front of canvas", &g.displayInFront); @@ -86,8 +89,9 @@ bool GridModifyTool::right_click_popup_gui(Vector2f popupPos) { } void GridModifyTool::tool_update() { - if(drawP.world.gridMan.grids->contains(grid)) { - WorldGrid& g = *grid; + NetworkingObjects::NetObjTemporaryPtr gLock = grid.lock(); + if(gLock) { + WorldGrid& g = *gLock; switch(selectionMode) { case 0: if(drawP.controls.leftClick) { @@ -137,7 +141,7 @@ void GridModifyTool::tool_update() { selectionMode = 0; break; } - drawP.world.delayedUpdateObjectManager.send_update_to_all(grid, false); + drawP.world.delayedUpdateObjectManager.send_update_to_all(gLock, false); } else selectionMode = 0; @@ -148,8 +152,9 @@ bool GridModifyTool::prevent_undo_or_redo() { } void GridModifyTool::draw(SkCanvas* canvas, const DrawData& drawData) { - if(drawP.world.gridMan.grids->contains(grid)) { - WorldGrid& g = *grid; + NetworkingObjects::NetObjTemporaryPtr gLock = grid.lock(); + if(gLock) { + WorldGrid& g = *gLock; if(g.bounds.has_value()) { const auto& b = g.bounds.value(); Vector2f bMin = drawP.world.drawData.cam.c.to_space(b.min); @@ -180,5 +185,7 @@ void GridModifyTool::draw(SkCanvas* canvas, const DrawData& drawData) { } void GridModifyTool::switch_tool(DrawingProgramToolType newTool) { - drawP.world.delayedUpdateObjectManager.send_update_to_all(grid, true); + NetworkingObjects::NetObjTemporaryPtr gLock = grid.lock(); + if(gLock) + drawP.world.delayedUpdateObjectManager.send_update_to_all(gLock, true); } diff --git a/src/DrawingProgram/GridModifyTool.hpp b/src/DrawingProgram/GridModifyTool.hpp index f693be1..24d8731 100644 --- a/src/DrawingProgram/GridModifyTool.hpp +++ b/src/DrawingProgram/GridModifyTool.hpp @@ -1,14 +1,14 @@ #pragma once #include "DrawingProgramToolBase.hpp" #include "../WorldGrid.hpp" -#include "Helpers/NetworkingObjects/NetObjPtr.hpp" +#include "Helpers/NetworkingObjects/NetObjWeakPtr.hpp" class DrawingProgram; class GridModifyTool : public DrawingProgramToolBase { public: GridModifyTool(DrawingProgram& initDrawP); - void set_grid(const NetworkingObjects::NetObjPtr& newGrid); + void set_grid(const NetworkingObjects::NetObjWeakPtr& newGrid); virtual DrawingProgramToolType get_type() override; virtual void gui_toolbox() override; virtual bool right_click_popup_gui(Vector2f popupPos) override; @@ -18,6 +18,6 @@ class GridModifyTool : public DrawingProgramToolBase { virtual void switch_tool(DrawingProgramToolType newTool) override; private: WorldGrid oldGrid; - NetworkingObjects::NetObjPtr grid; + NetworkingObjects::NetObjWeakPtr grid; unsigned selectionMode = 0; }; diff --git a/src/GridManager.cpp b/src/GridManager.cpp index 11e50ad..45b0bc1 100644 --- a/src/GridManager.cpp +++ b/src/GridManager.cpp @@ -21,32 +21,13 @@ void GridManager::add_default_grid(const std::string& newName) { g.color = color_mul_alpha(convert_vec4(world.canvasTheme.toolFrontColor), 0.4f); g.size = world.drawData.cam.c.inverseScale * WorldScalar(WorldGrid::GRID_UNIT_PIXEL_SIZE); g.offset = world.drawData.cam.c.pos + world.drawData.cam.c.dir_from_space(world.main.window.size.cast() * 0.5f); - NetworkingObjects::NetObjPtr gridPtr = grids->emplace_back_direct(grids, g); - - uint32_t pos = grids->size() - 1; - world.undo.push({[&grids = grids, gridPtr](){ - grids->erase(grids, gridPtr); - return true; - }, - [&grids = grids, gridPtr, pos]() { - grids->insert_and_send_create(grids, pos, gridPtr); - return true; - }}); + grids->emplace_back_direct(grids, g); } } void GridManager::remove_grid(uint32_t indexToRemove) { - if(grids) { - NetworkingObjects::NetObjPtr gridPtr = grids->erase(grids, indexToRemove); - world.undo.push({[&grids = grids, gridPtr, indexToRemove]() { - grids->insert_and_send_create(grids, indexToRemove, gridPtr); - return true; - }, - [&grids = grids, gridPtr](){ - grids->erase(grids, gridPtr); - return true; - }}); - } + if(grids) + grids->erase(grids, indexToRemove); } void GridManager::draw_back(SkCanvas* canvas, const DrawData& drawData) { diff --git a/src/GridManager.hpp b/src/GridManager.hpp index ca8dc9f..0f19d5a 100644 --- a/src/GridManager.hpp +++ b/src/GridManager.hpp @@ -1,7 +1,7 @@ #pragma once -#include "Helpers/NetworkingObjects/NetObjPtr.decl.hpp" #include "WorldGrid.hpp" #include +#include class World; @@ -33,6 +33,6 @@ class GridManager { void draw_coordinates(SkCanvas* canvas, const DrawData& drawData); void scale_up(const WorldScalar& scaleUpAmount); - NetworkingObjects::NetObjPtr> grids; + NetworkingObjects::NetObjOwnerPtr> grids; World& world; }; diff --git a/src/MainProgram.cpp b/src/MainProgram.cpp index 7cde893..99e1bfc 100755 --- a/src/MainProgram.cpp +++ b/src/MainProgram.cpp @@ -38,8 +38,6 @@ #endif #include -#include -#include MainProgram::MainProgram(): fonts(std::make_shared()), diff --git a/src/World.hpp b/src/World.hpp index 916d6bf..13ebcf8 100644 --- a/src/World.hpp +++ b/src/World.hpp @@ -1,6 +1,6 @@ #pragma once -#include "Helpers/NetworkingObjects/DelayUpdateSerializedClassManager.hpp" -#include "Helpers/NetworkingObjects/NetObjOrderedList.hpp" +#include +#include #include "UndoManager.hpp" #include "BookmarkManager.hpp" #include "ResourceManager.hpp"