Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Expeditions] Track DZ member status in world #1341

Merged
merged 1 commit into from May 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions common/dynamic_zone_base.h
Expand Up @@ -25,6 +25,8 @@ struct DynamicZoneMember
DynamicZoneMember(uint32_t id, std::string name_, DynamicZoneMemberStatus status_)
: id(id), name{std::move(name_)}, status(status_) {}

bool IsOnline() const { return status == DynamicZoneMemberStatus::Online ||
status == DynamicZoneMemberStatus::InDynamicZone; }
bool IsValid() const { return id != 0 && !name.empty(); }
};

Expand Down
25 changes: 25 additions & 0 deletions common/expedition_base.cpp
@@ -1,5 +1,6 @@
#include "expedition_base.h"
#include "repositories/expeditions_repository.h"
#include "rulesys.h"

ExpeditionBase::ExpeditionBase(uint32_t id, const std::string& uuid,
const std::string& expedition_name, const DynamicZoneMember& leader,
Expand Down Expand Up @@ -91,3 +92,27 @@ DynamicZoneMember ExpeditionBase::GetMemberData(const std::string& character_nam
}
return member_data;
}

bool ExpeditionBase::SetInternalMemberStatus(uint32_t character_id, DynamicZoneMemberStatus status)
{
if (status == DynamicZoneMemberStatus::InDynamicZone && !RuleB(Expedition, EnableInDynamicZoneStatus))
{
status = DynamicZoneMemberStatus::Online;
}

if (character_id == m_leader.id)
{
m_leader.status = status;
}

auto it = std::find_if(m_members.begin(), m_members.end(),
[&](const DynamicZoneMember& member) { return member.id == character_id; });

if (it != m_members.end() && it->status != status)
{
it->status = status;
return true;
}

return false;
}
1 change: 1 addition & 0 deletions common/expedition_base.h
Expand Up @@ -33,6 +33,7 @@ class ExpeditionBase
bool HasMember(uint32_t character_id);
bool IsEmpty() const { return m_members.empty(); }
void RemoveInternalMember(uint32_t character_id);
bool SetInternalMemberStatus(uint32_t character_id, DynamicZoneMemberStatus status);

void LoadRepositoryResult(ExpeditionsRepository::ExpeditionWithLeader&& entry);
void AddMemberFromRepositoryResult(ExpeditionMembersRepository::MemberWithName&& entry);
Expand Down
17 changes: 6 additions & 11 deletions common/servertalk.h
Expand Up @@ -148,7 +148,7 @@
#define ServerOP_ExpeditionMemberChange 0x0404
#define ServerOP_ExpeditionMemberSwap 0x0405
#define ServerOP_ExpeditionMemberStatus 0x0406
#define ServerOP_ExpeditionGetOnlineMembers 0x0407
#define ServerOP_ExpeditionGetMemberStatuses 0x0407
#define ServerOP_ExpeditionDzAddPlayer 0x0408
#define ServerOP_ExpeditionDzMakeLeader 0x0409
#define ServerOP_ExpeditionCharacterLockout 0x040d
Expand All @@ -159,7 +159,6 @@
#define ServerOP_ExpeditionMembersRemoved 0x0412
#define ServerOP_ExpeditionLockoutDuration 0x0414
#define ServerOP_ExpeditionExpireWarning 0x0416
#define ServerOP_ExpeditionChooseNewLeader 0x0417

#define ServerOP_DzAddRemoveCharacter 0x0450
#define ServerOP_DzRemoveAllCharacters 0x0451
Expand Down Expand Up @@ -2035,19 +2034,15 @@ struct ServerExpeditionMemberStatus_Struct {
uint32 character_id;
};

