From cf224a6ceea8f2f2dc30789f91a81edaafa97df6 Mon Sep 17 00:00:00 2001 From: praydog Date: Sun, 7 Aug 2022 10:37:38 -0700 Subject: [PATCH] Networking: Better entity GUID coherence across disconnects --- schema/Welcome.fbs | 1 + server/nier/Welcome.go | 17 +++++++++++++++- server/server.go | 6 ++++++ src/mods/multiplayer/EntitySync.cpp | 11 +++++++++- src/mods/multiplayer/EntitySync.hpp | 2 +- src/mods/multiplayer/NierClient.cpp | 20 ++++++++++--------- src/mods/multiplayer/NierClient.hpp | 2 +- .../multiplayer/schema/Packets_generated.h | 14 +++++++++++-- 8 files changed, 58 insertions(+), 15 deletions(-) diff --git a/schema/Welcome.fbs b/schema/Welcome.fbs index ee71d76..d59390c 100644 --- a/schema/Welcome.fbs +++ b/schema/Welcome.fbs @@ -3,6 +3,7 @@ namespace nier; table Welcome { guid: ulong; isMasterClient: bool; + highestEntityGuid: uint; } root_type Welcome; \ No newline at end of file diff --git a/server/nier/Welcome.go b/server/nier/Welcome.go index a760d7d..3c34634 100644 --- a/server/nier/Welcome.go +++ b/server/nier/Welcome.go @@ -57,8 +57,20 @@ func (rcv *Welcome) MutateIsMasterClient(n bool) bool { return rcv._tab.MutateBoolSlot(6, n) } +func (rcv *Welcome) HighestEntityGuid() uint32 { + o := flatbuffers.UOffsetT(rcv._tab.Offset(8)) + if o != 0 { + return rcv._tab.GetUint32(o + rcv._tab.Pos) + } + return 0 +} + +func (rcv *Welcome) MutateHighestEntityGuid(n uint32) bool { + return rcv._tab.MutateUint32Slot(8, n) +} + func WelcomeStart(builder *flatbuffers.Builder) { - builder.StartObject(2) + builder.StartObject(3) } func WelcomeAddGuid(builder *flatbuffers.Builder, guid uint64) { builder.PrependUint64Slot(0, guid, 0) @@ -66,6 +78,9 @@ func WelcomeAddGuid(builder *flatbuffers.Builder, guid uint64) { func WelcomeAddIsMasterClient(builder *flatbuffers.Builder, isMasterClient bool) { builder.PrependBoolSlot(1, isMasterClient, false) } +func WelcomeAddHighestEntityGuid(builder *flatbuffers.Builder, highestEntityGuid uint32) { + builder.PrependUint32Slot(2, highestEntityGuid, 0) +} func WelcomeEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { return builder.EndObject() } diff --git a/server/server.go b/server/server.go index 2025fe1..15fe213 100644 --- a/server/server.go +++ b/server/server.go @@ -146,6 +146,7 @@ func makeEntityPacketBytes(guid uint32, id nier.PacketType, data []uint8) []uint var connections = make(map[enet.Peer]*Connection) var clients = make(map[*Connection]*Client) var connectionCount uint64 = 0 +var highestEntityGuid uint32 = 0 type ActiveEntity struct { guid uint32 @@ -403,6 +404,7 @@ func main() { nier.WelcomeStart(builder) nier.WelcomeAddGuid(builder, client.guid) nier.WelcomeAddIsMasterClient(builder, client.isMasterClient) + nier.WelcomeAddHighestEntityGuid(builder, highestEntityGuid) return nier.WelcomeEnd(builder) }) @@ -533,6 +535,10 @@ func main() { spawnInfo := &nier.EntitySpawnParams{} flatbuffers.GetRootAs(entityPkt.DataBytes(), 0, spawnInfo) + if entityPkt.Guid() > highestEntityGuid { + highestEntityGuid = entityPkt.Guid() + } + entities[entityPkt.Guid()] = new(ActiveEntity) entities[entityPkt.Guid()].guid = entityPkt.Guid() entities[entityPkt.Guid()].spawnInfo = spawnInfo diff --git a/src/mods/multiplayer/EntitySync.cpp b/src/mods/multiplayer/EntitySync.cpp index 9afa171..1c4d31c 100644 --- a/src/mods/multiplayer/EntitySync.cpp +++ b/src/mods/multiplayer/EntitySync.cpp @@ -42,7 +42,9 @@ void NetworkEntity::startAnimationHook(Entity* ent, uint32_t anim, uint32_t vari original(ent, anim, variant, a3, a4); } -EntitySync::EntitySync() { +EntitySync::EntitySync(uint32_t highestGuid) + : m_maxGuid{highestGuid} +{ g_entitySync = this; } @@ -137,6 +139,13 @@ std::shared_ptr EntitySync::addEntity(EntityContainer* entity, ui spdlog::info("Adding entity {:x} with guid {}", (uintptr_t)entity, guid); scoped_lock _(m_mapMutex); + + // This allows someone taking over as master client + // to not screw up any previously spawned entities. + if (guid > m_maxGuid) { + m_maxGuid = guid; + } + auto& networkEntity = m_networkEntities[guid]; if (networkEntity == nullptr || networkEntity->getEntity() != entity) { diff --git a/src/mods/multiplayer/EntitySync.hpp b/src/mods/multiplayer/EntitySync.hpp index c9b7655..10d262d 100644 --- a/src/mods/multiplayer/EntitySync.hpp +++ b/src/mods/multiplayer/EntitySync.hpp @@ -57,7 +57,7 @@ class NetworkEntity { class EntitySync { public: - EntitySync(); + EntitySync(uint32_t highestGuid = 0); void onEntityCreated(EntityContainer* entity, EntitySpawnParams* data); void onEntityDeleted(EntityContainer* entity); diff --git a/src/mods/multiplayer/NierClient.cpp b/src/mods/multiplayer/NierClient.cpp index 9f06501..a48c827 100644 --- a/src/mods/multiplayer/NierClient.cpp +++ b/src/mods/multiplayer/NierClient.cpp @@ -82,7 +82,7 @@ void NierClient::think() { //*npc->getPosition() = *(Vector3f*)&data.position(); } - m_networkEntities.think(); + m_networkEntities->think(); } } @@ -459,7 +459,7 @@ void NierClient::sendEntityData(uint32_t guid, Entity* entity) { builder.Finish(builder.CreateStruct(newData)); - m_networkEntities.processEntityData(guid, &newData); + m_networkEntities->processEntityData(guid, &newData); sendEntityPacket(nier::PacketType_ID_ENTITY_DATA, guid, builder.GetBufferPointer(), builder.GetSize()); } @@ -482,11 +482,11 @@ void NierClient::onEntityCreated(EntityContainer* entity, EntitySpawnParams* dat return; } - m_networkEntities.onEntityCreated(entity, data); + m_networkEntities->onEntityCreated(entity, data); } void NierClient::onEntityDeleted(EntityContainer* entity) { - m_networkEntities.onEntityDeleted(entity); + m_networkEntities->onEntityDeleted(entity); } void NierClient::sendHello() { @@ -597,10 +597,12 @@ bool NierClient::handleWelcome(const nier::Packet* packet) { m_isMasterClient = welcome->isMasterClient(); m_guid = welcome->guid(); + const auto highestGuid = welcome->highestEntityGuid(); spdlog::info("Welcome packet received, isMasterClient: {}, guid: {}", m_isMasterClient, m_guid); - m_networkEntities.onEnterServer(m_isMasterClient); + m_networkEntities = std::make_unique(highestGuid); + m_networkEntities->onEnterServer(m_isMasterClient); return true; } @@ -754,7 +756,7 @@ bool NierClient::handleCreateEntity(const nier::EntityPacket* packet) { //ent->entity->setSuspend(false); spdlog::info(" Entity spawned @ {:x}", (uintptr_t)ent); - auto newNetworkEnt = m_networkEntities.addEntity(ent, packet->guid()); + auto newNetworkEnt = m_networkEntities->addEntity(ent, packet->guid()); if (newNetworkEnt != nullptr) { spdlog::info(" Network entity created"); @@ -770,7 +772,7 @@ bool NierClient::handleCreateEntity(const nier::EntityPacket* packet) { bool NierClient::handleDestroyEntity(const nier::EntityPacket* packet) { spdlog::info("Destroy entity packet received"); - m_networkEntities.removeEntity(packet->guid()); + m_networkEntities->removeEntity(packet->guid()); return true; } @@ -779,7 +781,7 @@ bool NierClient::handleEntityData(const nier::EntityPacket* packet) { spdlog::info("Entity data packet received"); const auto entityData = flatbuffers::GetRoot(packet->data()->data()); - m_networkEntities.processEntityData(packet->guid(), entityData); + m_networkEntities->processEntityData(packet->guid(), entityData); return true; } @@ -788,7 +790,7 @@ bool NierClient::handleEntityAnimationStart(const nier::EntityPacket* packet) { spdlog::info("Entity animation start packet received"); const auto guid = packet->guid(); - auto entityNetworked = m_networkEntities.getNetworkEntityFromGuid(guid); + auto entityNetworked = m_networkEntities->getNetworkEntityFromGuid(guid); if (entityNetworked == nullptr) { spdlog::error(" (nullptr) Entity data packet received for unknown entity {}", guid); diff --git a/src/mods/multiplayer/NierClient.hpp b/src/mods/multiplayer/NierClient.hpp index ffc2031..e61758c 100644 --- a/src/mods/multiplayer/NierClient.hpp +++ b/src/mods/multiplayer/NierClient.hpp @@ -74,7 +74,7 @@ class NierClient : public enetpp::client { bool handleAnimationStart(const nier::PlayerPacket* packet); bool handleButtons(const nier::PlayerPacket* packet); - EntitySync m_networkEntities{}; + std::unique_ptr m_networkEntities{}; std::recursive_mutex m_mtx{}; std::recursive_mutex m_playersMtx{}; diff --git a/src/mods/multiplayer/schema/Packets_generated.h b/src/mods/multiplayer/schema/Packets_generated.h index 6529191..81c49d6 100644 --- a/src/mods/multiplayer/schema/Packets_generated.h +++ b/src/mods/multiplayer/schema/Packets_generated.h @@ -764,7 +764,8 @@ struct Welcome FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { typedef WelcomeBuilder Builder; enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { VT_GUID = 4, - VT_ISMASTERCLIENT = 6 + VT_ISMASTERCLIENT = 6, + VT_HIGHESTENTITYGUID = 8 }; uint64_t guid() const { return GetField(VT_GUID, 0); @@ -772,10 +773,14 @@ struct Welcome FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { bool isMasterClient() const { return GetField(VT_ISMASTERCLIENT, 0) != 0; } + uint32_t highestEntityGuid() const { + return GetField(VT_HIGHESTENTITYGUID, 0); + } bool Verify(flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && VerifyField(verifier, VT_GUID) && VerifyField(verifier, VT_ISMASTERCLIENT) && + VerifyField(verifier, VT_HIGHESTENTITYGUID) && verifier.EndTable(); } }; @@ -790,6 +795,9 @@ struct WelcomeBuilder { void add_isMasterClient(bool isMasterClient) { fbb_.AddElement(Welcome::VT_ISMASTERCLIENT, static_cast(isMasterClient), 0); } + void add_highestEntityGuid(uint32_t highestEntityGuid) { + fbb_.AddElement(Welcome::VT_HIGHESTENTITYGUID, highestEntityGuid, 0); + } explicit WelcomeBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); @@ -804,9 +812,11 @@ struct WelcomeBuilder { inline flatbuffers::Offset CreateWelcome( flatbuffers::FlatBufferBuilder &_fbb, uint64_t guid = 0, - bool isMasterClient = false) { + bool isMasterClient = false, + uint32_t highestEntityGuid = 0) { WelcomeBuilder builder_(_fbb); builder_.add_guid(guid); + builder_.add_highestEntityGuid(highestEntityGuid); builder_.add_isMasterClient(isMasterClient); return builder_.Finish(); }