diff --git a/common/servertalk.h b/common/servertalk.h index a50e5832a..031885132 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -155,6 +155,8 @@ #define ServerOP_ExpeditionDzSafeReturn 0x040b #define ServerOP_ExpeditionDzZoneIn 0x040c #define ServerOP_ExpeditionRemoveCharLockouts 0x040d +#define ServerOP_ExpeditionSaveInvite 0x040e +#define ServerOP_ExpeditionRequestInvite 0x040f #define ServerOP_DzCharacterChange 0x0450 #define ServerOP_DzRemoveAllCharacters 0x0451 @@ -2057,6 +2059,10 @@ struct ServerExpeditionCharacterName_Struct { char expedition_name[128]; }; +struct ServerExpeditionCharacterID_Struct { + uint32_t character_id; +}; + struct ServerDzCommand_Struct { uint32 expedition_id; uint8 is_char_online; // 0: target name is offline, 1: online diff --git a/world/cliententry.h b/world/cliententry.h index b4d449c58..769700403 100644 --- a/world/cliententry.h +++ b/world/cliententry.h @@ -127,6 +127,9 @@ public: inline void PushToTellQueue(ServerChannelMessage_Struct *scm) { tell_queue.push_back(scm); } void ProcessTellQueue(); + void SetPendingExpeditionInvite(ServerPacket* pack) { p_pending_expedition_invite.reset(pack->Copy()); }; + std::unique_ptr GetPendingExpeditionInvite() { return std::move(p_pending_expedition_invite); } + private: void ClearVars(bool iAll = false); @@ -171,6 +174,8 @@ private: // Tell Queue -- really a vector :D std::vector tell_queue; + + std::unique_ptr p_pending_expedition_invite = nullptr; }; #endif /*CLIENTENTRY_H_*/ diff --git a/world/expedition.cpp b/world/expedition.cpp index 82ff28ba6..fb52a227b 100644 --- a/world/expedition.cpp +++ b/world/expedition.cpp @@ -68,6 +68,44 @@ void Expedition::PurgeExpiredCharacterLockouts() } } +void Expedition::HandleZoneMessage(ServerPacket* pack) +{ + switch (pack->opcode) + { + case ServerOP_ExpeditionGetOnlineMembers: + { + Expedition::GetOnlineMembers(pack); + break; + } + case ServerOP_ExpeditionDzAddPlayer: + { + Expedition::AddPlayer(pack); + break; + } + case ServerOP_ExpeditionDzMakeLeader: + { + Expedition::MakeLeader(pack); + break; + } + case ServerOP_ExpeditionRemoveCharLockouts: + { + auto buf = reinterpret_cast(pack->pBuffer); + client_list.SendPacket(buf->character_name, pack); + break; + } + case ServerOP_ExpeditionSaveInvite: + { + Expedition::SaveInvite(pack); + break; + } + case ServerOP_ExpeditionRequestInvite: + { + Expedition::RequestInvite(pack); + break; + } + } +} + void Expedition::AddPlayer(ServerPacket* pack) { auto buf = reinterpret_cast(pack->pBuffer); @@ -138,3 +176,31 @@ void Expedition::GetOnlineMembers(ServerPacket* pack) zoneserver_list.SendPacket(buf->sender_zone_id, buf->sender_instance_id, pack); } + +void Expedition::SaveInvite(ServerPacket* pack) +{ + auto buf = reinterpret_cast(pack->pBuffer); + + ClientListEntry* invited_cle = client_list.FindCharacter(buf->target_name); + if (invited_cle) + { + // store packet on cle and re-send it when client requests it + buf->is_char_online = true; + pack->opcode = ServerOP_ExpeditionDzAddPlayer; + invited_cle->SetPendingExpeditionInvite(pack); + } +} + +void Expedition::RequestInvite(ServerPacket* pack) +{ + auto buf = reinterpret_cast(pack->pBuffer); + ClientListEntry* cle = client_list.FindCLEByCharacterID(buf->character_id); + if (cle) + { + auto invite_pack = cle->GetPendingExpeditionInvite(); + if (invite_pack && cle->Server()) + { + cle->Server()->SendPacket(invite_pack.get()); + } + } +} diff --git a/world/expedition.h b/world/expedition.h index 2d9346e78..f40cda834 100644 --- a/world/expedition.h +++ b/world/expedition.h @@ -27,9 +27,12 @@ namespace Expedition { void PurgeExpiredExpeditions(); void PurgeExpiredCharacterLockouts(); + void HandleZoneMessage(ServerPacket* pack); void AddPlayer(ServerPacket* pack); void MakeLeader(ServerPacket* pack); void GetOnlineMembers(ServerPacket* pack); + void SaveInvite(ServerPacket* pack); + void RequestInvite(ServerPacket* pack); }; #endif diff --git a/world/zoneserver.cpp b/world/zoneserver.cpp index 35a6e27f0..6f3b1a9e1 100644 --- a/world/zoneserver.cpp +++ b/world/zoneserver.cpp @@ -1383,24 +1383,13 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) { break; } case ServerOP_ExpeditionGetOnlineMembers: - { - Expedition::GetOnlineMembers(pack); - break; - } case ServerOP_ExpeditionDzAddPlayer: - { - Expedition::AddPlayer(pack); - break; - } case ServerOP_ExpeditionDzMakeLeader: - { - Expedition::MakeLeader(pack); - break; - } case ServerOP_ExpeditionRemoveCharLockouts: + case ServerOP_ExpeditionSaveInvite: + case ServerOP_ExpeditionRequestInvite: { - auto buf = reinterpret_cast(pack->pBuffer); - client_list.SendPacket(buf->character_name, pack); + Expedition::HandleZoneMessage(pack); break; } case ServerOP_DzCharacterChange: diff --git a/zone/client.cpp b/zone/client.cpp index 242f57fbe..979eb294b 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -9560,7 +9560,6 @@ void Client::SendCrossZoneMessageString( void Client::UpdateExpeditionInfoAndLockouts() { // this is processed by client after entering a zone - // todo: live re-invites if client zoned with a pending invite window open SendDzCompassUpdate(); auto expedition = GetExpedition(); @@ -9582,6 +9581,9 @@ void Client::UpdateExpeditionInfoAndLockouts() } LoadAllExpeditionLockouts(); + + // ask world for any pending invite we saved from a previous zone + RequestPendingExpeditionInvite(); } Expedition* Client::CreateExpedition(DynamicZone& dz_instance, ExpeditionRequest& request) @@ -9775,6 +9777,15 @@ void Client::SendExpeditionLockoutTimers() QueuePacket(outapp.get()); } +void Client::RequestPendingExpeditionInvite() +{ + uint32_t packsize = sizeof(ServerExpeditionCharacterID_Struct); + auto pack = std::unique_ptr(new ServerPacket(ServerOP_ExpeditionRequestInvite, packsize)); + auto packbuf = reinterpret_cast(pack->pBuffer); + packbuf->character_id = CharacterID(); + worldserver.SendPacket(pack.get()); +} + void Client::DzListTimers() { // only lists player's current replay timer lockouts, not all event lockouts diff --git a/zone/client.h b/zone/client.h index b4d52d228..17f25d70b 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1131,6 +1131,7 @@ public: bool IsInExpedition() const { return m_expedition_id != 0; } void RemoveAllExpeditionLockouts(std::string expedition_name = {}); void RemoveExpeditionLockout(const std::string& expedition_name, const std::string& event_name, bool update_db = false, bool update_client = true); + void RequestPendingExpeditionInvite(); void SendExpeditionLockoutTimers(); void SetExpeditionID(uint32 expedition_id) { m_expedition_id = expedition_id; }; void SetPendingExpeditionInvite(ExpeditionInvite&& invite) { m_pending_expedition_invite = invite; } diff --git a/zone/expedition.cpp b/zone/expedition.cpp index 98fcda966..8adec8008 100644 --- a/zone/expedition.cpp +++ b/zone/expedition.cpp @@ -1269,6 +1269,16 @@ void Expedition::SendClientExpeditionInfo(Client* client) } } +void Expedition::SendWorldPendingInvite(const ExpeditionInvite& invite, const std::string& add_name) +{ + LogExpeditions( + "Character [{}] saving pending invite from [{}] to expedition [{}] in world", + add_name, invite.inviter_name, invite.expedition_id + ); + + SendWorldAddPlayerInvite(invite.inviter_name, invite.swap_remove_name, add_name, true); +} + std::unique_ptr Expedition::CreateInfoPacket(bool clear) { uint32_t outsize = sizeof(ExpeditionInfo_Struct); @@ -1375,10 +1385,11 @@ void Expedition::SendWorldExpeditionUpdate(bool destroyed) } void Expedition::SendWorldAddPlayerInvite( - const std::string& inviter_name, const std::string& swap_remove_name, const std::string& add_name) + const std::string& inviter_name, const std::string& swap_remove_name, const std::string& add_name, bool pending) { + auto server_opcode = pending ? ServerOP_ExpeditionSaveInvite : ServerOP_ExpeditionDzAddPlayer; uint32_t pack_size = sizeof(ServerDzCommand_Struct); - auto pack = std::unique_ptr(new ServerPacket(ServerOP_ExpeditionDzAddPlayer, pack_size)); + auto pack = std::unique_ptr(new ServerPacket(server_opcode, pack_size)); auto buf = reinterpret_cast(pack->pBuffer); buf->expedition_id = GetID(); buf->is_char_online = false; diff --git a/zone/expedition.h b/zone/expedition.h index cf6c9306d..c28e2fa3d 100644 --- a/zone/expedition.h +++ b/zone/expedition.h @@ -115,6 +115,7 @@ public: void RemoveLockout(const std::string& event_name); void SendClientExpeditionInfo(Client* client); + void SendWorldPendingInvite(const ExpeditionInvite& invite, const std::string& add_name); void DzAddPlayer(Client* requester, std::string add_char_name, std::string swap_remove_name = {}); void DzAddPlayerContinue(std::string leader_name, std::string add_char_name, std::string swap_remove_name = {}); @@ -155,7 +156,7 @@ private: void SendWorldDzLocationUpdate(uint16_t server_opcode, const DynamicZoneLocation& location); void SendWorldExpeditionUpdate(bool destroyed = false); void SendWorldGetOnlineMembers(); - void SendWorldAddPlayerInvite(const std::string& inviter_name, const std::string& swap_remove_name, const std::string& add_name); + void SendWorldAddPlayerInvite(const std::string& inviter_name, const std::string& swap_remove_name, const std::string& add_name, bool pending = false); void SendWorldLeaderChanged(); void SendWorldLockoutUpdate(const std::string& event_name, uint64_t expire_time, uint32_t duration, bool remove = false); void SendWorldMakeLeaderRequest(const std::string& requester_name, const std::string& new_leader_name); diff --git a/zone/zoning.cpp b/zone/zoning.cpp index ac8732e82..35dec1ca1 100644 --- a/zone/zoning.cpp +++ b/zone/zoning.cpp @@ -404,6 +404,16 @@ void Client::DoZoneSuccess(ZoneChange_Struct *zc, uint16 zone_id, uint32 instanc if(this->GetPet()) entity_list.RemoveFromHateLists(this->GetPet()); + if (GetPendingExpeditionInviteID() != 0) + { + // live re-invites if client zoned with a pending invite, save pending invite info in world + auto expedition = Expedition::FindCachedExpeditionByID(GetPendingExpeditionInviteID()); + if (expedition) + { + expedition->SendWorldPendingInvite(m_pending_expedition_invite, GetName()); + } + } + LogInfo("Zoning [{}] to: [{}] ([{}]) - ([{}]) x [{}] y [{}] z [{}]", m_pp.name, ZoneName(zone_id), zone_id, instance_id, dest_x, dest_y, dest_z); //set the player's coordinates in the new zone so they have them