struct ServerExpeditionCharacterEntry_Struct {
uint32 expedition_id;
struct ServerExpeditionMemberStatusEntry_Struct {
uint32 character_id;
uint32 character_zone_id;
uint16 character_instance_id;
uint8 character_online; // 0: offline 1: online
uint8 online_status; // 0: unknown 1: Online 2: Offline 3: In Dynamic Zone 4: Link Dead
};

struct ServerExpeditionCharacters_Struct {
uint32 sender_zone_id;
uint16 sender_instance_id;
struct ServerExpeditionMemberStatuses_Struct {
uint32 expedition_id;
uint32 count;
ServerExpeditionCharacterEntry_Struct entries[0];
ServerExpeditionMemberStatusEntry_Struct entries[0];
};

struct ServerExpeditionLockout_Struct {
Expand Down
63 changes: 60 additions & 3 deletions world/expedition.cpp
Expand Up @@ -62,10 +62,8 @@ void Expedition::ChooseNewLeader()
return;
}

// we don't track expedition member status in world so may choose a linkdead member
// this is fine since it will trigger another change when that member goes offline
auto it = std::find_if(m_members.begin(), m_members.end(), [&](const DynamicZoneMember& member) {
if (member.id != m_leader.id) {
if (member.id != m_leader.id && member.IsOnline()) {
auto member_cle = client_list.FindCLEByCharacterID(member.id);
return (member_cle && member_cle->GetOnline() == CLE_Status::InZone);
}
Expand Down Expand Up @@ -171,3 +169,62 @@ bool Expedition::Process()

return false;
}

void Expedition::UpdateMemberStatus(uint32_t character_id, DynamicZoneMemberStatus status)
{
SetInternalMemberStatus(character_id, status);

// any member status update will trigger a leader fix if leader was offline
if (m_leader.status == DynamicZoneMemberStatus::Offline)
{
ChooseNewLeader();
}
}

void Expedition::SendZoneMemberStatuses(uint16_t zone_id, uint16_t instance_id)
{
const auto& members = GetMembers();

uint32_t members_count = static_cast<uint32_t>(members.size());
uint32_t entries_size = sizeof(ServerExpeditionMemberStatusEntry_Struct) * members_count;
uint32_t pack_size = sizeof(ServerExpeditionMemberStatuses_Struct) + entries_size;
auto pack = std::make_unique<ServerPacket>(ServerOP_ExpeditionGetMemberStatuses, pack_size);
auto buf = reinterpret_cast<ServerExpeditionMemberStatuses_Struct*>(pack->pBuffer);
buf->expedition_id = GetID();
buf->count = members_count;

for (int i = 0; i < members.size(); ++i)
{
buf->entries[i].character_id = members[i].id;
buf->entries[i].online_status = static_cast<uint8_t>(members[i].status);
}

zoneserver_list.SendPacket(zone_id, instance_id, pack.get());
}

void Expedition::CacheMemberStatuses()
{
// called when a new expedition is cached to fill member statuses
std::string zone_name{};
std::vector<ClientListEntry*> all_clients;
all_clients.reserve(client_list.GetClientCount());
client_list.GetClients(zone_name.c_str(), all_clients);

for (const auto& member : m_members)
{
auto it = std::find_if(all_clients.begin(), all_clients.end(),
[&](const ClientListEntry* cle) { return (cle && cle->CharID() == member.id); });

auto status = DynamicZoneMemberStatus::Offline;
if (it != all_clients.end())
{
status = DynamicZoneMemberStatus::Online;
if (GetDynamicZone().IsSameDz((*it)->zone(), (*it)->instance()))
{
status = DynamicZoneMemberStatus::InDynamicZone;
}
}

SetInternalMemberStatus(member.id, status);
}
}
4 changes: 3 additions & 1 deletion world/expedition.h
Expand Up @@ -32,16 +32,18 @@ class Expedition : public ExpeditionBase
Expedition();

void RemoveMember(uint32_t character_id);
void CacheMemberStatuses();
void CheckExpireWarning();
void CheckLeader();
void ChooseNewLeader();
DynamicZone& GetDynamicZone() { return m_dynamic_zone; }
bool Process();

void SendZoneMemberStatuses(uint16_t zone_id, uint16_t instance_id);
void SendZonesExpeditionDeleted();
void SendZonesExpireWarning(uint32_t minutes_remaining);
void SetDynamicZone(DynamicZone&& dz);
bool SetNewLeader(const DynamicZoneMember& member);
void UpdateMemberStatus(uint32_t character_id, DynamicZoneMemberStatus status);

private:
void SendZonesLeaderChanged();
Expand Down
58 changes: 19 additions & 39 deletions world/expedition_message.cpp
Expand Up @@ -35,11 +35,6 @@ void ExpeditionMessage::HandleZoneMessage(ServerPacket* pack)
{
switch (pack->opcode)
{
case ServerOP_ExpeditionChooseNewLeader:
{
ExpeditionMessage::ChooseNewLeader(pack);
break;
}
case ServerOP_ExpeditionCreate:
{
auto buf = reinterpret_cast<ServerExpeditionID_Struct*>(pack->pBuffer);
Expand Down Expand Up @@ -69,9 +64,21 @@ void ExpeditionMessage::HandleZoneMessage(ServerPacket* pack)
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_ExpeditionGetOnlineMembers:
case ServerOP_ExpeditionMemberStatus:
{
auto buf = reinterpret_cast<ServerExpeditionMemberStatus_Struct*>(pack->pBuffer);
auto expedition = expedition_state.GetExpedition(buf->expedition_id);
if (expedition)
{
auto status = static_cast<DynamicZoneMemberStatus>(buf->status);
expedition->UpdateMemberStatus(buf->character_id, status);
}
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_ExpeditionGetMemberStatuses:
{
ExpeditionMessage::GetOnlineMembers(pack);
ExpeditionMessage::GetMemberStatuses(pack);
break;
}
case ServerOP_ExpeditionDzAddPlayer:
Expand Down Expand Up @@ -157,31 +164,14 @@ void ExpeditionMessage::MakeLeader(ServerPacket* pack)
}
}

void ExpeditionMessage::GetOnlineMembers(ServerPacket* pack)
void ExpeditionMessage::GetMemberStatuses(ServerPacket* pack)
{
auto buf = reinterpret_cast<ServerExpeditionCharacters_Struct*>(pack->pBuffer);

// not efficient but only requested during caching
char zone_name[64] = {0};
std::vector<ClientListEntry*> all_clients;
all_clients.reserve(client_list.GetClientCount());
client_list.GetClients(zone_name, all_clients);

for (uint32_t i = 0; i < buf->count; ++i)
auto buf = reinterpret_cast<ServerExpeditionID_Struct*>(pack->pBuffer);
auto expedition = expedition_state.GetExpedition(buf->expedition_id);
if (expedition)
{
auto it = std::find_if(all_clients.begin(), all_clients.end(), [&](const ClientListEntry* cle) {
return (cle && cle->CharID() == buf->entries[i].character_id);
});

if (it != all_clients.end())
{
buf->entries[i].character_zone_id = (*it)->zone();
buf->entries[i].character_instance_id = (*it)->instance();
buf->entries[i].character_online = true;
}
expedition->SendZoneMemberStatuses(buf->sender_zone_id, buf->sender_instance_id);
}

zoneserver_list.SendPacket(buf->sender_zone_id, buf->sender_instance_id, pack);
}

void ExpeditionMessage::SaveInvite(ServerPacket* pack)
Expand Down Expand Up @@ -211,13 +201,3 @@ void ExpeditionMessage::RequestInvite(ServerPacket* pack)
}
}
}

void ExpeditionMessage::ChooseNewLeader(ServerPacket* pack)
{
auto buf = reinterpret_cast<ServerExpeditionID_Struct*>(pack->pBuffer);
auto expedition = expedition_state.GetExpedition(buf->expedition_id);
if (expedition)
{
expedition->ChooseNewLeader();
}
}
3 changes: 1 addition & 2 deletions world/expedition_message.h
Expand Up @@ -26,8 +26,7 @@ class ServerPacket;
namespace ExpeditionMessage
{
void AddPlayer(ServerPacket* pack);
void ChooseNewLeader(ServerPacket* pack);
void GetOnlineMembers(ServerPacket* pack);
void GetMemberStatuses(ServerPacket* pack);
void HandleZoneMessage(ServerPacket* pack);
void MakeLeader(ServerPacket* pack);
void RequestInvite(ServerPacket* pack);
Expand Down
2 changes: 2 additions & 0 deletions world/expedition_state.cpp
Expand Up @@ -110,6 +110,8 @@ void ExpeditionState::CacheExpeditions(
}
}

expedition->CacheMemberStatuses();

m_expeditions.emplace_back(std::move(expedition));
}
}
Expand Down
5 changes: 2 additions & 3 deletions world/zoneserver.cpp
Expand Up @@ -1366,17 +1366,16 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
case ServerOP_ExpeditionLockout:
case ServerOP_ExpeditionLockoutDuration:
case ServerOP_ExpeditionLockState:
case ServerOP_ExpeditionMemberStatus:
case ServerOP_ExpeditionReplayOnJoin:
case ServerOP_ExpeditionExpireWarning:
{
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_ExpeditionChooseNewLeader:
case ServerOP_ExpeditionCreate:
case ServerOP_ExpeditionGetOnlineMembers:
case ServerOP_ExpeditionGetMemberStatuses:
case ServerOP_ExpeditionMemberChange:
case ServerOP_ExpeditionMemberStatus:
case ServerOP_ExpeditionMemberSwap:
case ServerOP_ExpeditionMembersRemoved:
case ServerOP_ExpeditionDzAddPlayer:
Expand Down