diff --git a/common/servertalk.h b/common/servertalk.h index bddee1586..3680ac76d 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -196,6 +196,7 @@ #define ServerOP_DzSaveInvite 0x0466 #define ServerOP_DzRequestInvite 0x0467 #define ServerOP_DzMakeLeader 0x0468 +#define ServerOP_DzGetBulkMemberStatuses 0x0469 #define ServerOP_LSInfo 0x1000 #define ServerOP_LSStatus 0x1001 @@ -1555,6 +1556,13 @@ struct ServerDzMemberStatuses_Struct { ServerDzMemberStatusEntry_Struct entries[0]; }; +struct ServerDzCerealData_Struct { + uint16_t zone_id; + uint16_t inst_id; + uint32_t cereal_size; + char cereal_data[1]; +}; + struct ServerDzMovePC_Struct { uint32 dz_id; uint16 sender_zone_id; diff --git a/world/dynamic_zone_manager.cpp b/world/dynamic_zone_manager.cpp index 6e7e2d68e..18263f996 100644 --- a/world/dynamic_zone_manager.cpp +++ b/world/dynamic_zone_manager.cpp @@ -7,6 +7,7 @@ #include "zoneserver.h" #include "../common/rulesys.h" #include "../common/repositories/dynamic_zone_lockouts_repository.h" +#include extern ClientList client_list; extern ZSList zoneserver_list; @@ -169,6 +170,33 @@ void DynamicZoneManager::LoadTemplates() } } +void DynamicZoneManager::SendBulkMemberStatuses(uint32_t zone_id, uint16_t inst_id) +{ + std::vector>> dzs; + dzs.reserve(dynamic_zone_cache.size()); + + for (const auto& [dz_id, dz] : dynamic_zone_cache) + { + dzs.emplace_back(dz_id, dz->GetMembers()); + } + + std::ostringstream ss; + { + cereal::BinaryOutputArchive archive(ss); + archive(dzs); + } + + std::string_view sv = ss.view(); + + size_t size = sizeof(ServerDzCerealData_Struct) + sv.size(); + ServerPacket pack(ServerOP_DzGetBulkMemberStatuses, static_cast(size)); + auto buf = reinterpret_cast(pack.pBuffer); + buf->cereal_size = static_cast(sv.size()); + memcpy(buf->cereal_data, sv.data(), sv.size()); + + zoneserver_list.SendPacket(zone_id, inst_id, &pack); +} + void DynamicZoneManager::HandleZoneMessage(ServerPacket* pack) { switch (pack->opcode) @@ -338,6 +366,15 @@ void DynamicZoneManager::HandleZoneMessage(ServerPacket* pack) } break; } + case ServerOP_DzGetBulkMemberStatuses: + { + auto buf = reinterpret_cast(pack->pBuffer); + if (buf->zone_id != 0 && !dynamic_zone_cache.empty()) + { + SendBulkMemberStatuses(buf->zone_id, buf->inst_id); + } + break; + } case ServerOP_DzUpdateMemberStatus: { auto buf = reinterpret_cast(pack->pBuffer); diff --git a/world/dynamic_zone_manager.h b/world/dynamic_zone_manager.h index 7b85957dc..0e7077639 100644 --- a/world/dynamic_zone_manager.h +++ b/world/dynamic_zone_manager.h @@ -30,6 +30,8 @@ public: std::unordered_map> dynamic_zone_cache; private: + void SendBulkMemberStatuses(uint32_t zone_id, uint16_t inst_id); + Timer m_process_throttle_timer{}; std::unordered_map m_dz_templates; }; diff --git a/world/zoneserver.cpp b/world/zoneserver.cpp index 94c605436..8c535cedd 100644 --- a/world/zoneserver.cpp +++ b/world/zoneserver.cpp @@ -1480,6 +1480,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) { case ServerOP_DzSwapMembers: case ServerOP_DzRemoveAllMembers: case ServerOP_DzGetMemberStatuses: + case ServerOP_DzGetBulkMemberStatuses: case ServerOP_DzSetSecondsRemaining: case ServerOP_DzSetCompass: case ServerOP_DzSetSafeReturn: diff --git a/zone/dynamic_zone.cpp b/zone/dynamic_zone.cpp index b8ac6ab4e..e6e993bc2 100644 --- a/zone/dynamic_zone.cpp +++ b/zone/dynamic_zone.cpp @@ -25,6 +25,7 @@ #include "worldserver.h" #include "../common/repositories/character_expedition_lockouts_repository.h" #include "../common/repositories/dynamic_zone_lockouts_repository.h" +#include extern WorldServer worldserver; @@ -162,14 +163,28 @@ void DynamicZone::CacheAllFromDatabase() } } - dz->UpdateMembers(); zone->dynamic_zone_cache.emplace(dz_id, std::move(dz)); } + if (!zone->dynamic_zone_cache.empty()) + { + RequestMemberStatuses(); + } + LogInfo("Loaded [{}] dynamic zone(s)", Strings::Commify(zone->dynamic_zone_cache.size())); LogDynamicZones("Caching [{}] dynamic zone(s) took [{}s]", zone->dynamic_zone_cache.size(), bench.elapsed()); } +void DynamicZone::RequestMemberStatuses() +{ + ServerPacket pack(ServerOP_DzGetBulkMemberStatuses, sizeof(ServerDzCerealData_Struct)); + auto buf = reinterpret_cast(pack.pBuffer); + buf->zone_id = static_cast(zone->GetZoneID()); + buf->inst_id = static_cast(zone->GetInstanceID()); + + worldserver.SendPacket(&pack); +} + template DynamicZone* FindDynamicZone(T pred) { @@ -849,6 +864,34 @@ void DynamicZone::HandleWorldMessage(ServerPacket* pack) } break; } + case ServerOP_DzGetBulkMemberStatuses: + { + if (zone) + { + std::vector>> dzs; + dzs.reserve(zone->dynamic_zone_cache.size()); + + auto buf = reinterpret_cast(pack->pBuffer); + EQ::Util::MemoryStreamReader ss(buf->cereal_data, buf->cereal_size); + { + cereal::BinaryInputArchive archive(ss); + archive(dzs); + } + + for (const auto& [dz_id, members] : dzs) + { + if (auto dz = DynamicZone::FindDynamicZoneByID(dz_id)) + { + for (const auto& member : members) + { + dz->SetInternalMemberStatus(member.id, member.status); + } + dz->m_has_member_statuses = true; + } + } + } + break; + } case ServerOP_DzUpdateMemberStatus: { auto buf = reinterpret_cast(pack->pBuffer); diff --git a/zone/dynamic_zone.h b/zone/dynamic_zone.h index 2aeaca30c..82d82263f 100644 --- a/zone/dynamic_zone.h +++ b/zone/dynamic_zone.h @@ -92,13 +92,13 @@ public: void SendMemberNameToZoneMembers(const std::string& char_name, bool remove); void SendMemberStatusToZoneMembers(const DynamicZoneMember& member); void SetLocked(bool lock, bool update_db = false, DzLockMsg lock_msg = DzLockMsg::None, uint32_t color = Chat::Yellow); - void UpdateMembers(); std::string GetLootEvent(uint32_t id, DzLootEvent::Type type) const; void SetLootEvent(uint32_t id, const std::string& event, DzLootEvent::Type type); private: static void StartAllClientRemovalTimers(); + static void RequestMemberStatuses(); uint16_t GetCurrentInstanceID() const override; uint16_t GetCurrentZoneID() const override; @@ -125,6 +125,7 @@ private: void SendWorldPlayerInvite(const std::string& inviter, const std::string& swap_name, const std::string& add_name, bool pending = false); void SetUpdatedDuration(uint32_t seconds); void TryAddClient(Client* add_client, const std::string& inviter, const std::string& swap_name, Client* leader = nullptr); + void UpdateMembers(); std::unique_ptr CreateExpireWarningPacket(uint32_t minutes_remaining); std::unique_ptr CreateInfoPacket(bool clear = false); diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index d9f2c6a56..46e719e9f 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -3410,6 +3410,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) case ServerOP_DzRemoveAllMembers: case ServerOP_DzDurationUpdate: case ServerOP_DzGetMemberStatuses: + case ServerOP_DzGetBulkMemberStatuses: case ServerOP_DzSetCompass: case ServerOP_DzSetSafeReturn: case ServerOP_DzSetZoneIn: