[Expeditions] Store members on dynamic zone (#1358)

This moves members from expeditions so other systems can use them

Replace expedition_members table with dynamic_zone_members

Move 'EnableInDynamicZoneStatus' rule to DynamicZone namespace

Modify #dz list to show dz members (not instance players) and type name

Move various queries to repository methods
This commit is contained in:
hg 2021-05-24 22:14:32 -04:00 committed by GitHub
parent e8b94a11f1
commit 15328196e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 683 additions and 585 deletions

View File

@ -177,10 +177,10 @@ SET(repositories
repositories/base/base_discovered_items_repository.h
repositories/base/base_doors_repository.h
repositories/base/base_dynamic_zones_repository.h
repositories/base/base_dynamic_zone_members_repository.h
repositories/base/base_eventlog_repository.h
repositories/base/base_expeditions_repository.h
repositories/base/base_expedition_lockouts_repository.h
repositories/base/base_expedition_members_repository.h
repositories/base/base_faction_base_data_repository.h
repositories/base/base_faction_list_repository.h
repositories/base/base_faction_list_mod_repository.h
@ -341,10 +341,10 @@ SET(repositories
repositories/discovered_items_repository.h
repositories/doors_repository.h
repositories/dynamic_zones_repository.h
repositories/dynamic_zone_members_repository.h
repositories/eventlog_repository.h
repositories/expeditions_repository.h
repositories/expedition_lockouts_repository.h
repositories/expedition_members_repository.h
repositories/faction_base_data_repository.h
repositories/faction_list_repository.h
repositories/faction_list_mod_repository.h

View File

@ -20,6 +20,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "../common/rulesys.h"
#include "../common/string_util.h"
#include "../common/timer.h"
#include "../common/repositories/dynamic_zone_members_repository.h"
#include "../common/repositories/dynamic_zones_repository.h"
#include "database.h"
@ -493,8 +495,8 @@ void Database::DeleteInstance(uint16 instance_id)
query = StringFormat("DELETE FROM spawn_condition_values WHERE instance_id=%u", instance_id);
QueryDatabase(query);
query = fmt::format("DELETE FROM dynamic_zones WHERE instance_id={}", instance_id);
QueryDatabase(query);
DynamicZoneMembersRepository::DeleteByInstance(*this, instance_id);
DynamicZonesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id));
BuryCorpsesInInstance(instance_id);
}
@ -585,7 +587,8 @@ void Database::PurgeExpiredInstances()
QueryDatabase(fmt::format("DELETE FROM respawn_times WHERE instance_id IN ({})", imploded_instance_ids));
QueryDatabase(fmt::format("DELETE FROM spawn_condition_values WHERE instance_id IN ({})", imploded_instance_ids));
QueryDatabase(fmt::format("UPDATE character_corpses SET is_buried = 1, instance_id = 0 WHERE instance_id IN ({})", imploded_instance_ids));
QueryDatabase(fmt::format("DELETE FROM dynamic_zones WHERE instance_id IN ({})", imploded_instance_ids));
DynamicZoneMembersRepository::DeleteByManyInstances(*this, imploded_instance_ids);
DynamicZonesRepository::DeleteWhere(*this, fmt::format("instance_id IN ({})", imploded_instance_ids));
}
void Database::SetInstanceDuration(uint16 instance_id, uint32 new_duration)

View File

