#pragma once #include "Helpers/Networking/NetLibrary.hpp" #include "NetObjWeakPtr.hpp" #include "cereal/archives/portable_binary.hpp" #include namespace NetworkingObjects { class DelayUpdateSerializedClassManager { public: template void register_class(NetObjManager& objMan) { objMan.register_class({ .writeConstructorFuncClient = [&](const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a){write_constructor_func(o, a);}, .readConstructorFuncClient = [&](const NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&){read_constructor_func(o, a);}, .readUpdateFuncClient = [&](const NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&){client_read_update_func(o, a);}, .writeConstructorFuncServer = [&](const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a){write_constructor_func(o, a);}, .readConstructorFuncServer = [&](const NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&){read_constructor_func(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::NetObjTemporaryPtr& o, const std::function& postAssignmentFunc, 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, postAssignmentFunc); else client_write_update_func(o, a, postAssignmentFunc, finalUpdate); }); } void update(); private: template void write_constructor_func(const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a) { a(*o); } template void client_write_update_func(const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a, const std::function& postAssignmentFunc, bool finalUpdate) { a(finalUpdate); 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.doLastAssignment = std::make_shared(true); toAdd.lastUpdateTimePoint = std::chrono::steady_clock::now(); toAdd.setDataAfterTimeout = [postAssignmentFunc, oWeak = NetObjWeakPtr(o), currentData = toAdd.objToUpdateCurrentData, doLastAssignment = toAdd.doLastAssignment]() { NetObjTemporaryPtr oLock = oWeak.lock(); if(oLock && *doLastAssignment) { *oLock = *std::static_pointer_cast(currentData); if(postAssignmentFunc) postAssignmentFunc(*oLock); } }; updatingObjs.emplace(o.get_net_id(), toAdd); } else { auto& [netID, updatingObjData] = *it; updatingObjData.lastUpdateTimePoint = std::chrono::steady_clock::now(); } } template void read_constructor_func(const NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a) { a(*o); } template void client_read_update_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 NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a, const std::function& postAssignmentFunc) { 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.doLastAssignment = std::make_shared(false); toAdd.setDataAfterTimeout = [postAssignmentFunc, oWeak = NetObjWeakPtr(o), currentData = toAdd.objToUpdateCurrentData, doLastAssignment = toAdd.doLastAssignment]() { NetObjTemporaryPtr oLock = oWeak.lock(); if(oLock && *doLastAssignment) { *oLock = *std::static_pointer_cast(currentData); if(postAssignmentFunc) postAssignmentFunc(*oLock); oLock.send_server_update_to_all_clients(RELIABLE_COMMAND_CHANNEL, [](const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a) { a(*o); }); } }; updatingObjs.emplace(o.get_net_id(), toAdd); } else { 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 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 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; }; std::unordered_map updatingObjs; }; }