mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-13 23:01:30 +00:00
Let world handle expedition leader changes
This should eliminate race conditions caused by zones trying to set a leader when members in different zones quit at the same time Zone still detects when leader goes offline to trigger a change since it's easier than having world process expedition member status updates and perform expedition lookups
This commit is contained in:
parent
955cbeb826
commit
6acfc41778
@ -164,6 +164,7 @@
|
|||||||
#define ServerOP_ExpeditionLockoutDuration 0x0414
|
#define ServerOP_ExpeditionLockoutDuration 0x0414
|
||||||
#define ServerOP_ExpeditionSecondsRemaining 0x0415
|
#define ServerOP_ExpeditionSecondsRemaining 0x0415
|
||||||
#define ServerOP_ExpeditionExpireWarning 0x0416
|
#define ServerOP_ExpeditionExpireWarning 0x0416
|
||||||
|
#define ServerOP_ExpeditionChooseNewLeader 0x0417
|
||||||
|
|
||||||
#define ServerOP_DzCharacterChange 0x0450
|
#define ServerOP_DzCharacterChange 0x0450
|
||||||
#define ServerOP_DzRemoveAllCharacters 0x0451
|
#define ServerOP_DzRemoveAllCharacters 0x0451
|
||||||
@ -2001,6 +2002,11 @@ struct ServerExpeditionID_Struct {
|
|||||||
uint32 sender_instance_id;
|
uint32 sender_instance_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ServerExpeditionLeaderID_Struct {
|
||||||
|
uint32 expedition_id;
|
||||||
|
uint32 leader_id;
|
||||||
|
};
|
||||||
|
|
||||||
struct ServerExpeditionMemberChange_Struct {
|
struct ServerExpeditionMemberChange_Struct {
|
||||||
uint32 expedition_id;
|
uint32 expedition_id;
|
||||||
uint32 sender_zone_id;
|
uint32 sender_zone_id;
|
||||||
|
|||||||
@ -20,26 +20,83 @@
|
|||||||
|
|
||||||
#include "expedition.h"
|
#include "expedition.h"
|
||||||
#include "expedition_database.h"
|
#include "expedition_database.h"
|
||||||
|
#include "cliententry.h"
|
||||||
|
#include "clientlist.h"
|
||||||
#include "zonelist.h"
|
#include "zonelist.h"
|
||||||
#include "zoneserver.h"
|
#include "zoneserver.h"
|
||||||
#include "../common/eqemu_logsys.h"
|
#include "../common/eqemu_logsys.h"
|
||||||
|
|
||||||
|
extern ClientList client_list;
|
||||||
extern ZSList zoneserver_list;
|
extern ZSList zoneserver_list;
|
||||||
|
|
||||||
Expedition::Expedition(uint32_t expedition_id, uint32_t dz_id, uint32_t dz_instance_id,
|
Expedition::Expedition(uint32_t expedition_id, uint32_t dz_id, uint32_t dz_instance_id,
|
||||||
uint32_t dz_zone_id, uint32_t start_time, uint32_t duration
|
uint32_t dz_zone_id, uint32_t start_time, uint32_t duration, uint32_t leader_id
|
||||||
) :
|
) :
|
||||||
m_expedition_id(expedition_id),
|
m_expedition_id(expedition_id),
|
||||||
m_dz_id(dz_id),
|
m_dz_id(dz_id),
|
||||||
m_dz_instance_id(dz_instance_id),
|
m_dz_instance_id(dz_instance_id),
|
||||||
m_dz_zone_id(dz_zone_id),
|
m_dz_zone_id(dz_zone_id),
|
||||||
m_start_time(std::chrono::system_clock::from_time_t(start_time)),
|
m_start_time(std::chrono::system_clock::from_time_t(start_time)),
|
||||||
m_duration(duration)
|
m_duration(duration),
|
||||||
|
m_leader_id(leader_id)
|
||||||
{
|
{
|
||||||
m_expire_time = m_start_time + m_duration;
|
m_expire_time = m_start_time + m_duration;
|
||||||
m_warning_cooldown_timer.Enable();
|
m_warning_cooldown_timer.Enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Expedition::AddMember(uint32_t character_id)
|
||||||
|
{
|
||||||
|
auto it = std::find_if(m_member_ids.begin(), m_member_ids.end(),
|
||||||
|
[&](uint32_t member_id) { return member_id == character_id; });
|
||||||
|
|
||||||
|
if (it == m_member_ids.end())
|
||||||
|
{
|
||||||
|
m_member_ids.emplace_back(character_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Expedition::RemoveMember(uint32_t character_id)
|
||||||
|
{
|
||||||
|
m_member_ids.erase(std::remove_if(m_member_ids.begin(), m_member_ids.end(),
|
||||||
|
[&](uint32_t member_id) { return member_id == character_id; }
|
||||||
|
), m_member_ids.end());
|
||||||
|
|
||||||
|
if (!m_member_ids.empty() && character_id == m_leader_id)
|
||||||
|
{
|
||||||
|
ChooseNewLeader();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Expedition::ChooseNewLeader()
|
||||||
|
{
|
||||||
|
// 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_member_ids.begin(), m_member_ids.end(), [&](uint32_t member_id) {
|
||||||
|
auto member_cle = (member_id != m_leader_id) ? client_list.FindCLEByCharacterID(member_id) : nullptr;
|
||||||
|
return (member_id != m_leader_id && member_cle && member_cle->GetOnline() == CLE_Status::InZone);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (it == m_member_ids.end())
|
||||||
|
{
|
||||||
|
// no online members found, fallback to choosing any member
|
||||||
|
it = std::find_if(m_member_ids.begin(), m_member_ids.end(),
|
||||||
|
[&](uint32_t member_id) { return (member_id != m_leader_id); });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it != m_member_ids.end())
|
||||||
|
{
|
||||||
|
SetNewLeader(*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Expedition::SetNewLeader(uint32_t character_id)
|
||||||
|
{
|
||||||
|
LogExpeditionsModerate("Replacing [{}] leader [{}] with [{}]", m_expedition_id, m_leader_id, character_id);
|
||||||
|
ExpeditionDatabase::UpdateLeaderID(m_expedition_id, character_id);
|
||||||
|
m_leader_id = character_id;
|
||||||
|
SendZonesLeaderChanged();
|
||||||
|
}
|
||||||
|
|
||||||
void Expedition::SendZonesExpeditionDeleted()
|
void Expedition::SendZonesExpeditionDeleted()
|
||||||
{
|
{
|
||||||
uint32_t pack_size = sizeof(ServerExpeditionID_Struct);
|
uint32_t pack_size = sizeof(ServerExpeditionID_Struct);
|
||||||
@ -69,6 +126,16 @@ void Expedition::SendZonesExpireWarning(uint32_t minutes_remaining)
|
|||||||
zoneserver_list.SendPacket(pack.get());
|
zoneserver_list.SendPacket(pack.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Expedition::SendZonesLeaderChanged()
|
||||||
|
{
|
||||||
|
uint32_t pack_size = sizeof(ServerExpeditionLeaderID_Struct);
|
||||||
|
auto pack = std::unique_ptr<ServerPacket>(new ServerPacket(ServerOP_ExpeditionLeaderChanged, pack_size));
|
||||||
|
auto buf = reinterpret_cast<ServerExpeditionLeaderID_Struct*>(pack->pBuffer);
|
||||||
|
buf->expedition_id = GetID();
|
||||||
|
buf->leader_id = m_leader_id;
|
||||||
|
zoneserver_list.SendPacket(pack.get());
|
||||||
|
}
|
||||||
|
|
||||||
void Expedition::UpdateDzSecondsRemaining(uint32_t seconds_remaining)
|
void Expedition::UpdateDzSecondsRemaining(uint32_t seconds_remaining)
|
||||||
{
|
{
|
||||||
auto now = std::chrono::system_clock::now();
|
auto now = std::chrono::system_clock::now();
|
||||||
|
|||||||
@ -24,19 +24,20 @@
|
|||||||
#include "../common/timer.h"
|
#include "../common/timer.h"
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <unordered_set>
|
#include <vector>
|
||||||
|
|
||||||
class Expedition
|
class Expedition
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Expedition() = default;
|
Expedition() = default;
|
||||||
Expedition(uint32_t expedition_id, uint32_t dz_id, uint32_t dz_instance_id,
|
Expedition(uint32_t expedition_id, uint32_t dz_id, uint32_t dz_instance_id,
|
||||||
uint32_t dz_zone_id, uint32_t expire_time, uint32_t duration);
|
uint32_t dz_zone_id, uint32_t expire_time, uint32_t duration, uint32_t leader_id);
|
||||||
|
|
||||||
void AddMember(uint32_t character_id) { m_member_ids.emplace(character_id); }
|
void AddMember(uint32_t character_id);
|
||||||
void RemoveMember(uint32_t character_id) { m_member_ids.erase(character_id); }
|
void RemoveMember(uint32_t character_id);
|
||||||
void RemoveAllMembers() { m_member_ids.clear(); }
|
void RemoveAllMembers() { m_member_ids.clear(); }
|
||||||
void CheckExpireWarning();
|
void CheckExpireWarning();
|
||||||
|
void ChooseNewLeader();
|
||||||
uint32_t GetID() const { return m_expedition_id; }
|
uint32_t GetID() const { return m_expedition_id; }
|
||||||
uint16_t GetInstanceID() const { return static_cast<uint16_t>(m_dz_instance_id); }
|
uint16_t GetInstanceID() const { return static_cast<uint16_t>(m_dz_instance_id); }
|
||||||
uint16_t GetZoneID() const { return static_cast<uint16_t>(m_dz_zone_id); }
|
uint16_t GetZoneID() const { return static_cast<uint16_t>(m_dz_zone_id); }
|
||||||
@ -47,18 +48,22 @@ public:
|
|||||||
void SendZonesDurationUpdate();
|
void SendZonesDurationUpdate();
|
||||||
void SendZonesExpeditionDeleted();
|
void SendZonesExpeditionDeleted();
|
||||||
void SendZonesExpireWarning(uint32_t minutes_remaining);
|
void SendZonesExpireWarning(uint32_t minutes_remaining);
|
||||||
|
void SetNewLeader(uint32_t new_leader_id);
|
||||||
void SetPendingDelete(bool pending) { m_pending_delete = pending; }
|
void SetPendingDelete(bool pending) { m_pending_delete = pending; }
|
||||||
void UpdateDzSecondsRemaining(uint32_t seconds_remaining);
|
void UpdateDzSecondsRemaining(uint32_t seconds_remaining);
|
||||||
std::chrono::system_clock::duration GetRemainingDuration() const;
|
std::chrono::system_clock::duration GetRemainingDuration() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void SendZonesLeaderChanged();
|
||||||
|
|
||||||
uint32_t m_expedition_id = 0;
|
uint32_t m_expedition_id = 0;
|
||||||
uint32_t m_dz_id = 0;
|
uint32_t m_dz_id = 0;
|
||||||
uint32_t m_dz_instance_id = 0;
|
uint32_t m_dz_instance_id = 0;
|
||||||
uint32_t m_dz_zone_id = 0;
|
uint32_t m_dz_zone_id = 0;
|
||||||
|
uint32_t m_leader_id = 0;
|
||||||
bool m_pending_delete = false;
|
bool m_pending_delete = false;
|
||||||
Timer m_warning_cooldown_timer;
|
Timer m_warning_cooldown_timer;
|
||||||
std::unordered_set<uint32_t> m_member_ids;
|
std::vector<uint32_t> m_member_ids;
|
||||||
std::chrono::seconds m_duration;
|
std::chrono::seconds m_duration;
|
||||||
std::chrono::time_point<std::chrono::system_clock> m_start_time;
|
std::chrono::time_point<std::chrono::system_clock> m_start_time;
|
||||||
std::chrono::time_point<std::chrono::system_clock> m_expire_time;
|
std::chrono::time_point<std::chrono::system_clock> m_expire_time;
|
||||||
|
|||||||
@ -77,6 +77,7 @@ std::vector<Expedition> ExpeditionDatabase::LoadExpeditions(uint32_t select_expe
|
|||||||
instance_list.zone,
|
instance_list.zone,
|
||||||
instance_list.start_time,
|
instance_list.start_time,
|
||||||
instance_list.duration,
|
instance_list.duration,
|
||||||
|
expeditions.leader_id,
|
||||||
expedition_members.character_id
|
expedition_members.character_id
|
||||||
FROM expeditions
|
FROM expeditions
|
||||||
INNER JOIN dynamic_zones ON expeditions.dynamic_zone_id = dynamic_zones.id
|
INNER JOIN dynamic_zones ON expeditions.dynamic_zone_id = dynamic_zones.id
|
||||||
@ -110,13 +111,14 @@ std::vector<Expedition> ExpeditionDatabase::LoadExpeditions(uint32_t select_expe
|
|||||||
static_cast<uint32_t>(strtoul(row[2], nullptr, 10)), // dz_instance_id
|
static_cast<uint32_t>(strtoul(row[2], nullptr, 10)), // dz_instance_id
|
||||||
static_cast<uint32_t>(strtoul(row[3], nullptr, 10)), // dz_zone_id
|
static_cast<uint32_t>(strtoul(row[3], nullptr, 10)), // dz_zone_id
|
||||||
static_cast<uint32_t>(strtoul(row[4], nullptr, 10)), // start_time
|
static_cast<uint32_t>(strtoul(row[4], nullptr, 10)), // start_time
|
||||||
static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) // duration
|
static_cast<uint32_t>(strtoul(row[5], nullptr, 10)), // duration
|
||||||
|
static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) // leader_id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
last_expedition_id = expedition_id;
|
last_expedition_id = expedition_id;
|
||||||
|
|
||||||
uint32_t member_id = static_cast<uint32_t>(strtoul(row[6], nullptr, 10));
|
uint32_t member_id = static_cast<uint32_t>(strtoul(row[7], nullptr, 10));
|
||||||
expeditions.back().AddMember(member_id);
|
expeditions.back().AddMember(member_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -167,3 +169,14 @@ void ExpeditionDatabase::UpdateDzDuration(uint16_t instance_id, uint32_t new_dur
|
|||||||
|
|
||||||
database.QueryDatabase(query);
|
database.QueryDatabase(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ExpeditionDatabase::UpdateLeaderID(uint32_t expedition_id, uint32_t leader_id)
|
||||||
|
{
|
||||||
|
LogExpeditionsDetail("Updating leader [{}] for expedition [{}]", leader_id, expedition_id);
|
||||||
|
|
||||||
|
auto query = fmt::format(SQL(
|
||||||
|
UPDATE expeditions SET leader_id = {} WHERE id = {};
|
||||||
|
), leader_id, expedition_id);
|
||||||
|
|
||||||
|
database.QueryDatabase(query);
|
||||||
|
}
|
||||||
|
|||||||
@ -34,6 +34,7 @@ namespace ExpeditionDatabase
|
|||||||
void PurgeExpiredExpeditions();
|
void PurgeExpiredExpeditions();
|
||||||
void PurgeExpiredCharacterLockouts();
|
void PurgeExpiredCharacterLockouts();
|
||||||
void UpdateDzDuration(uint16_t instance_id, uint32_t new_duration);
|
void UpdateDzDuration(uint16_t instance_id, uint32_t new_duration);
|
||||||
|
void UpdateLeaderID(uint32_t expedition_id, uint32_t leader_id);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -18,6 +18,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "expedition.h"
|
||||||
#include "expedition_message.h"
|
#include "expedition_message.h"
|
||||||
#include "expedition_state.h"
|
#include "expedition_state.h"
|
||||||
#include "cliententry.h"
|
#include "cliententry.h"
|
||||||
@ -34,6 +35,11 @@ void ExpeditionMessage::HandleZoneMessage(ServerPacket* pack)
|
|||||||
{
|
{
|
||||||
switch (pack->opcode)
|
switch (pack->opcode)
|
||||||
{
|
{
|
||||||
|
case ServerOP_ExpeditionChooseNewLeader:
|
||||||
|
{
|
||||||
|
ExpeditionMessage::ChooseNewLeader(pack);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case ServerOP_ExpeditionCreate:
|
case ServerOP_ExpeditionCreate:
|
||||||
{
|
{
|
||||||
auto buf = reinterpret_cast<ServerExpeditionID_Struct*>(pack->pBuffer);
|
auto buf = reinterpret_cast<ServerExpeditionID_Struct*>(pack->pBuffer);
|
||||||
@ -51,8 +57,8 @@ void ExpeditionMessage::HandleZoneMessage(ServerPacket* pack)
|
|||||||
case ServerOP_ExpeditionMemberSwap:
|
case ServerOP_ExpeditionMemberSwap:
|
||||||
{
|
{
|
||||||
auto buf = reinterpret_cast<ServerExpeditionMemberSwap_Struct*>(pack->pBuffer);
|
auto buf = reinterpret_cast<ServerExpeditionMemberSwap_Struct*>(pack->pBuffer);
|
||||||
expedition_state.MemberChange(buf->expedition_id, buf->remove_char_id, true);
|
|
||||||
expedition_state.MemberChange(buf->expedition_id, buf->add_char_id, false);
|
expedition_state.MemberChange(buf->expedition_id, buf->add_char_id, false);
|
||||||
|
expedition_state.MemberChange(buf->expedition_id, buf->remove_char_id, true);
|
||||||
zoneserver_list.SendPacket(pack);
|
zoneserver_list.SendPacket(pack);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -141,6 +147,12 @@ void ExpeditionMessage::MakeLeader(ServerPacket* pack)
|
|||||||
buf->is_char_online = true;
|
buf->is_char_online = true;
|
||||||
new_leader_zs = new_leader_cle->Server();
|
new_leader_zs = new_leader_cle->Server();
|
||||||
new_leader_zs->SendPacket(pack);
|
new_leader_zs->SendPacket(pack);
|
||||||
|
|
||||||
|
auto expedition = expedition_state.GetExpedition(buf->expedition_id);
|
||||||
|
if (expedition)
|
||||||
|
{
|
||||||
|
expedition->SetNewLeader(new_leader_cle->CharID());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if old and new leader are in the same zone only send one message
|
// if old and new leader are in the same zone only send one message
|
||||||
@ -205,3 +217,13 @@ 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -26,6 +26,7 @@ class ServerPacket;
|
|||||||
namespace ExpeditionMessage
|
namespace ExpeditionMessage
|
||||||
{
|
{
|
||||||
void AddPlayer(ServerPacket* pack);
|
void AddPlayer(ServerPacket* pack);
|
||||||
|
void ChooseNewLeader(ServerPacket* pack);
|
||||||
void GetOnlineMembers(ServerPacket* pack);
|
void GetOnlineMembers(ServerPacket* pack);
|
||||||
void HandleZoneMessage(ServerPacket* pack);
|
void HandleZoneMessage(ServerPacket* pack);
|
||||||
void MakeLeader(ServerPacket* pack);
|
void MakeLeader(ServerPacket* pack);
|
||||||
|
|||||||
@ -30,6 +30,14 @@ extern ZSList zoneserver_list;
|
|||||||
|
|
||||||
ExpeditionState expedition_state;
|
ExpeditionState expedition_state;
|
||||||
|
|
||||||
|
Expedition* ExpeditionState::GetExpedition(uint32_t expedition_id)
|
||||||
|
{
|
||||||
|
auto it = std::find_if(m_expeditions.begin(), m_expeditions.end(),
|
||||||
|
[&](const Expedition& expedition) { return expedition.GetID() == expedition_id; });
|
||||||
|
|
||||||
|
return (it != m_expeditions.end()) ? &(*it) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void ExpeditionState::LoadActiveExpeditions()
|
void ExpeditionState::LoadActiveExpeditions()
|
||||||
{
|
{
|
||||||
BenchTimer benchmark;
|
BenchTimer benchmark;
|
||||||
@ -51,11 +59,8 @@ void ExpeditionState::AddExpedition(uint32_t expedition_id)
|
|||||||
|
|
||||||
if (expedition.IsValid())
|
if (expedition.IsValid())
|
||||||
{
|
{
|
||||||
auto it = std::find_if(m_expeditions.begin(), m_expeditions.end(), [&](const Expedition& expedition) {
|
auto existing_expedition = GetExpedition(expedition_id);
|
||||||
return expedition.GetID() == expedition_id;
|
if (!existing_expedition)
|
||||||
});
|
|
||||||
|
|
||||||
if (it == m_expeditions.end())
|
|
||||||
{
|
{
|
||||||
m_expeditions.emplace_back(expedition);
|
m_expeditions.emplace_back(expedition);
|
||||||
}
|
}
|
||||||
@ -73,41 +78,32 @@ void ExpeditionState::RemoveExpedition(uint32_t expedition_id)
|
|||||||
|
|
||||||
void ExpeditionState::MemberChange(uint32_t expedition_id, uint32_t character_id, bool remove)
|
void ExpeditionState::MemberChange(uint32_t expedition_id, uint32_t character_id, bool remove)
|
||||||
{
|
{
|
||||||
auto it = std::find_if(m_expeditions.begin(), m_expeditions.end(), [&](const Expedition& expedition) {
|
auto expedition = GetExpedition(expedition_id);
|
||||||
return expedition.GetID() == expedition_id;
|
if (expedition)
|
||||||
});
|
|
||||||
|
|
||||||
if (it != m_expeditions.end())
|
|
||||||
{
|
{
|
||||||
if (remove) {
|
if (remove) {
|
||||||
it->RemoveMember(character_id);
|
expedition->RemoveMember(character_id);
|
||||||
} else {
|
} else {
|
||||||
it->AddMember(character_id);
|
expedition->AddMember(character_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExpeditionState::RemoveAllMembers(uint32_t expedition_id)
|
void ExpeditionState::RemoveAllMembers(uint32_t expedition_id)
|
||||||
{
|
{
|
||||||
auto it = std::find_if(m_expeditions.begin(), m_expeditions.end(), [&](const Expedition& expedition) {
|
auto expedition = GetExpedition(expedition_id);
|
||||||
return expedition.GetID() == expedition_id;
|
if (expedition)
|
||||||
});
|
|
||||||
|
|
||||||
if (it != m_expeditions.end())
|
|
||||||
{
|
{
|
||||||
it->RemoveAllMembers();
|
expedition->RemoveAllMembers();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExpeditionState::SetSecondsRemaining(uint32_t expedition_id, uint32_t seconds_remaining)
|
void ExpeditionState::SetSecondsRemaining(uint32_t expedition_id, uint32_t seconds_remaining)
|
||||||
{
|
{
|
||||||
auto it = std::find_if(m_expeditions.begin(), m_expeditions.end(), [&](const Expedition& expedition) {
|
auto expedition = GetExpedition(expedition_id);
|
||||||
return expedition.GetID() == expedition_id;
|
if (expedition)
|
||||||
});
|
|
||||||
|
|
||||||
if (it != m_expeditions.end())
|
|
||||||
{
|
{
|
||||||
it->UpdateDzSecondsRemaining(seconds_remaining);
|
expedition->UpdateDzSecondsRemaining(seconds_remaining);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -34,6 +34,7 @@ class ExpeditionState
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void AddExpedition(uint32_t expedition_id);
|
void AddExpedition(uint32_t expedition_id);
|
||||||
|
Expedition* GetExpedition(uint32_t expedition_id);
|
||||||
void LoadActiveExpeditions();
|
void LoadActiveExpeditions();
|
||||||
void MemberChange(uint32_t expedition_id, uint32_t character_id, bool remove);
|
void MemberChange(uint32_t expedition_id, uint32_t character_id, bool remove);
|
||||||
void Process();
|
void Process();
|
||||||
|
|||||||
@ -1362,7 +1362,6 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
|||||||
client_list.SendPacket(buf->character_name, pack);
|
client_list.SendPacket(buf->character_name, pack);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ServerOP_ExpeditionLeaderChanged:
|
|
||||||
case ServerOP_ExpeditionLockout:
|
case ServerOP_ExpeditionLockout:
|
||||||
case ServerOP_ExpeditionLockoutDuration:
|
case ServerOP_ExpeditionLockoutDuration:
|
||||||
case ServerOP_ExpeditionLockState:
|
case ServerOP_ExpeditionLockState:
|
||||||
@ -1376,6 +1375,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
|||||||
zoneserver_list.SendPacket(pack);
|
zoneserver_list.SendPacket(pack);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ServerOP_ExpeditionChooseNewLeader:
|
||||||
case ServerOP_ExpeditionCreate:
|
case ServerOP_ExpeditionCreate:
|
||||||
case ServerOP_ExpeditionGetOnlineMembers:
|
case ServerOP_ExpeditionGetOnlineMembers:
|
||||||
case ServerOP_ExpeditionMemberChange:
|
case ServerOP_ExpeditionMemberChange:
|
||||||
|
|||||||
@ -6984,20 +6984,15 @@ void command_dz(Client* c, const Seperator* sep)
|
|||||||
auto expedition = Expedition::FindCachedExpeditionByID(expedition_id);
|
auto expedition = Expedition::FindCachedExpeditionByID(expedition_id);
|
||||||
if (expedition)
|
if (expedition)
|
||||||
{
|
{
|
||||||
uint32_t char_id = database.GetCharacterID(sep->arg[3]);
|
|
||||||
auto char_name = FormatName(sep->arg[3]);
|
auto char_name = FormatName(sep->arg[3]);
|
||||||
if (char_id == 0)
|
if (!expedition->HasMember(char_name))
|
||||||
{
|
|
||||||
c->Message(Chat::Red, fmt::format("Failed to find character id for [{}]", char_name).c_str());
|
|
||||||
}
|
|
||||||
else if (!expedition->HasMember(char_id))
|
|
||||||
{
|
{
|
||||||
c->Message(Chat::Red, fmt::format("Character [{}] is not in that expedition", char_name).c_str());
|
c->Message(Chat::Red, fmt::format("Character [{}] is not in that expedition", char_name).c_str());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
c->Message(Chat::White, fmt::format("Setting expedition [{}] leader to [{}]", expedition_id, char_name).c_str());
|
c->Message(Chat::White, fmt::format("Setting expedition [{}] leader to [{}]", expedition_id, char_name).c_str());
|
||||||
expedition->SetNewLeader(char_id, char_name);
|
expedition->SendWorldMakeLeaderRequest(c->GetName(), char_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@ -578,12 +578,6 @@ bool Expedition::RemoveMember(const std::string& remove_char_name)
|
|||||||
ProcessMemberRemoved(member.name, member.char_id);
|
ProcessMemberRemoved(member.name, member.char_id);
|
||||||
SendWorldMemberChanged(member.name, member.char_id, true);
|
SendWorldMemberChanged(member.name, member.char_id, true);
|
||||||
|
|
||||||
// live always sends a leader update but we can send only if leader changes
|
|
||||||
if (member.char_id == m_leader.char_id)
|
|
||||||
{
|
|
||||||
ChooseNewLeader();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -609,11 +603,6 @@ void Expedition::SwapMember(Client* add_client, const std::string& remove_char_n
|
|||||||
ProcessMemberRemoved(member.name, member.char_id);
|
ProcessMemberRemoved(member.name, member.char_id);
|
||||||
ProcessMemberAdded(add_client->GetName(), add_client->CharacterID());
|
ProcessMemberAdded(add_client->GetName(), add_client->CharacterID());
|
||||||
SendWorldMemberSwapped(member.name, member.char_id, add_client->GetName(), add_client->CharacterID());
|
SendWorldMemberSwapped(member.name, member.char_id, add_client->GetName(), add_client->CharacterID());
|
||||||
|
|
||||||
if (!m_members.empty() && member.char_id == m_leader.char_id)
|
|
||||||
{
|
|
||||||
ChooseNewLeader();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Expedition::SetMemberStatus(Client* client, ExpeditionMemberStatus status)
|
void Expedition::SetMemberStatus(Client* client, ExpeditionMemberStatus status)
|
||||||
@ -623,11 +612,11 @@ void Expedition::SetMemberStatus(Client* client, ExpeditionMemberStatus status)
|
|||||||
UpdateMemberStatus(client->CharacterID(), status);
|
UpdateMemberStatus(client->CharacterID(), status);
|
||||||
SendWorldMemberStatus(client->CharacterID(), status);
|
SendWorldMemberStatus(client->CharacterID(), status);
|
||||||
|
|
||||||
// we either changed leader status here or leader was already offline and
|
// world could detect this itself but it'd have to process member status updates
|
||||||
// a member coming online needs to trigger a leader change
|
// a member coming online will trigger a leader change if all members were offline
|
||||||
if (m_leader.status == ExpeditionMemberStatus::Offline)
|
if (m_leader.status == ExpeditionMemberStatus::Offline)
|
||||||
{
|
{
|
||||||
ChooseNewLeader();
|
SendWorldExpeditionUpdate(ServerOP_ExpeditionChooseNewLeader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -662,20 +651,6 @@ void Expedition::UpdateMemberStatus(uint32_t update_member_id, ExpeditionMemberS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Expedition::ChooseNewLeader()
|
|
||||||
{
|
|
||||||
for (const auto& member : m_members)
|
|
||||||
{
|
|
||||||
if (member.char_id != m_leader.char_id && member.status == ExpeditionMemberStatus::Online)
|
|
||||||
{
|
|
||||||
LogExpeditionsModerate("Replacing leader [{}] with [{}]", m_leader.name, member.name);
|
|
||||||
SetNewLeader(member.char_id, member.name);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Expedition::SendClientExpeditionInvite(
|
void Expedition::SendClientExpeditionInvite(
|
||||||
Client* client, const std::string& inviter_name, const std::string& swap_remove_name)
|
Client* client, const std::string& inviter_name, const std::string& swap_remove_name)
|
||||||
{
|
{
|
||||||
@ -1051,17 +1026,8 @@ void Expedition::DzMakeLeader(Client* requester, std::string new_leader_name)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// database is not updated until new leader client validated
|
// leader can only be changed by world
|
||||||
Client* new_leader_client = entity_list.GetClientByName(new_leader_name.c_str());
|
SendWorldMakeLeaderRequest(requester->GetName(), new_leader_name);
|
||||||
if (new_leader_client)
|
|
||||||
{
|
|
||||||
ProcessMakeLeader(requester, new_leader_client, new_leader_name, true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// new leader not in this zone, let world verify and pass to new leader's zone
|
|
||||||
SendWorldMakeLeaderRequest(requester->GetName(), new_leader_name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Expedition::DzRemovePlayer(Client* requester, std::string char_name)
|
void Expedition::DzRemovePlayer(Client* requester, std::string char_name)
|
||||||
@ -1164,16 +1130,18 @@ void Expedition::SetLocked(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Expedition::SetNewLeader(uint32_t new_leader_id, const std::string& new_leader_name)
|
void Expedition::ProcessLeaderChanged(uint32_t new_leader_id)
|
||||||
{
|
{
|
||||||
ExpeditionDatabase::UpdateLeaderID(m_id, new_leader_id);
|
auto new_leader = GetMemberData(new_leader_id);
|
||||||
ProcessLeaderChanged(new_leader_id, new_leader_name);
|
if (new_leader.char_id == 0)
|
||||||
SendWorldLeaderChanged();
|
{
|
||||||
}
|
LogExpeditions("Processed invalid new leader id [{}] for expedition [{}]", new_leader_id, m_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void Expedition::ProcessLeaderChanged(uint32_t new_leader_id, const std::string& new_leader_name)
|
LogExpeditionsModerate("Replaced [{}] leader [{}] with [{}]", m_id, m_leader.name, new_leader.name);
|
||||||
{
|
|
||||||
m_leader = { new_leader_id, new_leader_name, ExpeditionMemberStatus::Online };
|
m_leader = new_leader;
|
||||||
|
|
||||||
// update each client's expedition window in this zone
|
// update each client's expedition window in this zone
|
||||||
auto outapp_leader = CreateLeaderNamePacket();
|
auto outapp_leader = CreateLeaderNamePacket();
|
||||||
@ -1219,7 +1187,6 @@ void Expedition::ProcessMakeLeader(
|
|||||||
{
|
{
|
||||||
new_leader_client->MessageString(Chat::Yellow, DZMAKELEADER_YOU);
|
new_leader_client->MessageString(Chat::Yellow, DZMAKELEADER_YOU);
|
||||||
}
|
}
|
||||||
SetNewLeader(new_leader_client->CharacterID(), new_leader_client->GetName());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1592,19 +1559,6 @@ void Expedition::SendWorldAddPlayerInvite(
|
|||||||
worldserver.SendPacket(pack.get());
|
worldserver.SendPacket(pack.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Expedition::SendWorldLeaderChanged()
|
|
||||||
{
|
|
||||||
uint32_t pack_size = sizeof(ServerExpeditionMemberChange_Struct);
|
|
||||||
auto pack = std::unique_ptr<ServerPacket>(new ServerPacket(ServerOP_ExpeditionLeaderChanged, pack_size));
|
|
||||||
auto buf = reinterpret_cast<ServerExpeditionMemberChange_Struct*>(pack->pBuffer);
|
|
||||||
buf->expedition_id = GetID();
|
|
||||||
buf->sender_zone_id = zone ? zone->GetZoneID() : 0;
|
|
||||||
buf->sender_instance_id = zone ? zone->GetInstanceID() : 0;
|
|
||||||
buf->char_id = m_leader.char_id;
|
|
||||||
strn0cpy(buf->char_name, m_leader.name.c_str(), sizeof(buf->char_name));
|
|
||||||
worldserver.SendPacket(pack.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Expedition::SendWorldLockoutDuration(
|
void Expedition::SendWorldLockoutDuration(
|
||||||
const ExpeditionLockoutTimer& lockout, int seconds, bool members_only)
|
const ExpeditionLockoutTimer& lockout, int seconds, bool members_only)
|
||||||
{
|
{
|
||||||
@ -1894,14 +1848,11 @@ void Expedition::HandleWorldMessage(ServerPacket* pack)
|
|||||||
}
|
}
|
||||||
case ServerOP_ExpeditionLeaderChanged:
|
case ServerOP_ExpeditionLeaderChanged:
|
||||||
{
|
{
|
||||||
auto buf = reinterpret_cast<ServerExpeditionMemberChange_Struct*>(pack->pBuffer);
|
auto buf = reinterpret_cast<ServerExpeditionLeaderID_Struct*>(pack->pBuffer);
|
||||||
if (zone && !zone->IsZone(buf->sender_zone_id, buf->sender_instance_id))
|
auto expedition = Expedition::FindCachedExpeditionByID(buf->expedition_id);
|
||||||
|
if (expedition)
|
||||||
{
|
{
|
||||||
auto expedition = Expedition::FindCachedExpeditionByID(buf->expedition_id);
|
expedition->ProcessLeaderChanged(buf->leader_id);
|
||||||
if (expedition)
|
|
||||||
{
|
|
||||||
expedition->ProcessLeaderChanged(buf->char_id, buf->char_name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -122,7 +122,6 @@ public:
|
|||||||
void RemoveAllMembers(bool enable_removal_timers = true);
|
void RemoveAllMembers(bool enable_removal_timers = true);
|
||||||
bool RemoveMember(const std::string& remove_char_name);
|
bool RemoveMember(const std::string& remove_char_name);
|
||||||
void SetMemberStatus(Client* client, ExpeditionMemberStatus status);
|
void SetMemberStatus(Client* client, ExpeditionMemberStatus status);
|
||||||
void SetNewLeader(uint32_t new_leader_id, const std::string& new_leader_name);
|
|
||||||
void SwapMember(Client* add_client, const std::string& remove_char_name);
|
void SwapMember(Client* add_client, const std::string& remove_char_name);
|
||||||
void SetLocked(bool lock_expedition, ExpeditionLockMessage lock_msg,
|
void SetLocked(bool lock_expedition, ExpeditionLockMessage lock_msg,
|
||||||
bool update_db = false, uint32_t msg_color = Chat::Yellow);
|
bool update_db = false, uint32_t msg_color = Chat::Yellow);
|
||||||
@ -144,6 +143,7 @@ public:
|
|||||||
void SetLootEventBySpawnID(uint32_t spawn_id, const std::string& event_name);
|
void SetLootEventBySpawnID(uint32_t spawn_id, const std::string& event_name);
|
||||||
|
|
||||||
void SendClientExpeditionInfo(Client* client);
|
void SendClientExpeditionInfo(Client* client);
|
||||||
|
void SendWorldMakeLeaderRequest(const std::string& requester_name, const std::string& new_leader_name);
|
||||||
void SendWorldPendingInvite(const ExpeditionInvite& invite, const std::string& add_name);
|
void SendWorldPendingInvite(const ExpeditionInvite& invite, const std::string& add_name);
|
||||||
|
|
||||||
void DzAddPlayer(Client* requester, const std::string& add_char_name, const std::string& swap_remove_name = {});
|
void DzAddPlayer(Client* requester, const std::string& add_char_name, const std::string& swap_remove_name = {});
|
||||||
@ -174,10 +174,9 @@ private:
|
|||||||
void AddLockout(const ExpeditionLockoutTimer& lockout, bool members_only = false);
|
void AddLockout(const ExpeditionLockoutTimer& lockout, bool members_only = false);
|
||||||
void AddLockoutDurationClients(const ExpeditionLockoutTimer& lockout, int seconds, uint32_t exclude_id = 0);
|
void AddLockoutDurationClients(const ExpeditionLockoutTimer& lockout, int seconds, uint32_t exclude_id = 0);
|
||||||
void AddInternalMember(const std::string& char_name, uint32_t char_id, ExpeditionMemberStatus status);
|
void AddInternalMember(const std::string& char_name, uint32_t char_id, ExpeditionMemberStatus status);
|
||||||
bool ChooseNewLeader();
|
|
||||||
bool ConfirmLeaderCommand(Client* requester);
|
bool ConfirmLeaderCommand(Client* requester);
|
||||||
bool ProcessAddConflicts(Client* leader_client, Client* add_client, bool swapping);
|
bool ProcessAddConflicts(Client* leader_client, Client* add_client, bool swapping);
|
||||||
void ProcessLeaderChanged(uint32_t new_leader_id, const std::string& new_leader_name);
|
void ProcessLeaderChanged(uint32_t new_leader_id);
|
||||||
void ProcessLockoutDuration(const ExpeditionLockoutTimer& lockout, int seconds, bool members_only = false);
|
void ProcessLockoutDuration(const ExpeditionLockoutTimer& lockout, int seconds, bool members_only = false);
|
||||||
void ProcessLockoutUpdate(const ExpeditionLockoutTimer& lockout, bool remove, bool members_only = false);
|
void ProcessLockoutUpdate(const ExpeditionLockoutTimer& lockout, bool remove, bool members_only = false);
|
||||||
void ProcessMakeLeader(Client* old_leader, Client* new_leader, const std::string& new_leader_name, bool is_online);
|
void ProcessMakeLeader(Client* old_leader, Client* new_leader, const std::string& new_leader_name, bool is_online);
|
||||||
@ -196,12 +195,10 @@ private:
|
|||||||
void SendWorldExpeditionUpdate(uint16_t server_opcode);
|
void SendWorldExpeditionUpdate(uint16_t server_opcode);
|
||||||
void SendWorldAddPlayerInvite(const std::string& inviter_name, const std::string& swap_remove_name,
|
void SendWorldAddPlayerInvite(const std::string& inviter_name, const std::string& swap_remove_name,
|
||||||
const std::string& add_name, bool pending = false);
|
const std::string& add_name, bool pending = false);
|
||||||
void SendWorldLeaderChanged();
|
|
||||||
void SendWorldLockoutDuration(
|
void SendWorldLockoutDuration(
|
||||||
const ExpeditionLockoutTimer& lockout, int seconds, bool members_only = false);
|
const ExpeditionLockoutTimer& lockout, int seconds, bool members_only = false);
|
||||||
void SendWorldLockoutUpdate(
|
void SendWorldLockoutUpdate(
|
||||||
const ExpeditionLockoutTimer& lockout, bool remove, bool members_only = false);
|
const ExpeditionLockoutTimer& lockout, bool remove, bool members_only = false);
|
||||||
void SendWorldMakeLeaderRequest(const std::string& requester_name, const std::string& new_leader_name);
|
|
||||||
void SendWorldMemberChanged(const std::string& char_name, uint32_t char_id, bool remove);
|
void SendWorldMemberChanged(const std::string& char_name, uint32_t char_id, bool remove);
|
||||||
void SendWorldMemberStatus(uint32_t character_id, ExpeditionMemberStatus status);
|
void SendWorldMemberStatus(uint32_t character_id, ExpeditionMemberStatus status);
|
||||||
void SendWorldMemberSwapped(const std::string& remove_char_name, uint32_t remove_char_id,
|
void SendWorldMemberSwapped(const std::string& remove_char_name, uint32_t remove_char_id,
|
||||||
|
|||||||
@ -629,17 +629,6 @@ void ExpeditionDatabase::InsertMembers(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExpeditionDatabase::UpdateLeaderID(uint32_t expedition_id, uint32_t leader_id)
|
|
||||||
{
|
|
||||||
LogExpeditionsDetail("Updating leader [{}] for expedition [{}]", leader_id, expedition_id);
|
|
||||||
|
|
||||||
auto query = fmt::format(SQL(
|
|
||||||
UPDATE expeditions SET leader_id = {} WHERE id = {};
|
|
||||||
), leader_id, expedition_id);
|
|
||||||
|
|
||||||
database.QueryDatabase(query);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExpeditionDatabase::UpdateLockState(uint32_t expedition_id, bool is_locked)
|
void ExpeditionDatabase::UpdateLockState(uint32_t expedition_id, bool is_locked)
|
||||||
{
|
{
|
||||||
LogExpeditionsDetail("Updating lock state [{}] for expedition [{}]", is_locked, expedition_id);
|
LogExpeditionsDetail("Updating lock state [{}] for expedition [{}]", is_locked, expedition_id);
|
||||||
|
|||||||
@ -71,7 +71,6 @@ namespace ExpeditionDatabase
|
|||||||
void InsertLockouts(uint32_t expedition_id, const std::unordered_map<std::string, ExpeditionLockoutTimer>& lockouts);
|
void InsertLockouts(uint32_t expedition_id, const std::unordered_map<std::string, ExpeditionLockoutTimer>& lockouts);
|
||||||
void InsertMember(uint32_t expedition_id, uint32_t character_id);
|
void InsertMember(uint32_t expedition_id, uint32_t character_id);
|
||||||
void InsertMembers(uint32_t expedition_id, const std::vector<ExpeditionMember>& members);
|
void InsertMembers(uint32_t expedition_id, const std::vector<ExpeditionMember>& members);
|
||||||
void UpdateLeaderID(uint32_t expedition_id, uint32_t leader_id);
|
|
||||||
void UpdateLockState(uint32_t expedition_id, bool is_locked);
|
void UpdateLockState(uint32_t expedition_id, bool is_locked);
|
||||||
void UpdateReplayLockoutOnJoin(uint32_t expedition_id, bool add_on_join);
|
void UpdateReplayLockoutOnJoin(uint32_t expedition_id, bool add_on_join);
|
||||||
void AddLockoutDuration(const std::vector<ExpeditionMember>& members,
|
void AddLockoutDuration(const std::vector<ExpeditionMember>& members,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user