From 4a97c6be7953ece290fb2eba70a8630bb43d86b0 Mon Sep 17 00:00:00 2001 From: Chris Sibbitt Date: Fri, 13 Oct 2023 23:55:12 -0400 Subject: [PATCH] Sequenced vectors with efficient replication * Adds sp::SeqVector for tracking elements that have a sequence number * Tracks last sequence # to replicate * Provides significant performance improvements for EE ships_log --- src/multiplayer.h | 70 ++++++++++++++++++++++++++++++++++++++ src/multiplayer_server.cpp | 6 +++- src/multiplayer_server.h | 1 + src/seqvector.h | 16 +++++++++ 4 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 src/seqvector.h diff --git a/src/multiplayer.h b/src/multiplayer.h index 42111bed..bffaec79 100644 --- a/src/multiplayer.h +++ b/src/multiplayer.h @@ -5,6 +5,7 @@ #include #include "Updatable.h" #include "stringImproved.h" +#include "seqvector.h" class MultiplayerObject; @@ -107,6 +108,55 @@ template struct multiplayerReplicationFunctions std::vector* prev_data = *(std::vector**)prev_data_ptr; delete prev_data; } + + static bool isChangedSeqVector(void* data, void* prev_data_ptr) + { + sp::SeqVector* ptr = (sp::SeqVector*)data; + bool changed = false; + if (ptr->back().seq != ptr->last_seq) + changed = true; + + return changed; + } + + static void sendDataSeqVector(void* data, sp::io::DataBuffer& packet) + { + sp::SeqVector* ptr = (sp::SeqVector*)data; + uint16_t count = ptr->size(); + unsigned int to_send = std::min(ptr->back().seq - ptr->last_seq, static_cast(count)); + + ptr->last_seq = ptr->back().seq; + + packet << count << to_send; + for(; to_send > 0; to_send--) + packet << (*ptr)[count - to_send]; + } + + static void sendWholeDataSeqVector(void* data, sp::io::DataBuffer& packet) + { + sp::SeqVector* ptr = (sp::SeqVector*)data; + auto last_seq = ptr->last_seq; + ptr->last_seq = ptr->front().seq - 1; + sendDataSeqVector(data, packet); + ptr->last_seq = last_seq; + } + + static void receiveDataSeqVector(void* data, sp::io::DataBuffer& packet) + { + sp::SeqVector* ptr = (sp::SeqVector*)data; + uint16_t count; + unsigned int to_recv; + packet >> count >> to_recv; + + // Remove oldest entries if local vector would grow larger than server's + while (ptr->size() + to_recv > count) + ptr->erase(ptr->begin()); + + ptr->resize(count); + + for(unsigned int n=count - to_recv; n> (*ptr)[n]; + } }; template @@ -146,6 +196,7 @@ class MultiplayerObject : public virtual PObject bool(*isChangedFunction)(void* data, void* prev_data_ptr); void(*sendFunction)(void* data, sp::io::DataBuffer& packet); + void(*sendWholeFunction)(void* data, sp::io::DataBuffer& packet) = nullptr; void(*receiveFunction)(void* data, sp::io::DataBuffer& packet); void(*cleanupFunction)(void* prev_data_ptr); }; @@ -217,6 +268,25 @@ class MultiplayerObject : public virtual PObject memberReplicationInfo.push_back(info); } + template void registerMemberReplication_(F_PARAM sp::SeqVector* member, float update_delay = 0.0f) + { + SDL_assert(!replicated); + SDL_assert(memberReplicationInfo.size() < 0xFFFF); + MemberReplicationInfo info; +#ifdef DEBUG + info.name = name; +#endif + info.ptr = member; + info.update_delay = update_delay; + info.update_timeout = 0.0f; + info.isChangedFunction = &multiplayerReplicationFunctions::isChangedSeqVector; + info.sendFunction = &multiplayerReplicationFunctions::sendDataSeqVector; + info.sendWholeFunction = &multiplayerReplicationFunctions::sendWholeDataSeqVector; + info.receiveFunction = &multiplayerReplicationFunctions::receiveDataSeqVector; + info.cleanupFunction = nullptr; + memberReplicationInfo.push_back(info); + } + void registerMemberReplication_(F_PARAM glm::vec3* member, float update_delay = 0.0f) { registerMemberReplication(&member->x, update_delay); diff --git a/src/multiplayer_server.cpp b/src/multiplayer_server.cpp index 3c9245ee..ae033a3a 100644 --- a/src/multiplayer_server.cpp +++ b/src/multiplayer_server.cpp @@ -562,7 +562,11 @@ void GameServer::generateCreatePacketFor(P obj, sp::io::DataB for(unsigned int n=0; nmemberReplicationInfo.size(); n++) { packet << int16_t(n); - (obj->memberReplicationInfo[n].sendFunction)(obj->memberReplicationInfo[n].ptr, packet); + if (obj->memberReplicationInfo[n].sendWholeFunction) + (obj->memberReplicationInfo[n].sendWholeFunction)(obj->memberReplicationInfo[n].ptr, packet); + else + (obj->memberReplicationInfo[n].sendFunction)(obj->memberReplicationInfo[n].ptr, packet); + } } diff --git a/src/multiplayer_server.h b/src/multiplayer_server.h index 988db30b..a058328d 100644 --- a/src/multiplayer_server.h +++ b/src/multiplayer_server.h @@ -12,6 +12,7 @@ #include "stringImproved.h" #include "networkAudioStream.h" #include "timer.h" +#include "seqvector.h" #include #include diff --git a/src/seqvector.h b/src/seqvector.h new file mode 100644 index 00000000..0c7589e9 --- /dev/null +++ b/src/seqvector.h @@ -0,0 +1,16 @@ +#ifndef SEQVECTOR_H +#define SEQVECTOR_H + +#include + +namespace sp { + +// A vector that tracks sequenced elements +template class SeqVector : public std::vector{ +public: + unsigned int last_seq = 0; +}; + +}//namespace sp + +#endif//SEQVECTOR_H