@ -309,10 +309,10 @@ namespace DatabaseSchema {
"banned_ips",
"bug_reports",
"bugs",
"dynamic_zone_members",
"dynamic_zones",
"eventlog",
"expedition_lockouts",
"expedition_members",
"expeditions",
"gm_ips",
"group_id",

View File

@ -3,6 +3,7 @@
#include "eqemu_logsys.h"
#include "repositories/instance_list_repository.h"
#include "repositories/instance_list_player_repository.h"
#include "rulesys.h"
#include "servertalk.h"
DynamicZoneBase::DynamicZoneBase(DynamicZonesRepository::DynamicZoneInstance&& entry)
@ -99,6 +100,13 @@ void DynamicZoneBase::LoadRepositoryResult(DynamicZonesRepository::DynamicZoneIn
m_expire_time = m_start_time + m_duration;
}
void DynamicZoneBase::AddMemberFromRepositoryResult(
DynamicZoneMembersRepository::MemberWithName&& entry)
{
auto status = DynamicZoneMemberStatus::Unknown;
AddInternalMember({ entry.character_id, std::move(entry.character_name), status });
}
uint32_t DynamicZoneBase::SaveToDatabase()
{
LogDynamicZonesDetail("Saving dz instance [{}] to database", m_instance_id);
@ -131,12 +139,14 @@ uint32_t DynamicZoneBase::SaveToDatabase()
void DynamicZoneBase::AddCharacter(uint32_t character_id)
{
DynamicZoneMembersRepository::AddMember(GetDatabase(), m_id, character_id);
GetDatabase().AddClientToInstance(m_instance_id, character_id);
SendInstanceAddRemoveCharacter(character_id, false); // stops client kick timer
}
void DynamicZoneBase::RemoveCharacter(uint32_t character_id)
{
DynamicZoneMembersRepository::RemoveMember(GetDatabase(), m_id, character_id);
GetDatabase().RemoveClientFromInstance(m_instance_id, character_id);
SendInstanceAddRemoveCharacter(character_id, true); // start client kick timer
}
@ -153,24 +163,35 @@ void DynamicZoneBase::RemoveAllCharacters(bool enable_removal_timers)
SendInstanceRemoveAllCharacters();
}
DynamicZoneMembersRepository::RemoveAllMembers(GetDatabase(), m_id);
GetDatabase().RemoveClientsFromInstance(GetInstanceID());
}
void DynamicZoneBase::SaveInstanceMembersToDatabase(const std::vector<uint32_t>& character_ids)
void DynamicZoneBase::SaveMembers(const std::vector<DynamicZoneMember>& members)
{
LogDynamicZonesDetail("Saving [{}] members for instance [{}]", character_ids.size(), m_instance_id);
LogDynamicZonesDetail("Saving [{}] member(s) for dz [{}]", members.size(), m_id);
m_members = members;
// the lower level instance_list_players needs to be kept updated as well
std::vector<DynamicZoneMembersRepository::DynamicZoneMembers> insert_members;
std::vector<InstanceListPlayerRepository::InstanceListPlayer> insert_players;
for (const auto& character_id : character_ids)
for (const auto& member : m_members)
{
InstanceListPlayerRepository::InstanceListPlayer entry{};
entry.id = static_cast<int>(m_instance_id);
entry.charid = static_cast<int>(character_id);
insert_players.emplace_back(entry);
DynamicZoneMembersRepository::DynamicZoneMembers member_entry{};
member_entry.dynamic_zone_id = m_id;
member_entry.character_id = member.id;
member_entry.is_current_member = true;
insert_members.emplace_back(member_entry);
InstanceListPlayerRepository::InstanceListPlayer player_entry;
player_entry.id = static_cast<int>(m_instance_id);
player_entry.charid = static_cast<int>(member.id);
insert_players.emplace_back(player_entry);
}
InstanceListPlayerRepository::InsertMany(GetDatabase(), insert_players);
DynamicZoneMembersRepository::InsertOrUpdateMany(GetDatabase(), insert_members);
InstanceListPlayerRepository::InsertOrUpdateMany(GetDatabase(), insert_players);
}
void DynamicZoneBase::SetCompass(const DynamicZoneLocation& location, bool update_db)
@ -287,3 +308,123 @@ std::unique_ptr<ServerPacket> DynamicZoneBase::CreateServerDzLocationPacket(
return pack;
}
uint32_t DynamicZoneBase::GetDatabaseMemberCount()
{
return DynamicZoneMembersRepository::GetCountWhere(GetDatabase(),
fmt::format("dynamic_zone_id = {} AND is_current_member = TRUE", m_id));
}
bool DynamicZoneBase::HasDatabaseMember(uint32_t character_id)
{
if (character_id == 0)
{
return false;
}
auto entries = DynamicZoneMembersRepository::GetWhere(GetDatabase(), fmt::format(
"dynamic_zone_id = {} AND character_id = {} AND is_current_member = TRUE",
m_id, character_id
));
return entries.size() != 0;
}
void DynamicZoneBase::AddInternalMember(const DynamicZoneMember& member)
{
if (!HasMember(member.id))
{
m_members.emplace_back(member);
}
}
void DynamicZoneBase::RemoveInternalMember(uint32_t character_id)
{
m_members.erase(std::remove_if(m_members.begin(), m_members.end(),
[&](const DynamicZoneMember& member) { return member.id == character_id; }
), m_members.end());
}
bool DynamicZoneBase::HasMember(uint32_t character_id)
{
return std::any_of(m_members.begin(), m_members.end(),
[&](const DynamicZoneMember& member) { return member.id == character_id; });
}
bool DynamicZoneBase::HasMember(const std::string& character_name)
{
return std::any_of(m_members.begin(), m_members.end(),
[&](const DynamicZoneMember& member) {
return strcasecmp(member.name.c_str(), character_name.c_str()) == 0;
});
}
DynamicZoneMember DynamicZoneBase::GetMemberData(uint32_t character_id)
{
auto it = std::find_if(m_members.begin(), m_members.end(),
[&](const DynamicZoneMember& member) { return member.id == character_id; });
DynamicZoneMember member_data;
if (it != m_members.end())
{
member_data = *it;
}
return member_data;
}
DynamicZoneMember DynamicZoneBase::GetMemberData(const std::string& character_name)
{
auto it = std::find_if(m_members.begin(), m_members.end(),
[&](const DynamicZoneMember& member) {
return strcasecmp(member.name.c_str(), character_name.c_str()) == 0;
});
DynamicZoneMember member_data;
if (it != m_members.end())
{
member_data = *it;
}
return member_data;
}
bool DynamicZoneBase::SetInternalMemberStatus(uint32_t character_id, DynamicZoneMemberStatus status)
{
if (status == DynamicZoneMemberStatus::InDynamicZone && !RuleB(DynamicZone, 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;
}
std::string DynamicZoneBase::GetDynamicZoneTypeName(DynamicZoneType dz_type)
{
switch (dz_type)
{
case DynamicZoneType::Expedition:
return "Expedition";
case DynamicZoneType::Tutorial:
return "Tutorial";
case DynamicZoneType::Task:
return "Task";
case DynamicZoneType::Mission:
return "Mission";
case DynamicZoneType::Quest:
return "Quest";
}
return "Unknown";
}

View File

@ -3,6 +3,7 @@
#include "eq_constants.h"
#include "repositories/dynamic_zones_repository.h"
#include "repositories/dynamic_zone_members_repository.h"
#include <algorithm>
#include <chrono>
#include <cstdint>
@ -56,27 +57,42 @@ public:
DynamicZoneBase(DynamicZoneType type) : m_type(type) {}
DynamicZoneBase(DynamicZonesRepository::DynamicZoneInstance&& entry);
static std::string GetDynamicZoneTypeName(DynamicZoneType dz_type);
virtual void SetSecondsRemaining(uint32_t seconds_remaining) = 0;
uint64_t GetExpireTime() const { return std::chrono::system_clock::to_time_t(m_expire_time); }
uint32_t GetID() const { return m_id; }
uint16_t GetInstanceID() const { return static_cast<uint16_t>(m_instance_id); }
uint32_t GetMaxPlayers() const { return m_max_players; }
uint32_t GetMemberCount() const { return static_cast<uint32_t>(m_members.size()); }
uint32_t GetMinPlayers() const { return m_min_players; }
uint32_t GetSecondsRemaining() const;
uint16_t GetZoneID() const { return static_cast<uint16_t>(m_zone_id); }
uint32_t GetZoneIndex() const { return (m_instance_id << 16) | (m_zone_id & 0xffff); }
uint32_t GetZoneVersion() const { return m_zone_version; }
DynamicZoneType GetType() const { return m_type; }
const std::string& GetLeaderName() const { return m_leader_name; }
const std::string& GetLeaderName() const { return m_leader.name; }
const std::string& GetName() const { return m_name; }
const DynamicZoneMember& GetLeader() const { return m_leader; }
const std::vector<DynamicZoneMember>& GetMembers() const { return m_members; }
const DynamicZoneLocation& GetCompassLocation() const { return m_compass; }
const DynamicZoneLocation& GetSafeReturnLocation() const { return m_safereturn; }
const DynamicZoneLocation& GetZoneInLocation() const { return m_zonein; }
std::chrono::system_clock::duration GetDurationRemaining() const { return m_expire_time - std::chrono::system_clock::now(); }
void AddCharacter(uint32_t character_id);
void AddInternalMember(const DynamicZoneMember& member);
void AddMemberFromRepositoryResult(DynamicZoneMembersRepository::MemberWithName&& entry);
void ClearInternalMembers() { m_members.clear(); }
uint32_t Create();
uint32_t GetDatabaseMemberCount();
DynamicZoneMember GetMemberData(uint32_t character_id);
DynamicZoneMember GetMemberData(const std::string& character_name);
bool HasDatabaseMember(uint32_t character_id);
bool HasMember(uint32_t character_id);
bool HasMember(const std::string& character_name);
bool HasMembers() const { return !m_members.empty(); }
bool HasZoneInLocation() const { return m_has_zonein; }
bool IsExpired() const { return m_expire_time < std::chrono::system_clock::now(); }
bool IsInstanceID(uint32_t instance_id) const { return (m_instance_id != 0 && m_instance_id == instance_id); }
@ -84,10 +100,12 @@ public:
bool IsSameDz(uint32_t zone_id, uint32_t instance_id) const { return zone_id == m_zone_id && instance_id == m_instance_id; }
void RemoveAllCharacters(bool enable_removal_timers = true);
void RemoveCharacter(uint32_t character_id);
void SaveInstanceMembersToDatabase(const std::vector<uint32_t>& character_ids);
void RemoveInternalMember(uint32_t character_id);
void SaveMembers(const std::vector<DynamicZoneMember>& members);
void SetCompass(const DynamicZoneLocation& location, bool update_db = false);
void SetCompass(uint32_t zone_id, float x, float y, float z, bool update_db = false);
void SetLeaderName(const std::string& leader_name) { m_leader_name = leader_name; }
bool SetInternalMemberStatus(uint32_t character_id, DynamicZoneMemberStatus status);
void SetLeader(const DynamicZoneMember& leader) { m_leader = leader; }
void SetMaxPlayers(uint32_t max_players) { m_max_players = max_players; }
void SetMinPlayers(uint32_t min_players) { m_min_players = min_players; }
void SetName(const std::string& name) { m_name = name; }
@ -122,7 +140,7 @@ protected:
bool m_never_expires = false;
bool m_has_zonein = false;
std::string m_name;
std::string m_leader_name;
DynamicZoneMember m_leader;
DynamicZoneType m_type{ DynamicZoneType::None };
DynamicZoneLocation m_compass;
DynamicZoneLocation m_safereturn;
@ -130,6 +148,7 @@ protected:
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_expire_time;
std::vector<DynamicZoneMember> m_members;
};
#endif

View File

@ -1,6 +1,5 @@
#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
@ -22,92 +21,3 @@ void ExpeditionBase::LoadRepositoryResult(ExpeditionsRepository::ExpeditionWithL
m_leader.id = entry.leader_id;
m_leader.name = std::move(entry.leader_name);
}
void ExpeditionBase::AddMemberFromRepositoryResult(
ExpeditionMembersRepository::MemberWithName&& entry)
{
auto status = DynamicZoneMemberStatus::Unknown;
AddInternalMember({ entry.character_id, std::move(entry.character_name), status });
}
void ExpeditionBase::AddInternalMember(const DynamicZoneMember& member)
{
if (!HasMember(member.id))
{
m_members.emplace_back(member);
}
}
void ExpeditionBase::RemoveInternalMember(uint32_t character_id)
{
m_members.erase(std::remove_if(m_members.begin(), m_members.end(),
[&](const DynamicZoneMember& member) { return member.id == character_id; }
), m_members.end());
}
bool ExpeditionBase::HasMember(uint32_t character_id)
{
return std::any_of(m_members.begin(), m_members.end(), [&](const DynamicZoneMember& member) {
return member.id == character_id;
});
}
bool ExpeditionBase::HasMember(const std::string& character_name)
{
return std::any_of(m_members.begin(), m_members.end(), [&](const DynamicZoneMember& member) {
return (strcasecmp(member.name.c_str(), character_name.c_str()) == 0);
});
}
DynamicZoneMember ExpeditionBase::GetMemberData(uint32_t character_id)
{
auto it = std::find_if(m_members.begin(), m_members.end(), [&](const DynamicZoneMember& member) {
return member.id == character_id;
});
DynamicZoneMember member_data;
if (it != m_members.end())
{
member_data = *it;
}
return member_data;
}
DynamicZoneMember ExpeditionBase::GetMemberData(const std::string& character_name)
{
auto it = std::find_if(m_members.begin(), m_members.end(), [&](const DynamicZoneMember& member) {
return (strcasecmp(member.name.c_str(), character_name.c_str()) == 0);
});
DynamicZoneMember member_data;
if (it != m_members.end())
{
member_data = *it;
}
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;
}

View File

@ -3,10 +3,8 @@
#include "dynamic_zone_base.h"
#include "repositories/expeditions_repository.h"
#include "repositories/expedition_members_repository.h"
#include <cstdint>
#include <string>
#include <vector>
class ExpeditionBase
{
@ -19,38 +17,24 @@ public:
uint32_t GetID() const { return m_id; }
uint32_t GetLeaderID() const { return m_leader.id; }
uint32_t GetMemberCount() const { return static_cast<uint32_t>(m_members.size()); }
const std::string& GetName() const { return m_expedition_name; }
const std::string& GetLeaderName() const { return m_leader.name; }
const std::string& GetUUID() const { return m_uuid; }
const std::vector<DynamicZoneMember>& GetMembers() const { return m_members; }
void AddInternalMember(const DynamicZoneMember& member);
void ClearInternalMembers() { m_members.clear(); }
bool HasMember(const std::string& character_name);
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);
const DynamicZoneMember& GetLeader() const { return m_leader; }
void LoadRepositoryResult(ExpeditionsRepository::ExpeditionWithLeader&& entry);
void AddMemberFromRepositoryResult(ExpeditionMembersRepository::MemberWithName&& entry);
protected:
ExpeditionBase() = default;
ExpeditionBase(uint32_t id, const std::string& uuid, const std::string& expedition_name,
const DynamicZoneMember& leader);
DynamicZoneMember GetMemberData(uint32_t character_id);
DynamicZoneMember GetMemberData(const std::string& character_name);
uint32_t m_id = 0;
bool m_is_locked = false;
bool m_add_replay_on_join = true;
std::string m_uuid;
std::string m_expedition_name;
DynamicZoneMember m_leader;
std::vector<DynamicZoneMember> m_members;
};
#endif

View File

@ -4,22 +4,22 @@
* This repository was automatically generated and is NOT to be modified directly.
* Any repository modifications are meant to be made to the repository extending the base.
* Any modifications to base repositories are to be made by the generator only
*
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
*/
#ifndef EQEMU_BASE_EXPEDITION_MEMBERS_REPOSITORY_H
#define EQEMU_BASE_EXPEDITION_MEMBERS_REPOSITORY_H
#ifndef EQEMU_BASE_DYNAMIC_ZONE_MEMBERS_REPOSITORY_H
#define EQEMU_BASE_DYNAMIC_ZONE_MEMBERS_REPOSITORY_H
#include "../../database.h"
#include "../../string_util.h"
class BaseExpeditionMembersRepository {
class BaseDynamicZoneMembersRepository {
public:
struct ExpeditionMembers {
struct DynamicZoneMembers {
int id;
int expedition_id;
int dynamic_zone_id;
int character_id;
int is_current_member;
};
@ -33,7 +33,7 @@ public:
{
return {
"id",
"expedition_id",
"dynamic_zone_id",
"character_id",
"is_current_member",
};
@ -46,7 +46,7 @@ public:
static std::string TableName()
{
return std::string("expedition_members");
return std::string("dynamic_zone_members");
}
static std::string BaseSelect()
@ -67,51 +67,51 @@ public:
);
}
static ExpeditionMembers NewEntity()
static DynamicZoneMembers NewEntity()
{
ExpeditionMembers entry{};
DynamicZoneMembers entry{};
entry.id = 0;
entry.expedition_id = 0;
entry.dynamic_zone_id = 0;
entry.character_id = 0;
entry.is_current_member = 1;
return entry;
}
static ExpeditionMembers GetExpeditionMembersEntry(
const std::vector<ExpeditionMembers> &expedition_memberss,
int expedition_members_id
static DynamicZoneMembers GetDynamicZoneMembersEntry(
const std::vector<DynamicZoneMembers> &dynamic_zone_memberss,
int dynamic_zone_members_id
)
{
for (auto &expedition_members : expedition_memberss) {
if (expedition_members.id == expedition_members_id) {
return expedition_members;
for (auto &dynamic_zone_members : dynamic_zone_memberss) {
if (dynamic_zone_members.id == dynamic_zone_members_id) {
return dynamic_zone_members;
}
}
return NewEntity();
}
static ExpeditionMembers FindOne(
static DynamicZoneMembers FindOne(
Database& db,
int expedition_members_id
int dynamic_zone_members_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE id = {} LIMIT 1",
BaseSelect(),
expedition_members_id
dynamic_zone_members_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
ExpeditionMembers entry{};
DynamicZoneMembers entry{};
entry.id = atoi(row[0]);
entry.expedition_id = atoi(row[1]);
entry.dynamic_zone_id = atoi(row[1]);
entry.character_id = atoi(row[2]);
entry.is_current_member = atoi(row[3]);
@ -123,7 +123,7 @@ public:
static int DeleteOne(
Database& db,
int expedition_members_id
int dynamic_zone_members_id
)
{
auto results = db.QueryDatabase(
@ -131,7 +131,7 @@ public:
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
expedition_members_id
dynamic_zone_members_id
)
);
@ -140,16 +140,16 @@ public:
static int UpdateOne(
Database& db,
ExpeditionMembers expedition_members_entry
DynamicZoneMembers dynamic_zone_members_entry
)
{
std::vector<std::string> update_values;
auto columns = Columns();
update_values.push_back(columns[1] + " = " + std::to_string(expedition_members_entry.expedition_id));
update_values.push_back(columns[2] + " = " + std::to_string(expedition_members_entry.character_id));
update_values.push_back(columns[3] + " = " + std::to_string(expedition_members_entry.is_current_member));
update_values.push_back(columns[1] + " = " + std::to_string(dynamic_zone_members_entry.dynamic_zone_id));
update_values.push_back(columns[2] + " = " + std::to_string(dynamic_zone_members_entry.character_id));
update_values.push_back(columns[3] + " = " + std::to_string(dynamic_zone_members_entry.is_current_member));
auto results = db.QueryDatabase(
fmt::format(
@ -157,24 +157,24 @@ public:
TableName(),
implode(", ", update_values),
PrimaryKey(),
expedition_members_entry.id
dynamic_zone_members_entry.id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static ExpeditionMembers InsertOne(
static DynamicZoneMembers InsertOne(
Database& db,
ExpeditionMembers expedition_members_entry
DynamicZoneMembers dynamic_zone_members_entry
)
{
std::vector<std::string> insert_values;
insert_values.push_back(std::to_string(expedition_members_entry.id));
insert_values.push_back(std::to_string(expedition_members_entry.expedition_id));
insert_values.push_back(std::to_string(expedition_members_entry.character_id));
insert_values.push_back(std::to_string(expedition_members_entry.is_current_member));
insert_values.push_back(std::to_string(dynamic_zone_members_entry.id));
insert_values.push_back(std::to_string(dynamic_zone_members_entry.dynamic_zone_id));
insert_values.push_back(std::to_string(dynamic_zone_members_entry.character_id));
insert_values.push_back(std::to_string(dynamic_zone_members_entry.is_current_member));
auto results = db.QueryDatabase(
fmt::format(
@ -185,29 +185,29 @@ public:
);
if (results.Success()) {
expedition_members_entry.id = results.LastInsertedID();
return expedition_members_entry;
dynamic_zone_members_entry.id = results.LastInsertedID();
return dynamic_zone_members_entry;
}
expedition_members_entry = NewEntity();
dynamic_zone_members_entry = NewEntity();
return expedition_members_entry;
return dynamic_zone_members_entry;
}
static int InsertMany(
Database& db,
std::vector<ExpeditionMembers> expedition_members_entries
std::vector<DynamicZoneMembers> dynamic_zone_members_entries
)
{
std::vector<std::string> insert_chunks;
for (auto &expedition_members_entry: expedition_members_entries) {
for (auto &dynamic_zone_members_entry: dynamic_zone_members_entries) {
std::vector<std::string> insert_values;
insert_values.push_back(std::to_string(expedition_members_entry.id));
insert_values.push_back(std::to_string(expedition_members_entry.expedition_id));
insert_values.push_back(std::to_string(expedition_members_entry.character_id));
insert_values.push_back(std::to_string(expedition_members_entry.is_current_member));
insert_values.push_back(std::to_string(dynamic_zone_members_entry.id));
insert_values.push_back(std::to_string(dynamic_zone_members_entry.dynamic_zone_id));
insert_values.push_back(std::to_string(dynamic_zone_members_entry.character_id));
insert_values.push_back(std::to_string(dynamic_zone_members_entry.is_current_member));
insert_chunks.push_back("(" + implode(",", insert_values) + ")");
}
@ -225,9 +225,9 @@ public:
return (results.Success() ? results.RowsAffected() : 0);
}
static std::vector<ExpeditionMembers> All(Database& db)
static std::vector<DynamicZoneMembers> All(Database& db)
{
std::vector<ExpeditionMembers> all_entries;
std::vector<DynamicZoneMembers> all_entries;
auto results = db.QueryDatabase(
fmt::format(
@ -239,10 +239,10 @@ public:
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
ExpeditionMembers entry{};
DynamicZoneMembers entry{};
entry.id = atoi(row[0]);
entry.expedition_id = atoi(row[1]);
entry.dynamic_zone_id = atoi(row[1]);
entry.character_id = atoi(row[2]);
entry.is_current_member = atoi(row[3]);
@ -252,9 +252,9 @@ public:
return all_entries;
}
static std::vector<ExpeditionMembers> GetWhere(Database& db, std::string where_filter)
static std::vector<DynamicZoneMembers> GetWhere(Database& db, std::string where_filter)
{
std::vector<ExpeditionMembers> all_entries;
std::vector<DynamicZoneMembers> all_entries;
auto results = db.QueryDatabase(
fmt::format(
@ -267,10 +267,10 @@ public:
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
ExpeditionMembers entry{};
DynamicZoneMembers entry{};
entry.id = atoi(row[0]);
entry.expedition_id = atoi(row[1]);
entry.dynamic_zone_id = atoi(row[1]);
entry.character_id = atoi(row[2]);
entry.is_current_member = atoi(row[3]);
@ -307,4 +307,4 @@ public:
};
#endif //EQEMU_BASE_EXPEDITION_MEMBERS_REPOSITORY_H
#endif //EQEMU_BASE_DYNAMIC_ZONE_MEMBERS_REPOSITORY_H

View File

@ -0,0 +1,249 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef EQEMU_DYNAMIC_ZONE_MEMBERS_REPOSITORY_H
#define EQEMU_DYNAMIC_ZONE_MEMBERS_REPOSITORY_H
#include "../database.h"
#include "../string_util.h"
#include "base/base_dynamic_zone_members_repository.h"
class DynamicZoneMembersRepository: public BaseDynamicZoneMembersRepository {
public:
/**
* This file was auto generated and can be modified and extended upon
*
* Base repository methods are automatically
* generated in the "base" version of this repository. The base repository
* is immutable and to be left untouched, while methods in this class
* are used as extension methods for more specific persistence-layer
* accessors or mutators.
*
* Base Methods (Subject to be expanded upon in time)
*
* Note: Not all tables are designed appropriately to fit functionality with all base methods
*
* InsertOne
* UpdateOne
* DeleteOne
* FindOne
* GetWhere(std::string where_filter)
* DeleteWhere(std::string where_filter)
* InsertMany
* All
*
* Example custom methods in a repository
*
* DynamicZoneMembersRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* DynamicZoneMembersRepository::GetWhereNeverExpires()
* DynamicZoneMembersRepository::GetWhereXAndY()
* DynamicZoneMembersRepository::DeleteWhereXAndY()
*
* Most of the above could be covered by base methods, but if you as a developer
* find yourself re-using logic for other parts of the code, its best to just make a
* method that can be re-used easily elsewhere especially if it can use a base repository
* method and encapsulate filters there
*/
// Custom extended repository methods here
struct MemberWithName {
uint32_t id;
uint32_t dynamic_zone_id;
uint32_t character_id;
int is_current_member;
std::string character_name;
};
static std::string SelectMembersWithNames()
{
return std::string(SQL(
SELECT
dynamic_zone_members.id,
dynamic_zone_members.dynamic_zone_id,
dynamic_zone_members.character_id,
dynamic_zone_members.is_current_member,
character_data.name
FROM dynamic_zone_members
INNER JOIN character_data ON dynamic_zone_members.character_id = character_data.id
));
}
static std::vector<MemberWithName> GetWithNames(Database& db,
const std::vector<uint32_t>& dynamic_zone_ids)
{
if (dynamic_zone_ids.empty())
{
return {};
}
std::vector<MemberWithName> all_entries;
auto results = db.QueryDatabase(fmt::format(SQL(
{}
WHERE dynamic_zone_members.dynamic_zone_id IN ({})
AND dynamic_zone_members.is_current_member = TRUE;
),
SelectMembersWithNames(),
fmt::join(dynamic_zone_ids, ",")
));
if (results.Success())
{
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row)
{
MemberWithName entry{};
int col = 0;
entry.id = strtoul(row[col++], nullptr, 10);
entry.dynamic_zone_id = strtoul(row[col++], nullptr, 10);
entry.character_id = strtoul(row[col++], nullptr, 10);
entry.is_current_member = strtoul(row[col++], nullptr, 10);
entry.character_name = row[col++];
all_entries.emplace_back(std::move(entry));
}
}
return all_entries;
}
static int DeleteByInstance(Database& db, int instance_id)
{
auto results = db.QueryDatabase(fmt::format(SQL(
DELETE dynamic_zone_members
FROM dynamic_zone_members
INNER JOIN dynamic_zones ON dynamic_zone_members.dynamic_zone_id = dynamic_zones.id
WHERE dynamic_zones.instance_id = {}
), instance_id));
return (results.Success() ? results.RowsAffected() : 0);
}
static int DeleteByManyInstances(Database& db, const std::string& joined_instance_ids)
{
auto results = db.QueryDatabase(fmt::format(SQL(
DELETE dynamic_zone_members
FROM dynamic_zone_members
INNER JOIN dynamic_zones ON dynamic_zone_members.dynamic_zone_id = dynamic_zones.id
WHERE dynamic_zones.instance_id IN ({})
), joined_instance_ids));
return (results.Success() ? results.RowsAffected() : 0);
}
static int GetCountWhere(Database& db, const std::string& where_filter)
{
auto results = db.QueryDatabase(fmt::format(
"SELECT COUNT(*) FROM {} WHERE {};", TableName(), where_filter));
uint32_t count = 0;
if (results.Success() && results.RowCount() > 0)
{
auto row = results.begin();
count = strtoul(row[0], nullptr, 10);
}
return count;
}
static void AddMember(Database& db, uint32_t dynamic_zone_id, uint32_t character_id)
{
db.QueryDatabase(fmt::format(SQL(
INSERT INTO {}
(dynamic_zone_id, character_id)
VALUES
({}, {})
ON DUPLICATE KEY UPDATE is_current_member = TRUE;
),
TableName(),
dynamic_zone_id,
character_id
));
}
static void RemoveMember(Database& db, uint32_t dynamic_zone_id, uint32_t character_id)
{
db.QueryDatabase(fmt::format(SQL(
UPDATE {} SET is_current_member = FALSE
WHERE dynamic_zone_id = {} AND character_id = {};
),
TableName(), dynamic_zone_id, character_id
));
}
static void RemoveAllMembers(Database& db, uint32_t dynamic_zone_id)
{
db.QueryDatabase(fmt::format(SQL(
UPDATE {} SET is_current_member = FALSE
WHERE dynamic_zone_id = {};
),
TableName(), dynamic_zone_id
));
}
static void RemoveAllMembers(Database& db, std::vector<uint32_t> dynamic_zone_ids)
{
if (!dynamic_zone_ids.empty())
{
db.QueryDatabase(fmt::format(SQL(
UPDATE {} SET is_current_member = FALSE
WHERE dynamic_zone_id IN ({});
),
TableName(), fmt::join(dynamic_zone_ids, ",")
));
}
}
static int InsertOrUpdateMany(Database& db,
const std::vector<DynamicZoneMembers>& dynamic_zone_members_entries)
{
std::vector<std::string> insert_chunks;
for (auto &dynamic_zone_members_entry: dynamic_zone_members_entries)
{
std::vector<std::string> insert_values;
insert_values.push_back(std::to_string(dynamic_zone_members_entry.id));
insert_values.push_back(std::to_string(dynamic_zone_members_entry.dynamic_zone_id));
insert_values.push_back(std::to_string(dynamic_zone_members_entry.character_id));
insert_values.push_back(std::to_string(dynamic_zone_members_entry.is_current_member));
insert_chunks.push_back("(" + implode(",", insert_values) + ")");
}
std::vector<std::string> insert_values;
auto results = db.QueryDatabase(
fmt::format(
"INSERT INTO {} ({}) VALUES {} ON DUPLICATE KEY UPDATE is_current_member = TRUE;",
TableName(),
ColumnsRaw(),
implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
};
#endif //EQEMU_DYNAMIC_ZONE_MEMBERS_REPOSITORY_H

View File

@ -249,7 +249,7 @@ public:
int version;
uint32_t start_time;
int duration;
int player_count;
int member_count;
};
static std::string SelectDynamicZoneInstancePlayerCount()
@ -263,10 +263,11 @@ public:
instance_list.version,
instance_list.start_time,
instance_list.duration,
COUNT(instance_list_player.id) member_count
COUNT(dynamic_zone_members.character_id) member_count
FROM dynamic_zones
INNER JOIN instance_list ON dynamic_zones.instance_id = instance_list.id
LEFT JOIN instance_list_player ON instance_list.id = instance_list_player.id
LEFT JOIN dynamic_zone_members ON dynamic_zones.id = dynamic_zone_members.dynamic_zone_id
AND dynamic_zone_members.is_current_member = TRUE
GROUP BY instance_list.id
ORDER BY dynamic_zones.id;
));
@ -293,7 +294,7 @@ public:
entry.version = strtol(row[col++], nullptr, 10);
entry.start_time = strtoul(row[col++], nullptr, 10);
entry.duration = strtol(row[col++], nullptr, 10);
entry.player_count = strtol(row[col++], nullptr, 10);
entry.member_count = strtol(row[col++], nullptr, 10);
all_entries.emplace_back(std::move(entry));
}

View File

@ -1,132 +0,0 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef EQEMU_EXPEDITION_MEMBERS_REPOSITORY_H
#define EQEMU_EXPEDITION_MEMBERS_REPOSITORY_H
#include "../database.h"
#include "../string_util.h"
#include "base/base_expedition_members_repository.h"
class ExpeditionMembersRepository: public BaseExpeditionMembersRepository {
public:
/**
* This file was auto generated and can be modified and extended upon
*
* Base repository methods are automatically
* generated in the "base" version of this repository. The base repository
* is immutable and to be left untouched, while methods in this class
* are used as extension methods for more specific persistence-layer
* accessors or mutators.
*
* Base Methods (Subject to be expanded upon in time)
*
* Note: Not all tables are designed appropriately to fit functionality with all base methods
*
* InsertOne
* UpdateOne
* DeleteOne
* FindOne
* GetWhere(std::string where_filter)
* DeleteWhere(std::string where_filter)
* InsertMany
* All
*
* Example custom methods in a repository
*
* ExpeditionMembersRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* ExpeditionMembersRepository::GetWhereNeverExpires()
* ExpeditionMembersRepository::GetWhereXAndY()
* ExpeditionMembersRepository::DeleteWhereXAndY()
*
* Most of the above could be covered by base methods, but if you as a developer
* find yourself re-using logic for other parts of the code, its best to just make a
* method that can be re-used easily elsewhere especially if it can use a base repository
* method and encapsulate filters there
*/
// Custom extended repository methods here
struct MemberWithName {
uint32_t id;
uint32_t expedition_id;
uint32_t character_id;
int is_current_member;
std::string character_name;
};
static std::string SelectMembersWithNames()
{
return std::string(SQL(
SELECT
expedition_members.id,
expedition_members.expedition_id,
expedition_members.character_id,
expedition_members.is_current_member,
character_data.name
FROM expedition_members
INNER JOIN character_data ON expedition_members.character_id = character_data.id
));
}
static std::vector<MemberWithName> GetWithNames(Database& db,
const std::vector<uint32_t>& expedition_ids)
{
if (expedition_ids.empty())
{
return {};
}
std::vector<MemberWithName> all_entries;
auto results = db.QueryDatabase(fmt::format(SQL(
{}
WHERE expedition_members.expedition_id IN ({})
AND expedition_members.is_current_member = TRUE;
),
SelectMembersWithNames(),
fmt::join(expedition_ids, ",")
));
if (results.Success())
{
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row)
{
MemberWithName entry{};
int col = 0;
entry.id = strtoul(row[col++], nullptr, 10);
entry.expedition_id = strtoul(row[col++], nullptr, 10);
entry.character_id = strtoul(row[col++], nullptr, 10);
entry.is_current_member = strtoul(row[col++], nullptr, 10);
entry.character_name = row[col++];
all_entries.emplace_back(std::move(entry));
}
}
return all_entries;
}
};
#endif //EQEMU_EXPEDITION_MEMBERS_REPOSITORY_H

View File

@ -184,11 +184,11 @@ public:
character_data.name,
MAX(expeditions.id)
FROM character_data
LEFT JOIN expedition_members
ON character_data.id = expedition_members.character_id
AND expedition_members.is_current_member = TRUE
LEFT JOIN dynamic_zone_members
ON character_data.id = dynamic_zone_members.character_id
AND dynamic_zone_members.is_current_member = TRUE
LEFT JOIN expeditions
ON expedition_members.expedition_id = expeditions.id
ON dynamic_zone_members.dynamic_zone_id = expeditions.dynamic_zone_id
WHERE character_data.name IN ({})
GROUP BY character_data.id
ORDER BY FIELD(character_data.name, {})
@ -214,6 +214,37 @@ public:
return entries;
}
static uint32_t GetIDByMemberID(Database& db, uint32_t character_id)
{
if (character_id == 0)
{
return 0;
}
uint32_t expedition_id = 0;
auto results = db.QueryDatabase(fmt::format(SQL(
SELECT
expeditions.id
FROM expeditions
INNER JOIN dynamic_zone_members
ON expeditions.dynamic_zone_id = dynamic_zone_members.dynamic_zone_id
WHERE
dynamic_zone_members.character_id = {}
AND dynamic_zone_members.is_current_member = TRUE;
),
character_id
));
if (results.Success() && results.RowCount() > 0)
{
auto row = results.begin();
expedition_id = std::strtoul(row[0], nullptr, 10);
}
return expedition_id;
}
};
#endif //EQEMU_EXPEDITIONS_REPOSITORY_H

View File

@ -65,6 +65,34 @@ public:
// Custom extended repository methods here
static int InsertOrUpdateMany(Database& db,
const std::vector<InstanceListPlayer>& instance_list_player_entries)
{
std::vector<std::string> insert_chunks;
for (auto &instance_list_player_entry: instance_list_player_entries)
{
std::vector<std::string> insert_values;
insert_values.push_back(std::to_string(instance_list_player_entry.id));
insert_values.push_back(std::to_string(instance_list_player_entry.charid));
insert_chunks.push_back("(" + implode(",", insert_values) + ")");
}
std::vector<std::string> insert_values;
auto results = db.QueryDatabase(
fmt::format(
"INSERT INTO {} ({}) VALUES {} ON DUPLICATE KEY UPDATE id = VALUES(id)",
TableName(),
ColumnsRaw(),
implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
};
#endif //EQEMU_INSTANCE_LIST_PLAYER_REPOSITORY_H

View File

@ -742,7 +742,6 @@ RULE_CATEGORY(Expedition)
RULE_INT(Expedition, MinStatusToBypassPlayerCountRequirements, 80, "Minimum GM status to bypass minimum player requirements for Expedition creation")
RULE_BOOL(Expedition, AlwaysNotifyNewLeaderOnChange, false, "Always notify clients when made expedition leader. If false (live-like) new leaders are only notified when made leader via /dzmakeleader")
RULE_REAL(Expedition, LockoutDurationMultiplier, 1.0, "Multiplies lockout duration by this value when new lockouts are added")
RULE_BOOL(Expedition, EnableInDynamicZoneStatus, false, "Enables the 'In Dynamic Zone' member status in expedition window. If false (live-like) players inside the dynamic zone will show as 'Online'")
RULE_INT(Expedition, ChooseLeaderCooldownTime, 2000, "Cooldown time (milliseconds) between choosing a new leader for automatic leader changes")
RULE_CATEGORY_END()
@ -750,6 +749,7 @@ RULE_CATEGORY(DynamicZone)
RULE_INT(DynamicZone, ClientRemovalDelayMS, 60000, "Delay (milliseconds) until a client is teleported out of dynamic zone after being removed as member")
RULE_BOOL(DynamicZone, EmptyShutdownEnabled, true, "Enable early instance shutdown for dynamic zones that have no members")
RULE_INT(DynamicZone, EmptyShutdownDelaySeconds, 1500, "Seconds to set dynamic zone instance expiration if early shutdown enabled")
RULE_BOOL(DynamicZone, EnableInDynamicZoneStatus, false, "Enables the 'In Dynamic Zone' member status in dynamic zone window. If false (live-like) players inside the dynamic zone will show as 'Online'")
RULE_INT(DynamicZone, WorldProcessRate, 6000, "Timer interval (milliseconds) that systems check their dynamic zone states")
RULE_CATEGORY_END()

View File

@ -34,7 +34,7 @@
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/
#define CURRENT_BINARY_DATABASE_VERSION 9165
#define CURRENT_BINARY_DATABASE_VERSION 9166
#ifdef BOTS
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9027

View File

@ -419,6 +419,7 @@
9163|2021_04_17_zone_safe_heading_changes.sql|SHOW COLUMNS FROM `zone` LIKE 'safe_heading'|empty|
9164|2021_04_23_character_exp_modifiers.sql|SHOW TABLES LIKE 'character_exp_modifiers'|empty|
9165|2021_04_28_idle_pathing.sql|SHOW COLUMNS FROM `spawn2` LIKE 'path_when_zone_idle'|empty|
9166|2021_02_12_dynamic_zone_members.sql|SHOW TABLES LIKE 'dynamic_zone_members'|empty|
# Upgrade conditions:
# This won't be needed after this system is implemented, but it is used database that are not

View File

@ -0,0 +1,11 @@
CREATE TABLE `dynamic_zone_members` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`dynamic_zone_id` int(10) unsigned NOT NULL DEFAULT 0,
`character_id` int(10) unsigned NOT NULL DEFAULT 0,
`is_current_member` tinyint(3) unsigned NOT NULL DEFAULT 1,
PRIMARY KEY (`id`),
UNIQUE KEY `dynamic_zone_id_character_id` (`dynamic_zone_id`,`character_id`),
KEY `character_id` (`character_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
DROP TABLE `expedition_members`;

View File

@ -25,11 +25,12 @@ DynamicZone* DynamicZone::FindDynamicZoneByID(uint32_t dz_id)
return nullptr;
}
DynamicZoneStatus DynamicZone::Process(bool force_expire)
DynamicZoneStatus DynamicZone::Process()
{
DynamicZoneStatus status = DynamicZoneStatus::Normal;
if (force_expire || IsExpired())
// force expire if no members
if (!HasMembers() || IsExpired())
{
status = DynamicZoneStatus::Expired;
@ -38,7 +39,7 @@ DynamicZoneStatus DynamicZone::Process(bool force_expire)
{
status = DynamicZoneStatus::ExpiredEmpty;
if (force_expire && !m_is_pending_early_shutdown && RuleB(DynamicZone, EmptyShutdownEnabled))
if (!HasMembers() && !m_is_pending_early_shutdown && RuleB(DynamicZone, EmptyShutdownEnabled))
{
SetSecondsRemaining(RuleI(DynamicZone, EmptyShutdownDelaySeconds));
m_is_pending_early_shutdown = true;

View File

@ -24,7 +24,7 @@ public:
void SetSecondsRemaining(uint32_t seconds_remaining) override;
DynamicZoneStatus Process(bool force_expire);
DynamicZoneStatus Process();
protected:
Database& GetDatabase() override;

View File

@ -39,14 +39,14 @@ Expedition::Expedition() :
void Expedition::SetDynamicZone(DynamicZone&& dz)
{
dz.SetName(GetName());
dz.SetLeaderName(GetLeaderName());
dz.SetLeader(GetLeader());
m_dynamic_zone = std::move(dz);
}
void Expedition::RemoveMember(uint32_t character_id)
{
RemoveInternalMember(character_id);
GetDynamicZone().RemoveInternalMember(character_id);
if (character_id == m_leader.id)
{
@ -56,13 +56,14 @@ void Expedition::RemoveMember(uint32_t character_id)
void Expedition::ChooseNewLeader()
{
if (m_members.empty() || !m_choose_leader_cooldown_timer.Check())
const auto& members = GetDynamicZone().GetMembers();
if (members.empty() || !m_choose_leader_cooldown_timer.Check())
{
m_choose_leader_needed = true;
return;
}
auto it = std::find_if(m_members.begin(), m_members.end(), [&](const DynamicZoneMember& member) {
auto it = std::find_if(members.begin(), members.end(), [&](const DynamicZoneMember& member) {
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);
@ -70,14 +71,14 @@ void Expedition::ChooseNewLeader()
return false;
});
if (it == m_members.end())
if (it == members.end())
{
// no online members found, fallback to choosing any member
it = std::find_if(m_members.begin(), m_members.end(),
it = std::find_if(members.begin(), members.end(),
[&](const DynamicZoneMember& member) { return (member.id != m_leader.id); });
}
if (it != m_members.end() && SetNewLeader(*it))
if (it != members.end() && SetNewLeader(*it))
{
m_choose_leader_needed = false;
}
@ -85,7 +86,7 @@ void Expedition::ChooseNewLeader()
bool Expedition::SetNewLeader(const DynamicZoneMember& member)
{
if (!HasMember(member.id))
if (!GetDynamicZone().HasMember(member.id))
{
return false;
}
@ -93,7 +94,7 @@ bool Expedition::SetNewLeader(const DynamicZoneMember& member)
LogExpeditionsModerate("Replacing [{}] leader [{}] with [{}]", m_id, m_leader.name, member.name);
ExpeditionDatabase::UpdateLeaderID(m_id, member.id);
m_leader = member;
m_dynamic_zone.SetLeaderName(m_leader.name);
m_dynamic_zone.SetLeader(m_leader);
SendZonesLeaderChanged();
return true;
}
@ -156,7 +157,7 @@ bool Expedition::Process()
{
// returns true if expedition needs to be deleted from world cache and db
// expedition is not deleted until its dz has no clients to prevent exploits
auto status = m_dynamic_zone.Process(IsEmpty()); // force expire if no members
auto status = m_dynamic_zone.Process();
if (status == DynamicZoneStatus::ExpiredEmpty)
{
LogExpeditions("Expedition [{}] expired or empty, notifying zones and deleting", GetID());
@ -172,7 +173,13 @@ bool Expedition::Process()
void Expedition::UpdateMemberStatus(uint32_t character_id, DynamicZoneMemberStatus status)
{
SetInternalMemberStatus(character_id, status);
GetDynamicZone().SetInternalMemberStatus(character_id, status);
// temporary until move to using dz leader object completely
if (character_id == m_leader.id)
{
m_leader.status = GetDynamicZone().GetLeader().status;
}
// any member status update will trigger a leader fix if leader was offline
if (m_leader.status == DynamicZoneMemberStatus::Offline)
@ -183,7 +190,7 @@ void Expedition::UpdateMemberStatus(uint32_t character_id, DynamicZoneMemberStat
void Expedition::SendZoneMemberStatuses(uint16_t zone_id, uint16_t instance_id)
{
const auto& members = GetMembers();
const auto& members = GetDynamicZone().GetMembers();
uint32_t members_count = static_cast<uint32_t>(members.size());
uint32_t entries_size = sizeof(ServerExpeditionMemberStatusEntry_Struct) * members_count;
@ -210,7 +217,7 @@ void Expedition::CacheMemberStatuses()
all_clients.reserve(client_list.GetClientCount());
client_list.GetClients(zone_name.c_str(), all_clients);
for (const auto& member : m_members)
for (const auto& member : GetDynamicZone().GetMembers())
{
auto it = std::find_if(all_clients.begin(), all_clients.end(),
[&](const ClientListEntry* cle) { return (cle && cle->CharID() == member.id); });
@ -225,6 +232,6 @@ void Expedition::CacheMemberStatuses()
}
}
SetInternalMemberStatus(member.id, status);
GetDynamicZone().SetInternalMemberStatus(member.id, status);
}
}

View File

@ -21,26 +21,28 @@
#include "expedition_database.h"
#include "expedition.h"
#include "worlddb.h"
#include "../common/repositories/dynamic_zone_members_repository.h"
void ExpeditionDatabase::PurgeExpiredExpeditions()
{
std::string query = SQL(
SELECT
expeditions.id
expeditions.id,
expeditions.dynamic_zone_id
FROM expeditions
LEFT JOIN dynamic_zones ON expeditions.dynamic_zone_id = dynamic_zones.id
LEFT JOIN instance_list ON dynamic_zones.instance_id = instance_list.id
LEFT JOIN
(
SELECT expedition_id, COUNT(IF(is_current_member = TRUE, 1, NULL)) member_count
FROM expedition_members
GROUP BY expedition_id
) expedition_members
ON expedition_members.expedition_id = expeditions.id
SELECT dynamic_zone_id, COUNT(IF(is_current_member = TRUE, 1, NULL)) member_count
FROM dynamic_zone_members
GROUP BY dynamic_zone_id
) dynamic_zone_members
ON dynamic_zone_members.dynamic_zone_id = expeditions.dynamic_zone_id
WHERE
instance_list.id IS NULL
OR expedition_members.member_count IS NULL
OR expedition_members.member_count = 0
OR dynamic_zone_members.member_count IS NULL
OR dynamic_zone_members.member_count = 0
OR (instance_list.start_time + instance_list.duration) <= UNIX_TIMESTAMP();
);
@ -48,15 +50,18 @@ void ExpeditionDatabase::PurgeExpiredExpeditions()
if (results.Success())
{
std::vector<uint32_t> expedition_ids;
std::vector<uint32_t> dynamic_zone_ids;
for (auto row = results.begin(); row != results.end(); ++row)
{
expedition_ids.emplace_back(static_cast<uint32_t>(strtoul(row[0], nullptr, 10)));
dynamic_zone_ids.emplace_back(static_cast<uint32_t>(strtoul(row[1], nullptr, 10)));
}
if (!expedition_ids.empty())
{
ExpeditionDatabase::MoveMembersToSafeReturn(expedition_ids);
ExpeditionDatabase::DeleteExpeditions(expedition_ids);
DynamicZoneMembersRepository::RemoveAllMembers(database, dynamic_zone_ids);
}
}
}
@ -82,9 +87,6 @@ void ExpeditionDatabase::DeleteExpeditions(const std::vector<uint32_t>& expediti
auto query = fmt::format("DELETE FROM expeditions WHERE id IN ({});", expedition_ids_query);
database.QueryDatabase(query);
query = fmt::format("DELETE FROM expedition_members WHERE expedition_id IN ({});", expedition_ids_query);
database.QueryDatabase(query);
query = fmt::format("DELETE FROM expedition_lockouts WHERE expedition_id IN ({});", expedition_ids_query);
database.QueryDatabase(query);
}
@ -108,8 +110,8 @@ void ExpeditionDatabase::MoveMembersToSafeReturn(const std::vector<uint32_t>& ex
// only offline members still in expired dz zones should be updated here
std::string query = fmt::format(SQL(
UPDATE character_data
INNER JOIN expedition_members ON character_data.id = expedition_members.character_id
INNER JOIN expeditions ON expedition_members.expedition_id = expeditions.id
INNER JOIN dynamic_zone_members ON character_data.id = dynamic_zone_members.character_id
INNER JOIN expeditions ON dynamic_zone_members.dynamic_zone_id = expeditions.dynamic_zone_id
INNER JOIN dynamic_zones ON expeditions.dynamic_zone_id = dynamic_zones.id
INNER JOIN instance_list ON dynamic_zones.instance_id = instance_list.id
AND character_data.zone_instance = instance_list.id

View File

@ -22,8 +22,9 @@
#include "expedition.h"
#include "expedition_database.h"
#include "worlddb.h"
#include "../common/dynamic_zone_base.h"
#include "../common/eqemu_logsys.h"
#include "../common/repositories/expedition_members_repository.h"
#include "../common/repositories/dynamic_zone_members_repository.h"
#include <algorithm>
ExpeditionState expedition_state;
@ -76,16 +77,14 @@ void ExpeditionState::CacheExpeditions(
std::vector<ExpeditionsRepository::ExpeditionWithLeader>&& expedition_entries)
{
// bulk load expedition dzs and members before caching
std::vector<uint32_t> expedition_ids;
std::vector<uint32_t> dynamic_zone_ids;
for (const auto& entry : expedition_entries)
{
expedition_ids.emplace_back(entry.id);
dynamic_zone_ids.emplace_back(entry.dynamic_zone_id);
}
auto dynamic_zones = DynamicZonesRepository::GetWithInstance(database, dynamic_zone_ids);
auto expedition_members = ExpeditionMembersRepository::GetWithNames(database, expedition_ids);
auto dynamic_zone_members = DynamicZoneMembersRepository::GetWithNames(database, dynamic_zone_ids);
for (auto& entry : expedition_entries)
{
@ -102,11 +101,11 @@ void ExpeditionState::CacheExpeditions(
expedition->SetDynamicZone(std::move(*dz_entry_iter));
}
for (auto& member : expedition_members)
for (auto& member : dynamic_zone_members)
{
if (member.expedition_id == expedition->GetID())
if (member.dynamic_zone_id == entry.dynamic_zone_id)
{
expedition->AddMemberFromRepositoryResult(std::move(member));
expedition->GetDynamicZone().AddMemberFromRepositoryResult(std::move(member));
}
}
@ -129,7 +128,7 @@ void ExpeditionState::MemberChange(
if (remove) {
expedition->RemoveMember(member.id);
} else {
expedition->AddInternalMember(member);
expedition->GetDynamicZone().AddInternalMember(member);
}
}
}
@ -139,7 +138,7 @@ void ExpeditionState::RemoveAllMembers(uint32_t expedition_id)
auto expedition = GetExpedition(expedition_id);
if (expedition)
{
expedition->ClearInternalMembers();
expedition->GetDynamicZone().ClearInternalMembers();
}
}
@ -151,6 +150,7 @@ void ExpeditionState::Process()
}
std::vector<uint32_t> expedition_ids;
std::vector<uint32_t> dynamic_zone_ids;
for (auto it = m_expeditions.begin(); it != m_expeditions.end();)
{
@ -158,6 +158,7 @@ void ExpeditionState::Process()
if (is_deleted)
{
expedition_ids.emplace_back((*it)->GetID());
dynamic_zone_ids.emplace_back((*it)->GetDynamicZone().GetID());
}
it = is_deleted ? m_expeditions.erase(it) : it + 1;
}
@ -166,5 +167,6 @@ void ExpeditionState::Process()
{
ExpeditionDatabase::MoveMembersToSafeReturn(expedition_ids);
ExpeditionDatabase::DeleteExpeditions(expedition_ids);
DynamicZoneMembersRepository::RemoveAllMembers(database, dynamic_zone_ids);
}
}

View File

@ -1717,7 +1717,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
/* Task Packets */
LoadClientTaskState();
m_expedition_id = ExpeditionDatabase::GetExpeditionIDFromCharacterID(CharacterID());
m_expedition_id = ExpeditionsRepository::GetIDByMemberID(database, CharacterID());
/**
* DevTools Load Settings

View File

@ -6916,7 +6916,7 @@ void command_dz(Client* c, const Seperator* sep)
expedition->GetDynamicZone().GetZoneID(),
expedition->GetDynamicZone().GetInstanceID(),
expedition->GetDynamicZone().GetZoneVersion(),
expedition->GetMemberCount(),
expedition->GetDynamicZone().GetMemberCount(),
seconds / 3600, // hours
(seconds / 60) % 60, // minutes
seconds % 60 // seconds
@ -6982,12 +6982,12 @@ void command_dz(Client* c, const Seperator* sep)
c->Message(Chat::White, fmt::format(
"dz id: [{}] type: [{}] {}: [{}]:[{}]:[{}] members: [{}] remaining: [{:02}:{:02}:{:02}]",
dz.id,
dz.type,
DynamicZone::GetDynamicZoneTypeName(static_cast<DynamicZoneType>(dz.type)),
zone_saylink,
dz.zone,
dz.instance,
dz.version,
dz.player_count,
dz.member_count,
seconds / 3600, // hours
(seconds / 60) % 60, // minutes
seconds % 60 // seconds

View File

@ -27,8 +27,8 @@
#include "zonedb.h"
#include "../common/eqemu_logsys.h"
#include "../common/expedition_lockout_timer.h"
#include "../common/repositories/dynamic_zone_members_repository.h"
#include "../common/repositories/expedition_lockouts_repository.h"
#include "../common/repositories/expedition_members_repository.h"
#include "../common/util/uuid.h"
extern WorldServer worldserver;
@ -59,7 +59,7 @@ Expedition::Expedition(
void Expedition::SetDynamicZone(DynamicZone&& dz)
{
dz.SetName(GetName());
dz.SetLeaderName(GetLeaderName());
dz.SetLeader(GetLeader());
m_dynamiczone = std::move(dz);
m_dynamiczone.RegisterOnCompassChange([this]() { SendCompassUpdateToZoneMembers(); });
@ -125,7 +125,7 @@ Expedition* Expedition::TryCreate(
expedition->GetDynamicZone().GetMaxPlayers()
);
expedition->SaveMembers(request);
expedition->GetDynamicZone().SaveMembers(request.GetMembers());
expedition->SaveLockouts(request);
auto inserted = zone->expedition_cache.emplace(expedition_id, std::move(expedition));
@ -165,7 +165,7 @@ void Expedition::CacheExpeditions(
}
auto dynamic_zones = DynamicZonesRepository::GetWithInstance(database, dynamic_zone_ids);
auto expedition_members = ExpeditionMembersRepository::GetWithNames(database, expedition_ids);
auto dynamic_zone_members = DynamicZoneMembersRepository::GetWithNames(database, dynamic_zone_ids);
auto expedition_lockouts = ExpeditionLockoutsRepository::GetWithTimestamp(database, expedition_ids);
for (auto& entry : expedition_entries)
@ -183,11 +183,11 @@ void Expedition::CacheExpeditions(
expedition->SetDynamicZone(std::move(*dz_entry_iter));
}
for (auto& member : expedition_members)
for (auto& member : dynamic_zone_members)
{
if (member.expedition_id == expedition->GetID())
if (member.dynamic_zone_id == entry.dynamic_zone_id)
{
expedition->AddMemberFromRepositoryResult(std::move(member));
expedition->GetDynamicZone().AddMemberFromRepositoryResult(std::move(member));
}
}
@ -258,27 +258,13 @@ void Expedition::SaveLockouts(ExpeditionRequest& request)
ExpeditionDatabase::InsertLockouts(m_id, m_lockouts);
}
void Expedition::SaveMembers(ExpeditionRequest& request)
{
m_members = request.GetMembers();
std::vector<uint32_t> member_ids;
for (const auto& member : m_members)
{
member_ids.emplace_back(member.id);
}
ExpeditionDatabase::InsertMembers(m_id, m_members);
m_dynamiczone.SaveInstanceMembersToDatabase(member_ids);
}
Expedition* Expedition::FindCachedExpeditionByCharacterID(uint32_t character_id)
{
if (zone)
{
for (const auto& expedition : zone->expedition_cache)
{
if (expedition.second->HasMember(character_id))
if (expedition.second->GetDynamicZone().HasMember(character_id))
{
return expedition.second.get();
}
@ -293,7 +279,7 @@ Expedition* Expedition::FindCachedExpeditionByCharacterName(const std::string& c
{
for (const auto& expedition : zone->expedition_cache)
{
if (expedition.second->HasMember(char_name))
if (expedition.second->GetDynamicZone().HasMember(char_name))
{
return expedition.second.get();
}
@ -384,7 +370,7 @@ void Expedition::AddLockout(const ExpeditionLockoutTimer& lockout, bool members_
{
ExpeditionDatabase::InsertLockout(m_id, lockout);
}
ExpeditionDatabase::InsertMembersLockout(m_members, lockout);
ExpeditionDatabase::InsertMembersLockout(GetDynamicZone().GetMembers(), lockout);
ProcessLockoutUpdate(lockout, false, members_only);
SendWorldLockoutUpdate(lockout, false, members_only);
@ -414,7 +400,7 @@ void Expedition::AddLockoutDuration(const std::string& event_name, int seconds,
// processing lockout duration applies multiplier again in client methods,
// update database with modified value now but pass original on
int modified_seconds = static_cast<int>(seconds * RuleR(Expedition, LockoutDurationMultiplier));
ExpeditionDatabase::AddLockoutDuration(m_members, lockout, modified_seconds);
ExpeditionDatabase::AddLockoutDuration(GetDynamicZone().GetMembers(), lockout, modified_seconds);
ProcessLockoutDuration(lockout, seconds, members_only);
SendWorldLockoutDuration(lockout, seconds, members_only);
@ -442,7 +428,7 @@ void Expedition::UpdateLockoutDuration(
void Expedition::RemoveLockout(const std::string& event_name)
{
ExpeditionDatabase::DeleteLockout(m_id, event_name);
ExpeditionDatabase::DeleteMembersLockout(m_members, m_expedition_name, event_name);
ExpeditionDatabase::DeleteMembersLockout(GetDynamicZone().GetMembers(), m_expedition_name, event_name);
ExpeditionLockoutTimer lockout{m_uuid, m_expedition_name, event_name, 0, 0};
ProcessLockoutUpdate(lockout, true);
@ -451,12 +437,11 @@ void Expedition::RemoveLockout(const std::string& event_name)
bool Expedition::AddMember(const std::string& add_char_name, uint32_t add_char_id)
{
if (HasMember(add_char_id))
if (GetDynamicZone().HasMember(add_char_id))
{
return false;
}
ExpeditionDatabase::InsertMember(m_id, add_char_id);
m_dynamiczone.AddCharacter(add_char_id);
ProcessMemberAdded(add_char_name, add_char_id);
@ -469,23 +454,20 @@ void Expedition::RemoveAllMembers(bool enable_removal_timers)
{
m_dynamiczone.RemoveAllCharacters(enable_removal_timers);
ExpeditionDatabase::DeleteAllMembers(m_id);
SendUpdatesToZoneMembers(true);
SendWorldExpeditionUpdate(ServerOP_ExpeditionMembersRemoved);
m_members.clear();
GetDynamicZone().ClearInternalMembers();
}
bool Expedition::RemoveMember(const std::string& remove_char_name)
{
auto member = GetMemberData(remove_char_name);
auto member = GetDynamicZone().GetMemberData(remove_char_name);
if (!member.IsValid())
{
return false;
}
ExpeditionDatabase::DeleteMember(m_id, member.id);
m_dynamiczone.RemoveCharacter(member.id);
ProcessMemberRemoved(member.name, member.id);
@ -501,15 +483,13 @@ void Expedition::SwapMember(Client* add_client, const std::string& remove_char_n
return;
}
auto member = GetMemberData(remove_char_name);
auto member = GetDynamicZone().GetMemberData(remove_char_name);
if (!member.IsValid())
{
return;
}
// make remove and add atomic to avoid racing with separate world messages
ExpeditionDatabase::DeleteMember(m_id, member.id);
ExpeditionDatabase::InsertMember(m_id, add_client->CharacterID());
m_dynamiczone.RemoveCharacter(member.id);
m_dynamiczone.AddCharacter(add_client->CharacterID());
@ -529,19 +509,19 @@ void Expedition::SetMemberStatus(Client* client, DynamicZoneMemberStatus status)
void Expedition::SendMemberStatusToZoneMembers(uint32_t update_member_id, DynamicZoneMemberStatus status)
{
auto member_data = GetMemberData(update_member_id);
auto member_data = GetDynamicZone().GetMemberData(update_member_id);
if (!member_data.IsValid())
{
return;
}
// if zone already had this member status cached avoid packet update to clients
bool changed = SetInternalMemberStatus(update_member_id, status);
bool changed = GetDynamicZone().SetInternalMemberStatus(update_member_id, status);
if (changed)
{
member_data = GetMemberData(update_member_id); // rules may override status
member_data = GetDynamicZone().GetMemberData(update_member_id); // rules may override status
auto outapp_member_status = CreateMemberListStatusPacket(member_data.name, member_data.status);
for (auto& member : m_members)
for (auto& member : GetDynamicZone().GetMembers())
{
Client* member_client = entity_list.GetClientByCharID(member.id);
if (member_client)
@ -673,7 +653,7 @@ bool Expedition::ProcessAddConflicts(Client* leader_client, Client* add_client,
// member swapping integrity is handled by invite response
if (!swapping)
{
auto member_count = ExpeditionDatabase::GetMemberCount(m_id);
auto member_count = GetDynamicZone().GetDatabaseMemberCount();
if (member_count == 0)
{
has_conflict = true;
@ -734,8 +714,8 @@ void Expedition::DzInviteResponse(Client* add_client, bool accepted, const std::
// error if swapping and character was already removed before the accept
if (was_swap_invite)
{
auto swap_member = GetMemberData(swap_remove_name);
if (!swap_member.IsValid() || !ExpeditionDatabase::HasMember(m_id, swap_member.id))
auto swap_member = GetDynamicZone().GetMemberData(swap_remove_name);
if (!swap_member.IsValid() || !GetDynamicZone().HasDatabaseMember(swap_member.id))
{
has_conflicts = true;
}
@ -852,7 +832,7 @@ void Expedition::DzAddPlayer(
}
else
{
auto member_data = GetMemberData(add_char_name);
auto member_data = GetDynamicZone().GetMemberData(add_char_name);
if (member_data.IsValid())
{
// live prioritizes offline message before already a member message
@ -950,7 +930,7 @@ void Expedition::DzSwapPlayer(
return;
}
if (remove_char_name.empty() || !HasMember(remove_char_name))
if (remove_char_name.empty() || !GetDynamicZone().HasMember(remove_char_name))
{
requester->MessageString(Chat::Red, DZSWAP_CANNOT_REMOVE, FormatName(remove_char_name).c_str());
return;
@ -966,7 +946,7 @@ void Expedition::DzPlayerList(Client* requester)
requester->MessageString(Chat::Yellow, EXPEDITION_LEADER, m_leader.name.c_str());
std::string member_names;
for (const auto& member : m_members)
for (const auto& member : GetDynamicZone().GetMembers())
{
fmt::format_to(std::back_inserter(member_names), "{}, ", member.name);
}
@ -1017,7 +997,7 @@ void Expedition::SetLocked(
void Expedition::ProcessLeaderChanged(uint32_t new_leader_id)
{
auto new_leader = GetMemberData(new_leader_id);
auto new_leader = GetDynamicZone().GetMemberData(new_leader_id);
if (!new_leader.IsValid())
{
LogExpeditions("Processed invalid new leader id [{}] for expedition [{}]", new_leader_id, m_id);
@ -1027,11 +1007,11 @@ void Expedition::ProcessLeaderChanged(uint32_t new_leader_id)
LogExpeditionsModerate("Replaced [{}] leader [{}] with [{}]", m_id, m_leader.name, new_leader.name);
m_leader = new_leader;
m_dynamiczone.SetLeaderName(m_leader.name);
m_dynamiczone.SetLeader(m_leader);
// update each client's expedition window in this zone
auto outapp_leader = CreateLeaderNamePacket();
for (const auto& member : m_members)
for (const auto& member : GetDynamicZone().GetMembers())
{
Client* member_client = entity_list.GetClientByCharID(member.id);
if (member_client)
@ -1074,7 +1054,7 @@ void Expedition::ProcessMakeLeader(Client* old_leader_client, Client* new_leader
void Expedition::ProcessMemberAdded(const std::string& char_name, uint32_t added_char_id)
{
AddInternalMember({ added_char_id, char_name, DynamicZoneMemberStatus::Online });
GetDynamicZone().AddInternalMember({ added_char_id, char_name, DynamicZoneMemberStatus::Online });
// adds the member to this expedition and notifies both leader and new member
Client* leader_client = entity_list.GetClientByCharID(m_leader.id);
@ -1097,24 +1077,22 @@ void Expedition::ProcessMemberAdded(const std::string& char_name, uint32_t added
void Expedition::ProcessMemberRemoved(const std::string& removed_char_name, uint32_t removed_char_id)
{
if (m_members.empty())
if (GetDynamicZone().GetMembers().empty())
{
return;
}
auto outapp_member_name = CreateMemberListNamePacket(removed_char_name, true);
for (auto it = m_members.begin(); it != m_members.end();)
for (const auto& member : GetDynamicZone().GetMembers())
{
bool is_removed = (it->name == removed_char_name);
Client* member_client = entity_list.GetClientByCharID(it->id);
Client* member_client = entity_list.GetClientByCharID(member.id);
if (member_client)
{
// all members receive the removed player name packet
member_client->QueuePacket(outapp_member_name.get());
if (is_removed)
if (member.id == removed_char_id)
{
// live doesn't clear expedition info on clients removed while inside dz.
// it instead let's the dz kick timer do it even if character zones out
@ -1123,17 +1101,15 @@ void Expedition::ProcessMemberRemoved(const std::string& removed_char_name, uint
member_client->SendDzCompassUpdate();
member_client->QueuePacket(CreateInfoPacket(true).get());
member_client->MessageString(Chat::Yellow, EXPEDITION_REMOVED,
it->name.c_str(), m_expedition_name.c_str());
member.name.c_str(), m_expedition_name.c_str());
}
}
it = is_removed ? m_members.erase(it) : it + 1;
}
LogExpeditionsDetail(
"Processed member [{}] ({}) removal from [{}], cache member count: [{}]",
removed_char_name, removed_char_id, m_id, m_members.size()
);
GetDynamicZone().RemoveInternalMember(removed_char_id);
LogExpeditionsDetail("Processed member [{}] ({}) removal from [{}], cache member count: [{}]",
removed_char_name, removed_char_id, m_id, GetDynamicZone().GetMemberCount());
}
void Expedition::ProcessLockoutDuration(
@ -1152,7 +1128,7 @@ void Expedition::ProcessLockoutDuration(
}
}
for (const auto& member : m_members)
for (const auto& member : GetDynamicZone().GetMembers())
{
Client* member_client = entity_list.GetClientByCharID(member.id);
if (member_client)
@ -1205,7 +1181,7 @@ void Expedition::ProcessLockoutUpdate(
}
}
for (const auto& member : m_members)
for (const auto& member : GetDynamicZone().GetMembers())
{
Client* member_client = entity_list.GetClientByCharID(member.id);
if (member_client)
@ -1254,7 +1230,7 @@ void Expedition::SendMemberListToZoneMembers()
{
auto outapp_members = CreateMemberListPacket(false);
for (const auto& member : m_members)
for (const auto& member : GetDynamicZone().GetMembers())
{
Client* member_client = entity_list.GetClientByCharID(member.id);
if (member_client)
@ -1266,12 +1242,12 @@ void Expedition::SendMemberListToZoneMembers()
void Expedition::SendUpdatesToZoneMembers(bool clear, bool message_on_clear)
{
if (!m_members.empty())
if (GetDynamicZone().HasMembers())
{
auto outapp_info = CreateInfoPacket(clear);
auto outapp_members = CreateMemberListPacket(clear);
for (const auto& member : m_members)
for (const auto& member : GetDynamicZone().GetMembers())
{
Client* member_client = entity_list.GetClientByCharID(member.id);
if (member_client)
@ -1351,7 +1327,7 @@ std::unique_ptr<EQApplicationPacket> Expedition::CreateInvitePacket(
std::unique_ptr<EQApplicationPacket> Expedition::CreateMemberListPacket(bool clear)
{
uint32_t member_count = clear ? 0 : static_cast<uint32_t>(m_members.size());
uint32_t member_count = clear ? 0 : static_cast<uint32_t>(GetDynamicZone().GetMemberCount());
uint32_t member_entries_size = sizeof(DynamicZoneMemberEntry_Struct) * member_count;
uint32_t outsize = sizeof(DynamicZoneMemberList_Struct) + member_entries_size;
auto outapp = std::make_unique<EQApplicationPacket>(OP_DzMemberList, outsize);
@ -1361,10 +1337,11 @@ std::unique_ptr<EQApplicationPacket> Expedition::CreateMemberListPacket(bool cle
if (!clear)
{
for (auto i = 0; i < m_members.size(); ++i)
const auto& members = GetDynamicZone().GetMembers();
for (auto i = 0; i < members.size(); ++i)
{
strn0cpy(buf->members[i].name, m_members[i].name.c_str(), sizeof(buf->members[i].name));
buf->members[i].online_status = static_cast<uint8_t>(m_members[i].status);
strn0cpy(buf->members[i].name, members[i].name.c_str(), sizeof(buf->members[i].name));
buf->members[i].online_status = static_cast<uint8_t>(members[i].status);
}
}
@ -1662,7 +1639,7 @@ void Expedition::HandleWorldMessage(ServerPacket* pack)
if (expedition)
{
expedition->SendUpdatesToZoneMembers(true);
expedition->m_members.clear();
expedition->GetDynamicZone().ClearInternalMembers();
}
}
break;
@ -1785,7 +1762,7 @@ void Expedition::HandleWorldMessage(ServerPacket* pack)
for (uint32_t i = 0; i < buf->count; ++i)
{
auto status = static_cast<DynamicZoneMemberStatus>(buf->entries[i].online_status);
expedition->SetInternalMemberStatus(buf->entries[i].character_id, status);
expedition->GetDynamicZone().SetInternalMemberStatus(buf->entries[i].character_id, status);
}
expedition->SendMemberListToZoneMembers();
}
@ -1865,7 +1842,7 @@ void Expedition::HandleWorldMessage(ServerPacket* pack)
void Expedition::SendCompassUpdateToZoneMembers()
{
for (const auto& member : m_members)
for (const auto& member : GetDynamicZone().GetMembers())
{
Client* member_client = entity_list.GetClientByCharID(member.id);
if (member_client)
@ -1979,7 +1956,7 @@ void Expedition::SendMembersExpireWarning(uint32_t minutes_remaining)
{
// expeditions warn members in all zones not just the dz
auto outapp = CreateExpireWarningPacket(minutes_remaining);
for (const auto& member : m_members)
for (const auto& member : GetDynamicZone().GetMembers())
{
Client* member_client = entity_list.GetClientByCharID(member.id);
if (member_client)

View File

@ -142,7 +142,6 @@ private:
void ProcessMemberAdded(const std::string& added_char_name, uint32_t added_char_id);
void ProcessMemberRemoved(const std::string& removed_char_name, uint32_t removed_char_id);
void SaveLockouts(ExpeditionRequest& request);
void SaveMembers(ExpeditionRequest& request);
void SendClientExpeditionInvite(
Client* client, const std::string& inviter_name, const std::string& swap_remove_name);
void SendLeaderMessage(Client* leader_client, uint16_t chat_type, uint32_t string_id,

View File

@ -213,67 +213,6 @@ void ExpeditionDatabase::DeleteLockout(uint32_t expedition_id, const std::string
database.QueryDatabase(query);
}
uint32_t ExpeditionDatabase::GetExpeditionIDFromCharacterID(uint32_t character_id)
{
LogExpeditionsDetail("Getting expedition id for character [{}]", character_id);
uint32_t expedition_id = 0;
auto query = fmt::format(SQL(
SELECT expedition_id FROM expedition_members
WHERE character_id = {} AND is_current_member = TRUE;
), character_id);
auto results = database.QueryDatabase(query);
if (results.Success() && results.RowCount() > 0)
{
auto row = results.begin();
expedition_id = strtoul(row[0], nullptr, 10);
}
return expedition_id;
}
uint32_t ExpeditionDatabase::GetMemberCount(uint32_t expedition_id)
{
LogExpeditionsDetail("Getting expedition [{}] member count from db", expedition_id);
uint32_t member_count = 0;
if (expedition_id != 0)
{
auto query = fmt::format(SQL(
SELECT COUNT(*)
FROM expedition_members
WHERE expedition_id = {} AND is_current_member = TRUE;
), expedition_id);
auto results = database.QueryDatabase(query);
if (results.Success() && results.RowCount() > 0)
{
auto row = results.begin();
member_count = strtoul(row[0], nullptr, 10);
}
}
return member_count;
}
bool ExpeditionDatabase::HasMember(uint32_t expedition_id, uint32_t character_id)
{
LogExpeditionsDetail("Checking db expedition [{}] for character [{}]", expedition_id, character_id);
if (expedition_id == 0 || character_id == 0)
{
return false;
}
auto query = fmt::format(SQL(
SELECT id
FROM expedition_members
WHERE expedition_id = {} AND character_id = {} AND is_current_member = TRUE;
), expedition_id, character_id);
auto results = database.QueryDatabase(query);
return (results.Success() && results.RowCount() > 0);
}
void ExpeditionDatabase::InsertCharacterLockouts(uint32_t character_id,
const std::vector<ExpeditionLockoutTimer>& lockouts)
{
@ -415,50 +354,6 @@ void ExpeditionDatabase::InsertLockouts(
}
}
void ExpeditionDatabase::InsertMember(uint32_t expedition_id, uint32_t character_id)
{
LogExpeditionsDetail("Inserting character [{}] into expedition [{}]", character_id, expedition_id);
auto query = fmt::format(SQL(
INSERT INTO expedition_members
(expedition_id, character_id)
VALUES
({}, {})
ON DUPLICATE KEY UPDATE is_current_member = TRUE;
), expedition_id, character_id);
database.QueryDatabase(query);
}
void ExpeditionDatabase::InsertMembers(
uint32_t expedition_id, const std::vector<DynamicZoneMember>& members)
{
LogExpeditionsDetail("Inserting characters into expedition [{}]", expedition_id);
std::string insert_values;
for (const auto& member : members)
{
fmt::format_to(std::back_inserter(insert_values),
"({}, {}),",
expedition_id, member.id
);
}
if (!insert_values.empty())
{
insert_values.pop_back(); // trailing comma
auto query = fmt::format(SQL(
INSERT INTO expedition_members
(expedition_id, character_id)
VALUES {}
ON DUPLICATE KEY UPDATE is_current_member = TRUE;
), insert_values);
database.QueryDatabase(query);
}
}
void ExpeditionDatabase::UpdateLockState(uint32_t expedition_id, bool is_locked)
{
LogExpeditionsDetail("Updating lock state [{}] for expedition [{}]", is_locked, expedition_id);
@ -470,29 +365,6 @@ void ExpeditionDatabase::UpdateLockState(uint32_t expedition_id, bool is_locked)
database.QueryDatabase(query);
}
void ExpeditionDatabase::DeleteMember(uint32_t expedition_id, uint32_t character_id)
{
LogExpeditionsDetail("Removing member [{}] from expedition [{}]", character_id, expedition_id);
auto query = fmt::format(SQL(
UPDATE expedition_members SET is_current_member = FALSE
WHERE expedition_id = {} AND character_id = {};
), expedition_id, character_id);
database.QueryDatabase(query);
}
void ExpeditionDatabase::DeleteAllMembers(uint32_t expedition_id)
{
LogExpeditionsDetail("Removing all members of expedition [{}]", expedition_id);
auto query = fmt::format(SQL(
UPDATE expedition_members SET is_current_member = FALSE WHERE expedition_id = {};
), expedition_id);
database.QueryDatabase(query);
}
void ExpeditionDatabase::UpdateReplayLockoutOnJoin(uint32_t expedition_id, bool add_on_join)
{
LogExpeditionsDetail("Updating replay lockout on join [{}] for expedition [{}]", add_on_join, expedition_id);

View File

@ -41,8 +41,6 @@ namespace ExpeditionDatabase
std::vector<ExpeditionLockoutTimer> LoadCharacterLockouts(uint32_t character_id);
std::vector<ExpeditionLockoutTimer> LoadCharacterLockouts(uint32_t character_id,
const std::string& expedition_name);
void DeleteAllMembers(uint32_t expedition_id);
void DeleteMember(uint32_t expedition_id, uint32_t character_id);
void DeleteAllCharacterLockouts(uint32_t character_id);
void DeleteAllCharacterLockouts(uint32_t character_id, const std::string& expedition_name);
void DeleteCharacterLockout(uint32_t character_id, const std::string& expedition_name,
@ -50,9 +48,6 @@ namespace ExpeditionDatabase
void DeleteLockout(uint32_t expedition_id, const std::string& event_name);
void DeleteMembersLockout(const std::vector<DynamicZoneMember>& members,
const std::string& expedition_name, const std::string& event_name);
uint32_t GetExpeditionIDFromCharacterID(uint32_t character_id);
uint32_t GetMemberCount(uint32_t expedition_id);
bool HasMember(uint32_t expedition_id, uint32_t character_id);
void InsertCharacterLockouts(uint32_t character_id,
const std::vector<ExpeditionLockoutTimer>& lockouts);
void InsertMembersLockout(const std::vector<DynamicZoneMember>& members,
@ -60,8 +55,6 @@ namespace ExpeditionDatabase
void InsertLockout(uint32_t expedition_id, const ExpeditionLockoutTimer& lockout);
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 InsertMembers(uint32_t expedition_id, const std::vector<DynamicZoneMember>& members);
void UpdateLockState(uint32_t expedition_id, bool is_locked);
void UpdateReplayLockoutOnJoin(uint32_t expedition_id, bool add_on_join);
void AddLockoutDuration(const std::vector<DynamicZoneMember>& members,

View File

@ -47,8 +47,8 @@ public:
const std::string& GetNotAllAddedMessage() const { return m_not_all_added_msg; }
uint32_t GetMinPlayers() const { return m_min_players; }
uint32_t GetMaxPlayers() const { return m_max_players; }
std::vector<DynamicZoneMember> GetMembers() const { return m_members; }
std::unordered_map<std::string, ExpeditionLockoutTimer> GetLockouts() const { return m_lockouts; }
const std::vector<DynamicZoneMember>& GetMembers() const { return m_members; }
const std::unordered_map<std::string, ExpeditionLockoutTimer>& GetLockouts() const { return m_lockouts; }
private:
bool CanMembersJoin(const std::vector<std::string>& member_names);

View File

@ -104,7 +104,7 @@ std::string Lua_Expedition::GetLootEventBySpawnID(uint32_t spawn_id) {
uint32_t Lua_Expedition::GetMemberCount() {
Lua_Safe_Call_Int();
return self->GetMemberCount();
return self->GetDynamicZone().GetMemberCount();
}
luabind::object Lua_Expedition::GetMembers(lua_State* L) {
@ -113,7 +113,7 @@ luabind::object Lua_Expedition::GetMembers(lua_State* L) {
if (d_)
{
auto self = reinterpret_cast<NativeType*>(d_);
for (const auto& member : self->GetMembers())
for (const auto& member : self->GetDynamicZone().GetMembers())
{
lua_table[member.name] = member.id;
}

View File

@ -247,7 +247,7 @@ XS(XS_Expedition_GetMemberCount) {
Expedition* THIS = nullptr;
VALIDATE_THIS_IS_EXPEDITION;
XSRETURN_UV(THIS->GetMemberCount());
XSRETURN_UV(THIS->GetDynamicZone().GetMemberCount());
}
XS(XS_Expedition_GetMembers);
@ -262,8 +262,7 @@ XS(XS_Expedition_GetMembers) {
HV* hash = newHV();
auto members = THIS->GetMembers();
for (const auto& member : members)
for (const auto& member : THIS->GetDynamicZone().GetMembers())
{
hv_store(hash, member.name.c_str(), static_cast<uint32_t>(member.name.size()),
newSVuv(member.id), 0);