[Expeditions] Move expedition code into DynamicZone (#4672)

This removes the separate Expedition class and moves lockout code and
/dz command handlers into DynamicZone classes. It also refactors some
code to reduce bloat and some database usage.

This completes the effort of moving everything to DynamicZone that
started when implementing shared tasks. It also makes sense to do this
since expeditions are just dynamic zones internally despite dzs being
used for other types. Expedition specific things are just handled with
dz type checks.

Functionally nothing should change. This is mainly internal refactoring
and moving code around along with some bug fixes and reduced database
usage.

Main changes:

 - The `expeditions` database table has been removed

 - Expeditions no longer use a separate id, the expedition id is just the dz id

 - Expedition lock state and replay timer option were moved to the
   `dynamic_zones` table

 - Expeditions no longer have a separate cache from dynamic zones

 - Expedition creation no longer has every zone query the database to cache it

 - Expedition internal lockouts are now stored on DynamicZone

 - The `expedition_lockouts` table has been renamed to `dynamic_zone_lockouts`

 - Fixed a small bug with the UpdateLockoutDuration api where the
   internal lockout would get the time added twice in memory in the
   initiating zone (this api is likely rarely used)

 - Fixed an issue where use of the group/raid DoesAnyMemberHaveExpeditionLockout
   api would query once for every out of zone character.

   - This api now checks all members in the current zone first and only
     performs a single bulk query for out of zone members if that check
     is exhausted

 - Deprecated the max_check_count param of DoesAnyMemberHaveExpeditionLockout,
   the quest api still exists to avoid api break but a passed arg has no effect
This commit is contained in:
hg
2025-02-15 19:40:35 -05:00
committed by GitHub
parent ab4e1191ef
commit 55155ff800
78 changed files with 2889 additions and 4778 deletions
+4 -6
View File
@@ -22,6 +22,7 @@ SET(common_sources
dbcore.cpp
deity.cpp
dynamic_zone_base.cpp
dynamic_zone_lockout.cpp
emu_constants.cpp
emu_limits.cpp
emu_opcodes.cpp
@@ -40,7 +41,6 @@ SET(common_sources
events/player_event_logs.cpp
events/player_event_discord_formatter.cpp
evolving_items.cpp
expedition_lockout_timer.cpp
extprofile.cpp
discord/discord_manager.cpp
faction.cpp
@@ -213,10 +213,9 @@ 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_lockouts_repository.h
repositories/base/base_dynamic_zone_members_repository.h
repositories/base/base_dynamic_zone_templates_repository.h
repositories/base/base_expeditions_repository.h
repositories/base/base_expedition_lockouts_repository.h
repositories/base/base_faction_association_repository.h
repositories/base/base_faction_base_data_repository.h
repositories/base/base_faction_list_repository.h
@@ -410,10 +409,9 @@ SET(repositories
repositories/discovered_items_repository.h
repositories/doors_repository.h
repositories/dynamic_zones_repository.h
repositories/dynamic_zone_lockouts_repository.h
repositories/dynamic_zone_members_repository.h
repositories/dynamic_zone_templates_repository.h
repositories/expeditions_repository.h
repositories/expedition_lockouts_repository.h
repositories/faction_association_repository.h
repositories/faction_base_data_repository.h
repositories/faction_list_repository.h
@@ -561,6 +559,7 @@ SET(common_headers
discord/discord.h
discord/discord_manager.h
dynamic_zone_base.h
dynamic_zone_lockout.h
emu_constants.h
emu_limits.h
emu_opcodes.h
@@ -587,7 +586,6 @@ SET(common_headers
events/player_events.h
event_sub.h
evolving_items.h
expedition_lockout_timer.h
extprofile.h
faction.h
file.h
+26 -1
View File
@@ -6812,7 +6812,32 @@ ALTER TABLE `guild_bank`
ALTER TABLE `guild_bank`
ADD INDEX `guild_id` (`guild_id`);
)"
}
},
ManifestEntry{
.version = 9305,
.description = "2024_12_01_expedition_dz_merge.sql",
.check = "SHOW COLUMNS FROM `dynamic_zones` LIKE 'is_locked'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `dynamic_zones`
ADD COLUMN `is_locked` TINYINT NOT NULL DEFAULT '0' AFTER `has_zone_in`,
ADD COLUMN `add_replay` TINYINT NOT NULL DEFAULT '1' AFTER `is_locked`;
ALTER TABLE `expedition_lockouts`
CHANGE COLUMN `expedition_id` `dynamic_zone_id` INT(10) UNSIGNED NOT NULL AFTER `id`,
DROP INDEX `expedition_id_event_name`,
ADD UNIQUE INDEX `dz_id_event_name` (`dynamic_zone_id`, `event_name`) USING BTREE;
UPDATE expedition_lockouts lockouts
INNER JOIN expeditions ON lockouts.dynamic_zone_id = expeditions.id
SET lockouts.dynamic_zone_id = expeditions.dynamic_zone_id;
DROP TABLE `expeditions`;
RENAME TABLE `expedition_lockouts` TO `dynamic_zone_lockouts`;
)"
},
// -- template; copy/paste this when you need to create a new entry
// ManifestEntry{
// .version = 9228,
+1 -2
View File
@@ -311,10 +311,9 @@ namespace DatabaseSchema {
"completed_shared_task_members",
"completed_shared_tasks",
"discord_webhooks",
"dynamic_zone_lockouts",
"dynamic_zone_members",
"dynamic_zones",
"expedition_lockouts",
"expeditions",
"gm_ips",
"group_id",
"group_leaders",
+293 -64
View File
@@ -1,11 +1,13 @@
#include "dynamic_zone_base.h"
#include "database.h"
#include "eqemu_logsys.h"
#include "repositories/instance_list_repository.h"
#include "repositories/instance_list_player_repository.h"
#include "rulesys.h"
#include "servertalk.h"
#include "util/uuid.h"
#include "repositories/character_expedition_lockouts_repository.h"
#include "repositories/dynamic_zone_lockouts_repository.h"
#include "repositories/instance_list_repository.h"
#include "repositories/instance_list_player_repository.h"
DynamicZoneBase::DynamicZoneBase(DynamicZonesRepository::DynamicZoneInstance&& entry)
{
@@ -93,13 +95,15 @@ void DynamicZoneBase::LoadRepositoryResult(DynamicZonesRepository::DynamicZoneIn
m_zonein.y = dz_entry.zone_in_y;
m_zonein.z = dz_entry.zone_in_z;
m_zonein.heading = dz_entry.zone_in_heading;
m_has_zonein = (dz_entry.has_zone_in != 0);
m_has_zonein = dz_entry.has_zone_in != 0;
m_is_locked = dz_entry.is_locked;
m_add_replay = dz_entry.add_replay;
// instance_list portion
m_zone_id = dz_entry.zone;
m_zone_version = dz_entry.version;
m_start_time = std::chrono::system_clock::from_time_t(dz_entry.start_time);
m_duration = std::chrono::seconds(dz_entry.duration);
m_never_expires = (dz_entry.never_expires != 0);
m_never_expires = dz_entry.never_expires != 0;
m_expire_time = m_start_time + m_duration;
}
@@ -119,37 +123,40 @@ void DynamicZoneBase::AddMemberFromRepositoryResult(
uint32_t DynamicZoneBase::SaveToDatabase()
{
LogDynamicZonesDetail("Saving dz instance [{}] to database", m_instance_id);
if (m_instance_id != 0)
if (m_instance_id == 0)
{
auto insert_dz = DynamicZonesRepository::NewEntity();
insert_dz.uuid = m_uuid;
insert_dz.name = m_name;
insert_dz.leader_id = m_leader.id;
insert_dz.min_players = m_min_players;
insert_dz.max_players = m_max_players;
insert_dz.instance_id = m_instance_id,
insert_dz.type = static_cast<int>(m_type);
insert_dz.dz_switch_id = m_dz_switch_id;
insert_dz.compass_zone_id = m_compass.zone_id;
insert_dz.compass_x = m_compass.x;
insert_dz.compass_y = m_compass.y;
insert_dz.compass_z = m_compass.z;
insert_dz.safe_return_zone_id = m_safereturn.zone_id;
insert_dz.safe_return_x = m_safereturn.x;
insert_dz.safe_return_y = m_safereturn.y;
insert_dz.safe_return_z = m_safereturn.z;
insert_dz.safe_return_heading = m_safereturn.heading;
insert_dz.zone_in_x = m_zonein.x;
insert_dz.zone_in_y = m_zonein.y;
insert_dz.zone_in_z = m_zonein.z;
insert_dz.zone_in_heading = m_zonein.heading;
insert_dz.has_zone_in = m_has_zonein;
auto inserted_dz = DynamicZonesRepository::InsertOne(GetDatabase(), insert_dz);
return inserted_dz.id;
return 0;
}
return 0;
auto dz = DynamicZonesRepository::NewEntity();
dz.uuid = m_uuid;
dz.name = m_name;
dz.leader_id = m_leader.id;
dz.min_players = m_min_players;
dz.max_players = m_max_players;
dz.instance_id = static_cast<int32_t>(m_instance_id),
dz.type = static_cast<uint8_t>(m_type);
dz.dz_switch_id = m_dz_switch_id;
dz.compass_zone_id = m_compass.zone_id;
dz.compass_x = m_compass.x;
dz.compass_y = m_compass.y;
dz.compass_z = m_compass.z;
dz.safe_return_zone_id = m_safereturn.zone_id;
dz.safe_return_x = m_safereturn.x;
dz.safe_return_y = m_safereturn.y;
dz.safe_return_z = m_safereturn.z;
dz.safe_return_heading = m_safereturn.heading;
dz.zone_in_x = m_zonein.x;
dz.zone_in_y = m_zonein.y;
dz.zone_in_z = m_zonein.z;
dz.zone_in_heading = m_zonein.heading;
dz.has_zone_in = static_cast<uint8_t>(m_has_zonein);
dz.is_locked = static_cast<int8_t>(m_is_locked);
dz.add_replay = static_cast<int8_t>(m_add_replay);
dz = DynamicZonesRepository::InsertOne(GetDatabase(), std::move(dz));
return dz.id;
}
bool DynamicZoneBase::AddMember(const DynamicZoneMember& add_member)
@@ -196,10 +203,9 @@ bool DynamicZoneBase::RemoveMember(const DynamicZoneMember& remove_member)
return true;
}
bool DynamicZoneBase::SwapMember(
const DynamicZoneMember& add_member, const std::string& remove_char_name)
bool DynamicZoneBase::SwapMember(const DynamicZoneMember& add_member, const std::string& remove_name)
{
auto remove_member = GetMemberData(remove_char_name);
auto remove_member = GetMemberData(remove_name);
if (!add_member.IsValid() || !remove_member.IsValid())
{
return false;
@@ -230,9 +236,18 @@ void DynamicZoneBase::RemoveAllMembers()
void DynamicZoneBase::SaveMembers(const std::vector<DynamicZoneMember>& members)
{
if (members.empty())
{
return;
}
LogDynamicZonesDetail("Saving [{}] member(s) for dz [{}]", members.size(), m_id);
m_members = members;
if (m_members.size() > m_max_players)
{
m_members.resize(m_max_players);
}
// the lower level instance_list_players needs to be kept updated as well
std::vector<DynamicZoneMembersRepository::DynamicZoneMembers> insert_members;
@@ -242,12 +257,12 @@ void DynamicZoneBase::SaveMembers(const std::vector<DynamicZoneMember>& members)
DynamicZoneMembersRepository::DynamicZoneMembers member_entry{};
member_entry.dynamic_zone_id = m_id;
member_entry.character_id = member.id;
insert_members.emplace_back(member_entry);
insert_members.push_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::InstanceListPlayer player_entry{};
player_entry.id = m_instance_id;
player_entry.charid = member.id;
insert_players.push_back(player_entry);
}
DynamicZoneMembersRepository::InsertOrUpdateMany(GetDatabase(), insert_members);
@@ -339,6 +354,44 @@ void DynamicZoneBase::SetLeader(const DynamicZoneMember& new_leader, bool update
}
}
void DynamicZoneBase::SetLocked(bool lock, bool update_db, DzLockMsg lock_msg, uint32_t color)
{
m_is_locked = lock;
if (update_db)
{
DynamicZonesRepository::UpdateLocked(GetDatabase(), m_id, lock);
ServerPacket pack(ServerOP_DzLock, sizeof(ServerDzLock_Struct));
auto buf = reinterpret_cast<ServerDzLock_Struct*>(pack.pBuffer);
buf->dz_id = GetID();
buf->sender_zone_id = GetCurrentZoneID();
buf->sender_instance_id = GetCurrentInstanceID();
buf->lock = m_is_locked;
buf->lock_msg = static_cast<uint8_t>(lock_msg);
buf->color = color;
SendServerPacket(&pack);
}
}
void DynamicZoneBase::SetReplayOnJoin(bool enabled, bool update_db)
{
m_add_replay = enabled;
if (update_db)
{
DynamicZonesRepository::UpdateReplayOnJoin(GetDatabase(), m_id, enabled);
ServerPacket pack(ServerOP_DzReplayOnJoin, sizeof(ServerDzBool_Struct));
auto buf = reinterpret_cast<ServerDzBool_Struct*>(pack.pBuffer);
buf->dz_id = GetID();
buf->sender_zone_id = GetCurrentZoneID();
buf->sender_instance_id = GetCurrentInstanceID();
buf->enabled = enabled;
SendServerPacket(&pack);
}
}
uint32_t DynamicZoneBase::GetSecondsRemaining() const
{
auto remaining = std::chrono::duration_cast<std::chrono::seconds>(GetDurationRemaining()).count();
@@ -478,13 +531,13 @@ void DynamicZoneBase::RemoveInternalMember(uint32_t character_id)
), m_members.end());
}
bool DynamicZoneBase::HasMember(uint32_t character_id)
bool DynamicZoneBase::HasMember(uint32_t character_id) const
{
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)
bool DynamicZoneBase::HasMember(const std::string& character_name) const
{
return std::any_of(m_members.begin(), m_members.end(),
[&](const DynamicZoneMember& member) {
@@ -590,35 +643,34 @@ std::string DynamicZoneBase::GetDynamicZoneTypeName(DynamicZoneType dz_type)
}
}
EQ::Net::DynamicPacket DynamicZoneBase::GetSerializedDzPacket()
std::unique_ptr<ServerPacket> DynamicZoneBase::CreateServerPacket(uint16_t zone_id, uint16_t instance_id)
{
EQ::Net::DynamicPacket dyn_pack;
dyn_pack.PutSerialize(0, *this);
std::ostringstream ss = GetSerialized();
std::string_view sv = ss.view();
LogDynamicZonesDetail("Serialized server dz size [{}]", dyn_pack.Length());
return dyn_pack;
}
std::unique_ptr<ServerPacket> DynamicZoneBase::CreateServerDzCreatePacket(
uint16_t origin_zone_id, uint16_t origin_instance_id)
{
EQ::Net::DynamicPacket dyn_pack = GetSerializedDzPacket();
auto pack_size = sizeof(ServerDzCreateSerialized_Struct) + dyn_pack.Length();
auto pack_size = sizeof(ServerDzCreate_Struct) + sv.size();
auto pack = std::make_unique<ServerPacket>(ServerOP_DzCreated, static_cast<uint32_t>(pack_size));
auto buf = reinterpret_cast<ServerDzCreateSerialized_Struct*>(pack->pBuffer);
buf->origin_zone_id = origin_zone_id;
buf->origin_instance_id = origin_instance_id;
buf->cereal_size = static_cast<uint32_t>(dyn_pack.Length());
memcpy(buf->cereal_data, dyn_pack.Data(), dyn_pack.Length());
auto buf = reinterpret_cast<ServerDzCreate_Struct*>(pack->pBuffer);
buf->origin_zone_id = zone_id;
buf->origin_instance_id = instance_id;
buf->dz_id = GetID();
buf->cereal_size = static_cast<uint32_t>(sv.size());
memcpy(buf->cereal_data, sv.data(), sv.size());
return pack;
}
void DynamicZoneBase::LoadSerializedDzPacket(char* cereal_data, uint32_t cereal_size)
std::ostringstream DynamicZoneBase::GetSerialized()
{
LogDynamicZonesDetail("Deserializing server dz size [{}]", cereal_size);
EQ::Util::MemoryStreamReader ss(cereal_data, cereal_size);
std::ostringstream ss;
cereal::BinaryOutputArchive archive(ss);
archive(*this);
return ss;
}
void DynamicZoneBase::Unserialize(std::span<char> buf)
{
EQ::Util::MemoryStreamReader ss(buf.data(), buf.size());
cereal::BinaryInputArchive archive(ss);
archive(*this);
}
@@ -647,3 +699,180 @@ void DynamicZoneBase::LoadTemplate(const DynamicZoneTemplatesRepository::Dynamic
m_zonein.z = dz_template.zone_in_z;
m_zonein.heading = dz_template.zone_in_h;
}
std::vector<uint32_t> DynamicZoneBase::GetMemberIds()
{
std::vector<uint32_t> ids;
ids.reserve(m_members.size());
for (const auto& member : m_members)
{
ids.push_back(member.id);
}
return ids;
}
bool DynamicZoneBase::HasLockout(const std::string& event)
{
return std::ranges::any_of(m_lockouts, [&](const auto& l) { return l.IsEvent(event); });
}
bool DynamicZoneBase::HasReplayLockout()
{
return HasLockout(DzLockout::ReplayTimer);
}
void DynamicZoneBase::AddLockout(const std::string& event, uint32_t seconds)
{
auto lockout = DzLockout::Create(m_name, event, seconds, m_uuid);
AddLockout(lockout);
}
void DynamicZoneBase::AddLockout(const DzLockout& lockout, bool members_only)
{
if (!members_only)
{
DynamicZoneLockoutsRepository::InsertLockouts(GetDatabase(), GetID(), { lockout });
}
CharacterExpeditionLockoutsRepository::InsertLockout(GetDatabase(), GetMemberIds(), lockout);
HandleLockoutUpdate(lockout, false, members_only);
SendServerPacket(CreateLockoutPacket(lockout, false, members_only).get());
}
void DynamicZoneBase::AddLockoutDuration(const std::string& event, int seconds, bool members_only)
{
auto lockout = DzLockout::Create(m_name, event, std::max(0, seconds), m_uuid);
// lockout has unsigned duration, pass original seconds to support reducing existing timers
int secs = static_cast<int>(seconds * RuleR(Expedition, LockoutDurationMultiplier));
CharacterExpeditionLockoutsRepository::AddLockoutDuration(GetDatabase(), GetMemberIds(), lockout, secs);
HandleLockoutDuration(lockout, seconds, members_only, true);
SendServerPacket(CreateLockoutDurationPacket(lockout, seconds, members_only).get());
}
void DynamicZoneBase::UpdateLockoutDuration(const std::string& event, uint32_t seconds, bool members_only)
{
// some live expeditions update existing lockout timers during progression
auto it = std::ranges::find_if(m_lockouts, [&](const auto& l) { return l.IsEvent(event); });
if (it != m_lockouts.end())
{
seconds = static_cast<uint32_t>(seconds * RuleR(Expedition, LockoutDurationMultiplier));
DzLockout lockout(m_uuid, m_name, event, it->GetStartTime() + seconds, seconds);
AddLockout(lockout, members_only);
}
}
void DynamicZoneBase::RemoveLockout(const std::string& event)
{
DynamicZoneLockoutsRepository::DeleteWhere(GetDatabase(), fmt::format(
"dynamic_zone_id = {} AND event_name = '{}'", GetID(), Strings::Escape(event)));
CharacterExpeditionLockoutsRepository::DeleteWhere(GetDatabase(), fmt::format(
"character_id IN ({}) AND expedition_name = '{}' AND event_name = '{}'",
fmt::join(GetMemberIds(), ","), Strings::Escape(m_name), Strings::Escape(event)));
DzLockout lockout{m_uuid, m_name, event, 0, 0};
HandleLockoutUpdate(lockout, true, false);
SendServerPacket(CreateLockoutPacket(lockout, true).get());
}
void DynamicZoneBase::HandleLockoutUpdate(const DzLockout& lockout, bool remove, bool members_only)
{
if (!members_only)
{
std::erase_if(m_lockouts, [&](const auto& l) { return l.IsEvent(lockout.Event()); });
if (!remove)
{
m_lockouts.push_back(lockout);
}
}
}
void DynamicZoneBase::HandleLockoutDuration(const DzLockout& lockout, int seconds, bool members_only, bool insert_db)
{
if (!members_only)
{
auto it = std::ranges::find_if(m_lockouts, [&](const auto& l) { return l.IsEvent(lockout.Event()); });
if (it != m_lockouts.end())
{
it->AddLockoutTime(seconds);
}
else
{
it = m_lockouts.insert(m_lockouts.end(), lockout);
}
if (insert_db)
{
DynamicZoneLockoutsRepository::InsertLockouts(GetDatabase(), GetID(), { *it });
}
}
}
std::unique_ptr<ServerPacket> DynamicZoneBase::CreateLockoutPacket(const DzLockout& lockout, bool remove, bool members_only) const
{
uint32_t pack_size = sizeof(ServerDzLockout_Struct);
auto pack = std::make_unique<ServerPacket>(ServerOP_DzLockout, pack_size);
auto buf = reinterpret_cast<ServerDzLockout_Struct*>(pack->pBuffer);
buf->dz_id = GetID();
buf->expire_time = lockout.GetExpireTime();
buf->duration = lockout.GetDuration();
buf->sender_zone_id = GetCurrentZoneID();
buf->sender_instance_id = GetCurrentInstanceID();
buf->remove = remove;
buf->members_only = members_only;
strn0cpy(buf->event_name, lockout.Event().c_str(), sizeof(buf->event_name));
return pack;
}
std::unique_ptr<ServerPacket> DynamicZoneBase::CreateLockoutDurationPacket(const DzLockout& lockout, int seconds, bool members_only) const
{
uint32_t pack_size = sizeof(ServerDzLockout_Struct);
auto pack = std::make_unique<ServerPacket>(ServerOP_DzLockoutDuration, pack_size);
auto buf = reinterpret_cast<ServerDzLockout_Struct*>(pack->pBuffer);
buf->dz_id = GetID();
buf->expire_time = lockout.GetExpireTime();
buf->duration = lockout.GetDuration();
buf->sender_zone_id = GetCurrentZoneID();
buf->sender_instance_id = GetCurrentInstanceID();
buf->members_only = members_only;
buf->seconds = seconds;
strn0cpy(buf->event_name, lockout.Event().c_str(), sizeof(buf->event_name));
return pack;
}
void DynamicZoneBase::SyncCharacterLockouts(uint32_t char_id, std::vector<DzLockout>& lockouts)
{
// adds missing event lockouts to client for this expedition and updates
// client timers that are both shorter and from another expedition
bool modified = false;
for (const auto& lockout : m_lockouts)
{
if (lockout.IsReplay() || lockout.IsExpired() || lockout.UUID() != m_uuid)
{
continue;
}
auto it = std::find_if(lockouts.begin(), lockouts.end(), [&](const DzLockout& l) { return l.IsSame(lockout); });
if (it == lockouts.end())
{
modified = true;
lockouts.push_back(lockout); // insert missing
}
else if (it->GetSecondsRemaining() < lockout.GetSecondsRemaining() && it->UUID() != m_uuid)
{
// only update lockout timer not uuid so loot event apis still work
modified = true;
it->SetDuration(lockout.GetDuration());
it->SetExpireTime(lockout.GetExpireTime());
}
}
if (modified)
{
CharacterExpeditionLockoutsRepository::InsertLockouts(GetDatabase(), char_id, lockouts);
}
}
+68 -14
View File
@@ -1,8 +1,8 @@
#ifndef COMMON_DYNAMIC_ZONE_BASE_H
#define COMMON_DYNAMIC_ZONE_BASE_H
#include "dynamic_zone_lockout.h"
#include "eq_constants.h"
#include "net/packet.h"
#include "repositories/dynamic_zones_repository.h"
#include "repositories/dynamic_zone_members_repository.h"
#include "repositories/dynamic_zone_templates_repository.h"
@@ -10,12 +10,40 @@
#include <chrono>
#include <cstdint>
#include <memory>
#include <span>
#include <string>
#include <vector>
class Database;
class ServerPacket;
// message string 8312 added in September 08 2020 Test patch (used by both dz and shared tasks)
inline constexpr char DzNotAllAdded[] = "Not all players in your {0} were added to the {1}. The {1} can take a maximum of {2} players, and your {0} has {3}.";
enum class DzLockMsg : uint8_t
{
None = 0, Close, Begin
};
enum class DynamicZoneType
{
None = 0,
Expedition,
Tutorial,
Task,
Mission, // Shared Task
Quest
};
enum class DynamicZoneMemberStatus
{
Unknown = 0,
Online,
Offline,
InDynamicZone,
LinkDead
};
struct DynamicZoneMember
{
uint32_t id = 0;
@@ -93,6 +121,7 @@ public:
const std::string& GetName() const { return m_name; }
const std::string& GetUUID() const { return m_uuid; }
const DynamicZoneMember& GetLeader() const { return m_leader; }
const std::vector<DzLockout>& GetLockouts() const { return m_lockouts; }
const std::vector<DynamicZoneMember>& GetMembers() const { return m_members; }
const DynamicZoneLocation& GetCompassLocation() const { return m_compass; }
const DynamicZoneLocation& GetSafeReturnLocation() const { return m_safereturn; }
@@ -104,31 +133,34 @@ public:
uint32_t GetDatabaseMemberCount();
DynamicZoneMember GetMemberData(uint32_t character_id);
DynamicZoneMember GetMemberData(const std::string& character_name);
EQ::Net::DynamicPacket GetSerializedDzPacket();
std::vector<uint32_t> GetMemberIds();
std::ostringstream GetSerialized();
bool HasDatabaseMember(uint32_t character_id);
bool HasMember(uint32_t character_id);
bool HasMember(const std::string& character_name);
bool HasMember(uint32_t character_id) const;
bool HasMember(const std::string& character_name) const;
bool HasMembers() const { return !m_members.empty(); }
bool HasZoneInLocation() const { return m_has_zonein; }
bool IsExpedition() const { return m_type == DynamicZoneType::Expedition; }
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); }
bool IsLocked() const { return m_is_locked; }
bool IsValid() const { return m_instance_id != 0; }
bool IsSameDz(uint32_t zone_id, uint32_t instance_id) const { return zone_id == m_zone_id && instance_id == m_instance_id; }
void LoadSerializedDzPacket(char* cereal_data, uint32_t cereal_size);
void LoadTemplate(const DynamicZoneTemplatesRepository::DynamicZoneTemplates& dz_template);
void RemoveAllMembers();
bool RemoveMember(uint32_t character_id);
bool RemoveMember(const std::string& character_name);
bool RemoveMember(const DynamicZoneMember& remove_member);
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 SetDuration(uint32_t seconds) { m_duration = std::chrono::seconds(seconds); }
void SetLeader(const DynamicZoneMember& leader, bool update_db = false);
void SetLocked(bool lock, bool update_db = false, DzLockMsg lock_msg = DzLockMsg::None, uint32_t color = Chat::Yellow);
void SetMaxPlayers(uint32_t max_players) { m_max_players = max_players; }
void SetMemberStatus(uint32_t character_id, DynamicZoneMemberStatus status);
void SetMinPlayers(uint32_t min_players) { m_min_players = min_players; }
void SetName(const std::string& name) { m_name = name; }
void SetReplayOnJoin(bool enabled, bool update_db = false);
void SetSafeReturn(const DynamicZoneLocation& location, bool update_db = false);
void SetSafeReturn(uint32_t zone_id, float x, float y, float z, float heading, bool update_db = false);
void SetSwitchID(int dz_switch_id, bool update_db = false);
@@ -136,34 +168,48 @@ public:
void SetUUID(std::string uuid) { m_uuid = std::move(uuid); }
void SetZoneInLocation(const DynamicZoneLocation& location, bool update_db = false);
void SetZoneInLocation(float x, float y, float z, float heading, bool update_db = false);
bool SwapMember(const DynamicZoneMember& add_member, const std::string& remove_char_name);
bool SwapMember(const DynamicZoneMember& add_member, const std::string& remove_name);
void AddLockout(const std::string& event, uint32_t seconds);
void AddLockoutDuration(const std::string& event, int seconds, bool members_only = true);
bool HasLockout(const std::string& event);
bool HasReplayLockout();
void RemoveLockout(const std::string& event);
void SyncCharacterLockouts(uint32_t char_id, std::vector<DzLockout>& lockouts);
void UpdateLockoutDuration(const std::string& event, uint32_t seconds, bool members_only = true);
protected:
virtual uint16_t GetCurrentInstanceID() { return 0; }
virtual uint16_t GetCurrentZoneID() { return 0; }
virtual uint16_t GetCurrentInstanceID() const { return 0; }
virtual uint16_t GetCurrentZoneID() const { return 0; }
virtual Database& GetDatabase() = 0;
virtual void HandleLockoutDuration(const DzLockout& lockout, int seconds, bool members_only, bool insert_db);
virtual void HandleLockoutUpdate(const DzLockout& lockout, bool remove, bool members_only);
virtual void ProcessCompassChange(const DynamicZoneLocation& location) { m_compass = location; }
virtual void ProcessMemberAddRemove(const DynamicZoneMember& member, bool removed);
virtual bool ProcessMemberStatusChange(uint32_t member_id, DynamicZoneMemberStatus status);
virtual void ProcessRemoveAllMembers(bool silent = false) { m_members.clear(); }
virtual bool ProcessMemberStatusChange(uint32_t character_id, DynamicZoneMemberStatus status);
virtual void ProcessRemoveAllMembers() { m_members.clear(); }
virtual void ProcessSetSwitchID(int dz_switch_id) { m_dz_switch_id = dz_switch_id; }
virtual bool SendServerPacket(ServerPacket* packet) = 0;
void AddLockout(const DzLockout& lockout, bool members_only = false);
void AddInternalMember(const DynamicZoneMember& member);
uint32_t Create();
uint32_t CreateInstance();
void LoadRepositoryResult(DynamicZonesRepository::DynamicZoneInstance&& dz_entry);
void RemoveInternalMember(uint32_t character_id);
void SaveMembers(const std::vector<DynamicZoneMember>& members);
uint32_t SaveToDatabase();
bool SetInternalMemberStatus(uint32_t character_id, DynamicZoneMemberStatus status);
std::unique_ptr<ServerPacket> CreateServerDzCreatePacket(uint16_t origin_zone_id, uint16_t origin_instance_id);
std::unique_ptr<ServerPacket> CreateServerPacket(uint16_t zone_id, uint16_t instance_id);
std::unique_ptr<ServerPacket> CreateServerDzLocationPacket(uint16_t server_opcode, const DynamicZoneLocation& location);
std::unique_ptr<ServerPacket> CreateServerDzSwitchIDPacket();
std::unique_ptr<ServerPacket> CreateServerMemberAddRemovePacket(const DynamicZoneMember& member, bool removed);
std::unique_ptr<ServerPacket> CreateServerMemberStatusPacket(uint32_t character_id, DynamicZoneMemberStatus status);
std::unique_ptr<ServerPacket> CreateServerMemberSwapPacket(const DynamicZoneMember& remove_member, const DynamicZoneMember& add_member);
std::unique_ptr<ServerPacket> CreateServerRemoveAllMembersPacket();
std::unique_ptr<ServerPacket> CreateLockoutPacket(const DzLockout& lockout, bool remove, bool members_only = false) const;
std::unique_ptr<ServerPacket> CreateLockoutDurationPacket(const DzLockout& lockout, int seconds, bool members_only = false) const;
uint32_t m_id = 0;
uint32_t m_zone_id = 0;
@@ -175,6 +221,8 @@ protected:
bool m_never_expires = false;
bool m_has_zonein = false;
bool m_has_member_statuses = false;
bool m_is_locked = false;
bool m_add_replay = true;
std::string m_name;
std::string m_uuid;
DynamicZoneMember m_leader;
@@ -182,12 +230,15 @@ protected:
DynamicZoneLocation m_compass;
DynamicZoneLocation m_safereturn;
DynamicZoneLocation m_zonein;
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_expire_time;
std::vector<DynamicZoneMember> m_members;
std::vector<DzLockout> m_lockouts;
public:
void Unserialize(std::span<char> buf);
template<class Archive>
void serialize(Archive& archive)
{
@@ -202,6 +253,8 @@ public:
m_never_expires,
m_has_zonein,
m_has_member_statuses,
m_is_locked,
m_add_replay,
m_name,
m_uuid,
m_leader,
@@ -212,7 +265,8 @@ public:
m_duration,
m_start_time,
m_expire_time,
m_members
m_members,
m_lockouts
);
}
};
+92
View File
@@ -0,0 +1,92 @@
#include "dynamic_zone_lockout.h"
#include "strings.h"
#include "rulesys.h"
#include "util/uuid.h"
#include <fmt/format.h>
#include <cereal/types/chrono.hpp>
DzLockout::DzLockout(std::string uuid, std::string expedition, std::string event, uint64_t expire_time, uint32_t duration)
: m_uuid(std::move(uuid))
, m_name(std::move(expedition))
, m_event(std::move(event))
, m_expire_time(std::chrono::system_clock::from_time_t(expire_time))
, m_duration(duration)
{
m_is_replay = m_event == ReplayTimer;
}
DzLockout::DzLockout(std::string_view name, BaseDynamicZoneLockoutsRepository::DynamicZoneLockouts&& lockout)
: m_uuid(std::move(lockout.from_expedition_uuid))
, m_name(name)
, m_event(std::move(lockout.event_name))
, m_expire_time(std::chrono::system_clock::from_time_t(lockout.expire_time))
, m_duration(lockout.duration)
{
m_is_replay = m_event == ReplayTimer;
}
DzLockout DzLockout::Create(const std::string& expedition, const std::string& event, uint32_t seconds, std::string uuid)
{
seconds = static_cast<uint32_t>(seconds * RuleR(Expedition, LockoutDurationMultiplier));
if (uuid.empty())
{
uuid = EQ::Util::UUID::Generate().ToString();
}
DzLockout lockout{uuid, expedition, event, 0, seconds};
lockout.Reset(); // sets expire time
return lockout;
}
uint32_t DzLockout::GetSecondsRemaining() const
{
auto now = std::chrono::system_clock::now();
if (m_expire_time > now)
{
auto remaining = m_expire_time - now;
return static_cast<uint32_t>(std::chrono::duration_cast<std::chrono::seconds>(remaining).count());
}
return 0;
}
DzLockout::TimeStrings DzLockout::GetTimeRemainingStrs() const
{
auto seconds = GetSecondsRemaining();
return DzLockout::TimeStrings{
fmt::format_int(seconds / 86400).str(), // days
fmt::format_int(seconds / 3600 % 24).str(), // hours
fmt::format_int(seconds / 60 % 60).str(), // minutes
fmt::format_int(seconds % 60).str() // seconds
};
}
bool DzLockout::IsSame(const DzLockout& other) const
{
return other.IsSame(m_name, m_event);
}
bool DzLockout::IsSame(const std::string& expedition, const std::string& event) const
{
return m_name == expedition && m_event == event;
}
void DzLockout::AddLockoutTime(int seconds)
{
seconds = static_cast<int>(seconds * RuleR(Expedition, LockoutDurationMultiplier));
auto new_duration = std::max(0, static_cast<int>(m_duration.count()) + seconds);
auto start_time = m_expire_time - m_duration;
m_duration = std::chrono::seconds(new_duration);
m_expire_time = start_time + m_duration;
}
template <typename T>
void DzLockout::serialize(T& archive)
{
archive(m_is_replay, m_uuid, m_name, m_event, m_duration, m_expire_time);
}
template void DzLockout::serialize(cereal::BinaryOutputArchive&);
template void DzLockout::serialize(cereal::BinaryInputArchive&);
+56
View File
@@ -0,0 +1,56 @@
#pragma once
#include <chrono>
#include <string>
#include "repositories/base/base_dynamic_zone_lockouts_repository.h"
class DzLockout
{
public:
DzLockout() = default;
DzLockout(std::string uuid, std::string expedition, std::string event, uint64_t expire_time, uint32_t duration);
DzLockout(std::string_view name, BaseDynamicZoneLockoutsRepository::DynamicZoneLockouts&& lockout);
static constexpr char ReplayTimer[] = "Replay Timer";
static DzLockout Create(const std::string& expedition, const std::string& event, uint32_t seconds, std::string uuid = {});
struct TimeStrings
{
std::string days;
std::string hours;
std::string mins;
std::string secs;
};
void AddLockoutTime(int seconds);
uint32_t GetDuration() const { return static_cast<uint32_t>(m_duration.count()); }
uint64_t GetExpireTime() const { return std::chrono::system_clock::to_time_t(m_expire_time); }
uint64_t GetStartTime() const { return std::chrono::system_clock::to_time_t(m_expire_time - m_duration); }
uint32_t GetSecondsRemaining() const;
TimeStrings GetTimeRemainingStrs() const;
const std::string& DzName() const { return m_name; }
const std::string& Event() const { return m_event; }
const std::string& UUID() const { return m_uuid; }
bool IsEvent(std::string_view event) const { return m_event == event; }
bool IsExpired() const { return GetSecondsRemaining() == 0; }
bool IsReplay() const { return m_is_replay; }
bool IsSame(const DzLockout& other) const;
bool IsSame(const std::string& expedition, const std::string& event) const;
bool IsUUID(const std::string& uuid) const { return uuid == m_uuid; }
void Reset() { m_expire_time = std::chrono::system_clock::now() + m_duration; }
void SetDuration(uint32_t seconds) { m_duration = std::chrono::seconds(seconds); }
void SetExpireTime(uint64_t expire_time) { m_expire_time = std::chrono::system_clock::from_time_t(expire_time); }
void SetUUID(const std::string& uuid) { m_uuid = uuid; }
template <typename T>
void serialize(T& archive);
private:
bool m_is_replay = false;
std::string m_uuid; // dz received in
std::string m_name;
std::string m_event;
std::chrono::seconds m_duration = {};
std::chrono::time_point<std::chrono::system_clock> m_expire_time;
};
-19
View File
@@ -974,25 +974,6 @@ namespace ZoneBlockedSpellTypes {
const uint8 Region = 2;
};
enum class DynamicZoneType
{
None = 0,
Expedition,
Tutorial,
Task,
Mission, // Shared Task
Quest
};
enum class DynamicZoneMemberStatus : uint8_t
{
Unknown = 0,
Online,
Offline,
InDynamicZone,
LinkDead
};
enum StartZoneIndex {
Odus = 0,
Qeynos,
-101
View File
@@ -1,101 +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
*
*/
#include "expedition_lockout_timer.h"
#include "../common/strings.h"
#include "../common/rulesys.h"
#include "../common/util/uuid.h"
#include <fmt/format.h>
const char* const DZ_REPLAY_TIMER_NAME = "Replay Timer"; // see December 14, 2016 patch notes
ExpeditionLockoutTimer::ExpeditionLockoutTimer(
std::string expedition_uuid, std::string expedition_name,
std::string event_name, uint64_t expire_time, uint32_t duration
) :
m_expedition_uuid{std::move(expedition_uuid)},
m_expedition_name{std::move(expedition_name)},
m_event_name{std::move(event_name)},
m_expire_time(std::chrono::system_clock::from_time_t(expire_time)),
m_duration(duration)
{
if (m_event_name == DZ_REPLAY_TIMER_NAME)
{
m_is_replay_timer = true;
}
}
ExpeditionLockoutTimer ExpeditionLockoutTimer::CreateLockout(
const std::string& expedition_name, const std::string& event_name, uint32_t seconds, std::string uuid)
{
seconds = static_cast<uint32_t>(seconds * RuleR(Expedition, LockoutDurationMultiplier));
if (uuid.empty())
{
uuid = EQ::Util::UUID::Generate().ToString();
}
ExpeditionLockoutTimer lockout{uuid, expedition_name, event_name, 0, seconds};
lockout.Reset(); // sets expire time
return lockout;
}
uint32_t ExpeditionLockoutTimer::GetSecondsRemaining() const
{
auto now = std::chrono::system_clock::now();
if (m_expire_time > now)
{
auto remaining = m_expire_time - now;
return static_cast<uint32_t>(std::chrono::duration_cast<std::chrono::seconds>(remaining).count());
}
return 0;
}
ExpeditionLockoutTimer::DaysHoursMinutes ExpeditionLockoutTimer::GetDaysHoursMinutesRemaining() const
{
auto seconds = GetSecondsRemaining();
return ExpeditionLockoutTimer::DaysHoursMinutes{
fmt::format_int(seconds / 86400).str(), // days
fmt::format_int((seconds / 3600) % 24).str(), // hours
fmt::format_int((seconds / 60) % 60).str() // minutes
};
}
bool ExpeditionLockoutTimer::IsSameLockout(const ExpeditionLockoutTimer& compare_lockout) const
{
return compare_lockout.IsSameLockout(GetExpeditionName(), GetEventName());
}
bool ExpeditionLockoutTimer::IsSameLockout(
const std::string& expedition_name, const std::string& event_name) const
{
return GetExpeditionName() == expedition_name && GetEventName() == event_name;
}
void ExpeditionLockoutTimer::AddLockoutTime(int seconds)
{
seconds = static_cast<uint32_t>(seconds * RuleR(Expedition, LockoutDurationMultiplier));
auto new_duration = std::max(0, static_cast<int>(m_duration.count()) + seconds);
auto start_time = m_expire_time - m_duration;
m_duration = std::chrono::seconds(new_duration);
m_expire_time = start_time + m_duration;
}
-76
View File
@@ -1,76 +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 EXPEDITION_LOCKOUT_TIMER_H
#define EXPEDITION_LOCKOUT_TIMER_H
#include <chrono>
#include <string>
extern const char* const DZ_REPLAY_TIMER_NAME;
class ExpeditionLockoutTimer
{
public:
ExpeditionLockoutTimer() = default;
ExpeditionLockoutTimer(
std::string expedition_uuid, std::string expedition_name,
std::string event_name, uint64_t expire_time, uint32_t duration);
static ExpeditionLockoutTimer CreateLockout(
const std::string& expedition_name, const std::string& event_name,
uint32_t seconds, std::string uuid = {});
struct DaysHoursMinutes
{
std::string days;
std::string hours;
std::string mins;
};
void AddLockoutTime(int seconds);
uint32_t GetDuration() const { return static_cast<uint32_t>(m_duration.count()); }
uint64_t GetExpireTime() const { return std::chrono::system_clock::to_time_t(m_expire_time); }
uint64_t GetStartTime() const { return std::chrono::system_clock::to_time_t(m_expire_time - m_duration); }
uint32_t GetSecondsRemaining() const;
DaysHoursMinutes GetDaysHoursMinutesRemaining() const;
const std::string& GetExpeditionName() const { return m_expedition_name; }
const std::string& GetExpeditionUUID() const { return m_expedition_uuid; }
const std::string& GetEventName() const { return m_event_name; }
bool IsExpired() const { return GetSecondsRemaining() == 0; }
bool IsFromExpedition(const std::string& uuid) const { return uuid == m_expedition_uuid; }
bool IsReplayTimer() const { return m_is_replay_timer; }
bool IsSameLockout(const ExpeditionLockoutTimer& compare_lockout) const;
bool IsSameLockout(const std::string& expedition_name, const std::string& event_name) const;
void Reset() { m_expire_time = std::chrono::system_clock::now() + m_duration; }
void SetDuration(uint32_t seconds) { m_duration = std::chrono::seconds(seconds); }
void SetExpireTime(uint64_t expire_time) { m_expire_time = std::chrono::system_clock::from_time_t(expire_time); }
void SetUUID(const std::string& uuid) { m_expedition_uuid = uuid; }
private:
bool m_is_replay_timer = false;
std::string m_expedition_uuid; // expedition received in
std::string m_expedition_name;
std::string m_event_name;
std::chrono::seconds m_duration;
std::chrono::time_point<std::chrono::system_clock> m_expire_time;
};
#endif
@@ -9,18 +9,18 @@
* @docs https://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_EXPEDITION_LOCKOUTS_REPOSITORY_H
#define EQEMU_BASE_EXPEDITION_LOCKOUTS_REPOSITORY_H
#ifndef EQEMU_BASE_DYNAMIC_ZONE_LOCKOUTS_REPOSITORY_H
#define EQEMU_BASE_DYNAMIC_ZONE_LOCKOUTS_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
class BaseExpeditionLockoutsRepository {
class BaseDynamicZoneLockoutsRepository {
public:
struct ExpeditionLockouts {
struct DynamicZoneLockouts {
uint32_t id;
uint32_t expedition_id;
uint32_t dynamic_zone_id;
std::string event_name;
time_t expire_time;
uint32_t duration;
@@ -36,7 +36,7 @@ public:
{
return {
"id",
"expedition_id",
"dynamic_zone_id",
"event_name",
"expire_time",
"duration",
@@ -48,7 +48,7 @@ public:
{
return {
"id",
"expedition_id",
"dynamic_zone_id",
"event_name",
"UNIX_TIMESTAMP(expire_time)",
"duration",
@@ -68,7 +68,7 @@ public:
static std::string TableName()
{
return std::string("expedition_lockouts");
return std::string("dynamic_zone_lockouts");
}
static std::string BaseSelect()
@@ -89,12 +89,12 @@ public:
);
}
static ExpeditionLockouts NewEntity()
static DynamicZoneLockouts NewEntity()
{
ExpeditionLockouts e{};
DynamicZoneLockouts e{};
e.id = 0;
e.expedition_id = 0;
e.dynamic_zone_id = 0;
e.event_name = "";
e.expire_time = std::time(nullptr);
e.duration = 0;
@@ -103,23 +103,23 @@ public:
return e;
}
static ExpeditionLockouts GetExpeditionLockouts(
const std::vector<ExpeditionLockouts> &expedition_lockoutss,
int expedition_lockouts_id
static DynamicZoneLockouts GetDynamicZoneLockouts(
const std::vector<DynamicZoneLockouts> &dynamic_zone_lockoutss,
int dynamic_zone_lockouts_id
)
{
for (auto &expedition_lockouts : expedition_lockoutss) {
if (expedition_lockouts.id == expedition_lockouts_id) {
return expedition_lockouts;
for (auto &dynamic_zone_lockouts : dynamic_zone_lockoutss) {
if (dynamic_zone_lockouts.id == dynamic_zone_lockouts_id) {
return dynamic_zone_lockouts;
}
}
return NewEntity();
}
static ExpeditionLockouts FindOne(
static DynamicZoneLockouts FindOne(
Database& db,
int expedition_lockouts_id
int dynamic_zone_lockouts_id
)
{
auto results = db.QueryDatabase(
@@ -127,16 +127,16 @@ public:
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
expedition_lockouts_id
dynamic_zone_lockouts_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
ExpeditionLockouts e{};
DynamicZoneLockouts e{};
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.expedition_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.dynamic_zone_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.event_name = row[2] ? row[2] : "";
e.expire_time = strtoll(row[3] ? row[3] : "-1", nullptr, 10);
e.duration = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
@@ -150,7 +150,7 @@ public:
static int DeleteOne(
Database& db,
int expedition_lockouts_id
int dynamic_zone_lockouts_id
)
{
auto results = db.QueryDatabase(
@@ -158,7 +158,7 @@ public:
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
expedition_lockouts_id
dynamic_zone_lockouts_id
)
);
@@ -167,14 +167,14 @@ public:
static int UpdateOne(
Database& db,
const ExpeditionLockouts &e
const DynamicZoneLockouts &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[1] + " = " + std::to_string(e.expedition_id));
v.push_back(columns[1] + " = " + std::to_string(e.dynamic_zone_id));
v.push_back(columns[2] + " = '" + Strings::Escape(e.event_name) + "'");
v.push_back(columns[3] + " = FROM_UNIXTIME(" + (e.expire_time > 0 ? std::to_string(e.expire_time) : "null") + ")");
v.push_back(columns[4] + " = " + std::to_string(e.duration));
@@ -193,15 +193,15 @@ public:
return (results.Success() ? results.RowsAffected() : 0);
}
static ExpeditionLockouts InsertOne(
static DynamicZoneLockouts InsertOne(
Database& db,
ExpeditionLockouts e
DynamicZoneLockouts e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.expedition_id));
v.push_back(std::to_string(e.dynamic_zone_id));
v.push_back("'" + Strings::Escape(e.event_name) + "'");
v.push_back("FROM_UNIXTIME(" + (e.expire_time > 0 ? std::to_string(e.expire_time) : "null") + ")");
v.push_back(std::to_string(e.duration));
@@ -227,7 +227,7 @@ public:
static int InsertMany(
Database& db,
const std::vector<ExpeditionLockouts> &entries
const std::vector<DynamicZoneLockouts> &entries
)
{
std::vector<std::string> insert_chunks;
@@ -236,7 +236,7 @@ public:
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.expedition_id));
v.push_back(std::to_string(e.dynamic_zone_id));
v.push_back("'" + Strings::Escape(e.event_name) + "'");
v.push_back("FROM_UNIXTIME(" + (e.expire_time > 0 ? std::to_string(e.expire_time) : "null") + ")");
v.push_back(std::to_string(e.duration));
@@ -258,9 +258,9 @@ public:
return (results.Success() ? results.RowsAffected() : 0);
}
static std::vector<ExpeditionLockouts> All(Database& db)
static std::vector<DynamicZoneLockouts> All(Database& db)
{
std::vector<ExpeditionLockouts> all_entries;
std::vector<DynamicZoneLockouts> all_entries;
auto results = db.QueryDatabase(
fmt::format(
@@ -272,10 +272,10 @@ public:
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
ExpeditionLockouts e{};
DynamicZoneLockouts e{};
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.expedition_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.dynamic_zone_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.event_name = row[2] ? row[2] : "";
e.expire_time = strtoll(row[3] ? row[3] : "-1", nullptr, 10);
e.duration = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
@@ -287,9 +287,9 @@ public:
return all_entries;
}
static std::vector<ExpeditionLockouts> GetWhere(Database& db, const std::string &where_filter)
static std::vector<DynamicZoneLockouts> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<ExpeditionLockouts> all_entries;
std::vector<DynamicZoneLockouts> all_entries;
auto results = db.QueryDatabase(
fmt::format(
@@ -302,10 +302,10 @@ public:
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
ExpeditionLockouts e{};
DynamicZoneLockouts e{};
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.expedition_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.dynamic_zone_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.event_name = row[2] ? row[2] : "";
e.expire_time = strtoll(row[3] ? row[3] : "-1", nullptr, 10);
e.duration = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
@@ -379,13 +379,13 @@ public:
static int ReplaceOne(
Database& db,
const ExpeditionLockouts &e
const DynamicZoneLockouts &e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.expedition_id));
v.push_back(std::to_string(e.dynamic_zone_id));
v.push_back("'" + Strings::Escape(e.event_name) + "'");
v.push_back("FROM_UNIXTIME(" + (e.expire_time > 0 ? std::to_string(e.expire_time) : "null") + ")");
v.push_back(std::to_string(e.duration));
@@ -404,7 +404,7 @@ public:
static int ReplaceMany(
Database& db,
const std::vector<ExpeditionLockouts> &entries
const std::vector<DynamicZoneLockouts> &entries
)
{
std::vector<std::string> insert_chunks;
@@ -413,7 +413,7 @@ public:
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.expedition_id));
v.push_back(std::to_string(e.dynamic_zone_id));
v.push_back("'" + Strings::Escape(e.event_name) + "'");
v.push_back("FROM_UNIXTIME(" + (e.expire_time > 0 ? std::to_string(e.expire_time) : "null") + ")");
v.push_back(std::to_string(e.duration));
@@ -436,4 +436,4 @@ public:
}
};
#endif //EQEMU_BASE_EXPEDITION_LOCKOUTS_REPOSITORY_H
#endif //EQEMU_BASE_DYNAMIC_ZONE_LOCKOUTS_REPOSITORY_H
@@ -42,6 +42,8 @@ public:
float zone_in_z;
float zone_in_heading;
uint8_t has_zone_in;
int8_t is_locked;
int8_t add_replay;
};
static std::string PrimaryKey()
@@ -75,6 +77,8 @@ public:
"zone_in_z",
"zone_in_heading",
"has_zone_in",
"is_locked",
"add_replay",
};
}
@@ -104,6 +108,8 @@ public:
"zone_in_z",
"zone_in_heading",
"has_zone_in",
"is_locked",
"add_replay",
};
}
@@ -167,6 +173,8 @@ public:
e.zone_in_z = 0;
e.zone_in_heading = 0;
e.has_zone_in = 0;
e.is_locked = 0;
e.add_replay = 1;
return e;
}
@@ -226,6 +234,8 @@ public:
e.zone_in_z = row[20] ? strtof(row[20], nullptr) : 0;
e.zone_in_heading = row[21] ? strtof(row[21], nullptr) : 0;
e.has_zone_in = row[22] ? static_cast<uint8_t>(strtoul(row[22], nullptr, 10)) : 0;
e.is_locked = row[23] ? static_cast<int8_t>(atoi(row[23])) : 0;
e.add_replay = row[24] ? static_cast<int8_t>(atoi(row[24])) : 1;
return e;
}
@@ -281,6 +291,8 @@ public:
v.push_back(columns[20] + " = " + std::to_string(e.zone_in_z));
v.push_back(columns[21] + " = " + std::to_string(e.zone_in_heading));
v.push_back(columns[22] + " = " + std::to_string(e.has_zone_in));
v.push_back(columns[23] + " = " + std::to_string(e.is_locked));
v.push_back(columns[24] + " = " + std::to_string(e.add_replay));
auto results = db.QueryDatabase(
fmt::format(
@@ -325,6 +337,8 @@ public:
v.push_back(std::to_string(e.zone_in_z));
v.push_back(std::to_string(e.zone_in_heading));
v.push_back(std::to_string(e.has_zone_in));
v.push_back(std::to_string(e.is_locked));
v.push_back(std::to_string(e.add_replay));
auto results = db.QueryDatabase(
fmt::format(
@@ -377,6 +391,8 @@ public:
v.push_back(std::to_string(e.zone_in_z));
v.push_back(std::to_string(e.zone_in_heading));
v.push_back(std::to_string(e.has_zone_in));
v.push_back(std::to_string(e.is_locked));
v.push_back(std::to_string(e.add_replay));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -433,6 +449,8 @@ public:
e.zone_in_z = row[20] ? strtof(row[20], nullptr) : 0;
e.zone_in_heading = row[21] ? strtof(row[21], nullptr) : 0;
e.has_zone_in = row[22] ? static_cast<uint8_t>(strtoul(row[22], nullptr, 10)) : 0;
e.is_locked = row[23] ? static_cast<int8_t>(atoi(row[23])) : 0;
e.add_replay = row[24] ? static_cast<int8_t>(atoi(row[24])) : 1;
all_entries.push_back(e);
}
@@ -480,6 +498,8 @@ public:
e.zone_in_z = row[20] ? strtof(row[20], nullptr) : 0;
e.zone_in_heading = row[21] ? strtof(row[21], nullptr) : 0;
e.has_zone_in = row[22] ? static_cast<uint8_t>(strtoul(row[22], nullptr, 10)) : 0;
e.is_locked = row[23] ? static_cast<int8_t>(atoi(row[23])) : 0;
e.add_replay = row[24] ? static_cast<int8_t>(atoi(row[24])) : 1;
all_entries.push_back(e);
}
@@ -577,6 +597,8 @@ public:
v.push_back(std::to_string(e.zone_in_z));
v.push_back(std::to_string(e.zone_in_heading));
v.push_back(std::to_string(e.has_zone_in));
v.push_back(std::to_string(e.is_locked));
v.push_back(std::to_string(e.add_replay));
auto results = db.QueryDatabase(
fmt::format(
@@ -622,6 +644,8 @@ public:
v.push_back(std::to_string(e.zone_in_z));
v.push_back(std::to_string(e.zone_in_heading));
v.push_back(std::to_string(e.has_zone_in));
v.push_back(std::to_string(e.is_locked));
v.push_back(std::to_string(e.add_replay));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -1,415 +0,0 @@
/**
* DO NOT MODIFY THIS FILE
*
* 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://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_EXPEDITIONS_REPOSITORY_H
#define EQEMU_BASE_EXPEDITIONS_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
class BaseExpeditionsRepository {
public:
struct Expeditions {
uint32_t id;
uint32_t dynamic_zone_id;
uint8_t add_replay_on_join;
uint8_t is_locked;
};
static std::string PrimaryKey()
{
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"id",
"dynamic_zone_id",
"add_replay_on_join",
"is_locked",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"id",
"dynamic_zone_id",
"add_replay_on_join",
"is_locked",
};
}
static std::string ColumnsRaw()
{
return std::string(Strings::Implode(", ", Columns()));
}
static std::string SelectColumnsRaw()
{
return std::string(Strings::Implode(", ", SelectColumns()));
}
static std::string TableName()
{
return std::string("expeditions");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static Expeditions NewEntity()
{
Expeditions e{};
e.id = 0;
e.dynamic_zone_id = 0;
e.add_replay_on_join = 1;
e.is_locked = 0;
return e;
}
static Expeditions GetExpeditions(
const std::vector<Expeditions> &expeditionss,
int expeditions_id
)
{
for (auto &expeditions : expeditionss) {
if (expeditions.id == expeditions_id) {
return expeditions;
}
}
return NewEntity();
}
static Expeditions FindOne(
Database& db,
int expeditions_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
expeditions_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
Expeditions e{};
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.dynamic_zone_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.add_replay_on_join = row[2] ? static_cast<uint8_t>(strtoul(row[2], nullptr, 10)) : 1;
e.is_locked = row[3] ? static_cast<uint8_t>(strtoul(row[3], nullptr, 10)) : 0;
return e;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int expeditions_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
expeditions_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
const Expeditions &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[1] + " = " + std::to_string(e.dynamic_zone_id));
v.push_back(columns[2] + " = " + std::to_string(e.add_replay_on_join));
v.push_back(columns[3] + " = " + std::to_string(e.is_locked));
auto results = db.QueryDatabase(
fmt::format(
"UPDATE {} SET {} WHERE {} = {}",
TableName(),
Strings::Implode(", ", v),
PrimaryKey(),
e.id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static Expeditions InsertOne(
Database& db,
Expeditions e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.dynamic_zone_id));
v.push_back(std::to_string(e.add_replay_on_join));
v.push_back(std::to_string(e.is_locked));
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseInsert(),
Strings::Implode(",", v)
)
);
if (results.Success()) {
e.id = results.LastInsertedID();
return e;
}
e = NewEntity();
return e;
}
static int InsertMany(
Database& db,
const std::vector<Expeditions> &entries
)
{
std::vector<std::string> insert_chunks;
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.dynamic_zone_id));
v.push_back(std::to_string(e.add_replay_on_join));
v.push_back(std::to_string(e.is_locked));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
std::vector<std::string> v;
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseInsert(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static std::vector<Expeditions> All(Database& db)
{
std::vector<Expeditions> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
Expeditions e{};
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.dynamic_zone_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.add_replay_on_join = row[2] ? static_cast<uint8_t>(strtoul(row[2], nullptr, 10)) : 1;
e.is_locked = row[3] ? static_cast<uint8_t>(strtoul(row[3], nullptr, 10)) : 0;
all_entries.push_back(e);
}
return all_entries;
}
static std::vector<Expeditions> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<Expeditions> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {}",
BaseSelect(),
where_filter
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
Expeditions e{};
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.dynamic_zone_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.add_replay_on_join = row[2] ? static_cast<uint8_t>(strtoul(row[2], nullptr, 10)) : 1;
e.is_locked = row[3] ? static_cast<uint8_t>(strtoul(row[3], nullptr, 10)) : 0;
all_entries.push_back(e);
}
return all_entries;
}
static int DeleteWhere(Database& db, const std::string &where_filter)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {}",
TableName(),
where_filter
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int Truncate(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"TRUNCATE TABLE {}",
TableName()
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int64 GetMaxId(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COALESCE(MAX({}), 0) FROM {}",
PrimaryKey(),
TableName()
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static int64 Count(Database& db, const std::string &where_filter = "")
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COUNT(*) FROM {} {}",
TableName(),
(where_filter.empty() ? "" : "WHERE " + where_filter)
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static std::string BaseReplace()
{
return fmt::format(
"REPLACE INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static int ReplaceOne(
Database& db,
const Expeditions &e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.dynamic_zone_id));
v.push_back(std::to_string(e.add_replay_on_join));
v.push_back(std::to_string(e.is_locked));
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseReplace(),
Strings::Implode(",", v)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int ReplaceMany(
Database& db,
const std::vector<Expeditions> &entries
)
{
std::vector<std::string> insert_chunks;
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.dynamic_zone_id));
v.push_back(std::to_string(e.add_replay_on_join));
v.push_back(std::to_string(e.is_locked));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
std::vector<std::string> v;
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseReplace(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
};
#endif //EQEMU_BASE_EXPEDITIONS_REPOSITORY_H
@@ -2,7 +2,7 @@
#define EQEMU_CHARACTER_EXPEDITION_LOCKOUTS_REPOSITORY_H
#include "../database.h"
#include "../expedition_lockout_timer.h"
#include "../dynamic_zone_lockout.h"
#include "../strings.h"
#include "base/base_character_expedition_lockouts_repository.h"
#include <unordered_map>
@@ -47,33 +47,8 @@ public:
// Custom extended repository methods here
struct CharacterExpeditionLockoutsTimeStamp {
int id;
int character_id;
std::string expedition_name;
std::string event_name;
time_t expire_time;
int duration;
std::string from_expedition_uuid;
};
static ExpeditionLockoutTimer GetExpeditionLockoutTimerFromEntry(
CharacterExpeditionLockoutsTimeStamp&& entry)
{
ExpeditionLockoutTimer lockout_timer{
std::move(entry.from_expedition_uuid),
std::move(entry.expedition_name),
std::move(entry.event_name),
static_cast<uint64_t>(entry.expire_time),
static_cast<uint32_t>(entry.duration)
};
return lockout_timer;
}
static std::unordered_map<uint32_t, std::vector<ExpeditionLockoutTimer>> GetManyCharacterLockoutTimers(
Database& db, const std::vector<uint32_t>& character_ids,
const std::string& expedition_name, const std::string& ordered_event_name)
static std::unordered_map<uint32_t, std::vector<DzLockout>> GetLockouts(
Database& db, const std::vector<uint32_t>& char_ids, const std::string& expedition)
{
auto results = db.QueryDatabase(fmt::format(SQL(
SELECT
@@ -84,39 +59,171 @@ public:
from_expedition_uuid
FROM character_expedition_lockouts
WHERE
character_id IN ({})
character_id IN ({0})
AND expire_time > NOW()
AND expedition_name = '{}'
AND expedition_name = '{1}'
ORDER BY
FIELD(character_id, {}),
FIELD(event_name, '{}') DESC
FIELD(character_id, {0}),
FIELD(event_name, '{2}') DESC
),
fmt::join(character_ids, ","),
Strings::Escape(expedition_name),
fmt::join(character_ids, ","),
Strings::Escape(ordered_event_name)
fmt::join(char_ids, ","),
Strings::Escape(expedition),
Strings::Escape(DzLockout::ReplayTimer)
));
std::unordered_map<uint32_t, std::vector<ExpeditionLockoutTimer>> lockouts;
std::unordered_map<uint32_t, std::vector<DzLockout>> lockouts;
for (auto row = results.begin(); row != results.end(); ++row)
{
CharacterExpeditionLockoutsTimeStamp entry{};
int col = 0;
entry.character_id = std::strtoul(row[col++], nullptr, 10);
entry.expire_time = std::strtoull(row[col++], nullptr, 10);
entry.duration = std::strtoul(row[col++], nullptr, 10);
entry.event_name = row[col++];
entry.expedition_name = expedition_name;
entry.from_expedition_uuid = row[col++];
uint32_t char_id = std::strtoul(row[col++], nullptr, 10);
time_t expire_time = std::strtoull(row[col++], nullptr, 10);
uint32_t duration = std::strtoul(row[col++], nullptr, 10);
std::string event = row[col++];
std::string uuid = row[col++];
auto lockout = GetExpeditionLockoutTimerFromEntry(std::move(entry));
lockouts[entry.character_id].emplace_back(std::move(lockout));
lockouts[char_id].emplace_back(std::move(uuid), expedition, std::move(event), expire_time, duration);
}
return lockouts;
}
static std::vector<DzLockout> GetLockouts(Database& db, uint32_t char_id)
{
std::vector<DzLockout> lockouts;
auto rows = GetWhere(db, fmt::format("character_id = {} AND expire_time > NOW()", char_id));
lockouts.reserve(rows.size());
for (auto& row : rows)
{
lockouts.emplace_back(
std::move(row.from_expedition_uuid),
std::move(row.expedition_name),
std::move(row.event_name),
row.expire_time,
row.duration
);
}
return lockouts;
}
static std::vector<CharacterExpeditionLockouts> GetLockouts(Database& db, const std::vector<std::string>& names, const std::string& expedition, const std::string& event)
{
if (names.empty())
{
return {};
}
return GetWhere(db, fmt::format(
"character_id IN (select id from character_data where name IN ('{}')) AND expire_time > NOW() AND expedition_name = '{}' AND event_name = '{}' LIMIT 1",
fmt::join(names, "','"), Strings::Escape(expedition), Strings::Escape(event)));
}
static void InsertLockouts(Database& db, uint32_t char_id, const std::vector<DzLockout>& lockouts)
{
std::string insert_values;
for (const auto& lockout : lockouts)
{
fmt::format_to(std::back_inserter(insert_values),
"({}, FROM_UNIXTIME({}), {}, '{}', '{}', '{}'),",
char_id,
lockout.GetExpireTime(),
lockout.GetDuration(),
Strings::Escape(lockout.UUID()),
Strings::Escape(lockout.DzName()),
Strings::Escape(lockout.Event())
);
}
if (!insert_values.empty())
{
insert_values.pop_back(); // trailing comma
auto query = fmt::format(SQL(
INSERT INTO character_expedition_lockouts
(character_id, expire_time, duration, from_expedition_uuid, expedition_name, event_name)
VALUES {}
ON DUPLICATE KEY UPDATE
from_expedition_uuid = VALUES(from_expedition_uuid),
expire_time = VALUES(expire_time),
duration = VALUES(duration);
), insert_values);
db.QueryDatabase(query);
}
}
static void InsertLockout(Database& db, const std::vector<uint32_t>& char_ids, const DzLockout& lockout)
{
std::string insert_values;
for (const auto& char_id : char_ids)
{
fmt::format_to(std::back_inserter(insert_values),
"({}, FROM_UNIXTIME({}), {}, '{}', '{}', '{}'),",
char_id,
lockout.GetExpireTime(),
lockout.GetDuration(),
Strings::Escape(lockout.UUID()),
Strings::Escape(lockout.DzName()),
Strings::Escape(lockout.Event())
);
}
if (!insert_values.empty())
{
insert_values.pop_back(); // trailing comma
auto query = fmt::format(SQL(
INSERT INTO character_expedition_lockouts
(character_id, expire_time, duration, from_expedition_uuid, expedition_name, event_name)
VALUES {}
ON DUPLICATE KEY UPDATE
from_expedition_uuid = VALUES(from_expedition_uuid),
expire_time = VALUES(expire_time),
duration = VALUES(duration);
), insert_values);
db.QueryDatabase(query);
}
}
// inserts a new lockout or updates existing lockout with seconds added to current time
static void AddLockoutDuration(Database& db, const std::vector<uint32_t>& char_ids, const DzLockout& lockout, int seconds)
{
std::string insert_values;
for (const auto& char_id : char_ids)
{
fmt::format_to(std::back_inserter(insert_values),
"({}, FROM_UNIXTIME({}), {}, '{}', '{}', '{}'),",
char_id,
lockout.GetExpireTime(),
lockout.GetDuration(),
Strings::Escape(lockout.UUID()),
Strings::Escape(lockout.DzName()),
Strings::Escape(lockout.Event())
);
}
if (!insert_values.empty())
{
insert_values.pop_back(); // trailing comma
auto query = fmt::format(SQL(
INSERT INTO character_expedition_lockouts
(character_id, expire_time, duration, from_expedition_uuid, expedition_name, event_name)
VALUES {0}
ON DUPLICATE KEY UPDATE
from_expedition_uuid = VALUES(from_expedition_uuid),
expire_time = DATE_ADD(expire_time, INTERVAL {1} SECOND),
duration = GREATEST(0, CAST(duration AS SIGNED) + {1});
), insert_values, seconds);
db.QueryDatabase(query);
}
}
};
#endif //EQEMU_CHARACTER_EXPEDITION_LOCKOUTS_REPOSITORY_H
@@ -0,0 +1,84 @@
#ifndef EQEMU_DYNAMIC_ZONE_LOCKOUTS_REPOSITORY_H
#define EQEMU_DYNAMIC_ZONE_LOCKOUTS_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
#include "../dynamic_zone_lockout.h"
#include "base/base_dynamic_zone_lockouts_repository.h"
class DynamicZoneLockoutsRepository: public BaseDynamicZoneLockoutsRepository {
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
*
* DynamicZoneLockoutsRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* DynamicZoneLockoutsRepository::GetWhereNeverExpires()
* DynamicZoneLockoutsRepository::GetWhereXAndY()
* DynamicZoneLockoutsRepository::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
static void InsertLockouts(Database& db, uint32_t dz_id, const std::vector<DzLockout>& lockouts)
{
std::string insert_values;
for (const auto& lockout : lockouts)
{
fmt::format_to(std::back_inserter(insert_values),
"({}, '{}', '{}', FROM_UNIXTIME({}), {}),",
dz_id,
Strings::Escape(lockout.UUID()),
Strings::Escape(lockout.Event()),
lockout.GetExpireTime(),
lockout.GetDuration()
);
}
if (!insert_values.empty())
{
insert_values.pop_back(); // trailing comma
auto query = fmt::format(SQL(
INSERT INTO dynamic_zone_lockouts
(dynamic_zone_id, from_expedition_uuid, event_name, expire_time, duration)
VALUES {}
ON DUPLICATE KEY UPDATE
from_expedition_uuid = VALUES(from_expedition_uuid),
expire_time = VALUES(expire_time),
duration = VALUES(duration);
), insert_values);
db.QueryDatabase(query);
}
}
};
#endif //EQEMU_DYNAMIC_ZONE_LOCKOUTS_REPOSITORY_H
@@ -65,7 +65,7 @@ public:
));
}
static std::vector<MemberWithName> GetAllWithNames(Database& db)
static std::vector<MemberWithName> AllWithNames(Database& db)
{
std::vector<MemberWithName> all_entries;
@@ -146,65 +146,34 @@ public:
static void RemoveMember(Database& db, uint32_t dynamic_zone_id, uint32_t character_id)
{
db.QueryDatabase(fmt::format(SQL(
DELETE FROM {}
WHERE dynamic_zone_id = {} AND character_id = {};
),
TableName(), dynamic_zone_id, character_id
));
DeleteWhere(db, fmt::format("dynamic_zone_id = {} AND character_id = {}", dynamic_zone_id, character_id));
}
static void RemoveAllMembers(Database& db, uint32_t dynamic_zone_id)
{
db.QueryDatabase(fmt::format(SQL(
DELETE FROM {}
WHERE dynamic_zone_id = {};
),
TableName(), dynamic_zone_id
));
DeleteWhere(db, fmt::format("dynamic_zone_id = {}", dynamic_zone_id));
}
static void RemoveAllMembers(Database& db, std::vector<uint32_t> dynamic_zone_ids)
static uint32_t InsertOrUpdateMany(Database& db, const std::vector<DynamicZoneMembers>& entries)
{
if (!dynamic_zone_ids.empty())
if (entries.empty())
{
db.QueryDatabase(fmt::format(SQL(
DELETE FROM {}
WHERE dynamic_zone_id IN ({});
),
TableName(), Strings::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_chunks.push_back("(" + Strings::Implode(",", insert_values) + ")");
return 0;
}
std::vector<std::string> insert_values;
std::vector<std::string> values;
values.reserve(entries.size());
auto results = db.QueryDatabase(
fmt::format(
"INSERT INTO {} ({}) VALUES {} ON DUPLICATE KEY UPDATE id = id;",
TableName(),
ColumnsRaw(),
Strings::Implode(",", insert_chunks)
)
);
for (const auto& entry : entries)
{
values.push_back(fmt::format("({},{},{})", entry.id, entry.dynamic_zone_id, entry.character_id));
}
return (results.Success() ? results.RowsAffected() : 0);
auto results = db.QueryDatabase(fmt::format(
"INSERT INTO {} ({}) VALUES {} ON DUPLICATE KEY UPDATE id = id;",
TableName(), ColumnsRaw(), fmt::join(values, ",")));
return results.Success() ? results.RowsAffected() : 0;
}
};
@@ -70,6 +70,8 @@ public:
float zone_in_z;
float zone_in_heading;
int has_zone_in;
int8_t is_locked;
int8_t add_replay;
int zone;
int version;
int is_global;
@@ -105,6 +107,8 @@ public:
dynamic_zones.zone_in_z,
dynamic_zones.zone_in_heading,
dynamic_zones.has_zone_in,
dynamic_zones.is_locked,
dynamic_zones.add_replay,
instance_list.zone,
instance_list.version,
instance_list.is_global,
@@ -144,6 +148,8 @@ public:
entry.zone_in_z = strtof(row[col++], nullptr);
entry.zone_in_heading = strtof(row[col++], nullptr);
entry.has_zone_in = strtol(row[col++], nullptr, 10) != 0;
entry.is_locked = static_cast<int8_t>(strtol(row[col++], nullptr, 10));
entry.add_replay = static_cast<int8_t>(strtol(row[col++], nullptr, 10));
// from instance_list
entry.zone = strtol(row[col++], nullptr, 10);
entry.version = strtol(row[col++], nullptr, 10);
@@ -244,6 +250,22 @@ public:
}
}
static void UpdateLocked(Database& db, uint32_t dz_id, bool lock)
{
if (dz_id != 0)
{
db.QueryDatabase(fmt::format("UPDATE dynamic_zones SET is_locked = {} WHERE id = {}", lock, dz_id));
}
}
static void UpdateReplayOnJoin(Database& db, uint32_t dz_id, bool enabled)
{
if (dz_id != 0)
{
db.QueryDatabase(fmt::format("UPDATE dynamic_zones SET add_replay = {} WHERE id = {}", enabled, dz_id));
}
}
static void UpdateSwitchID(Database& db, uint32_t dz_id, int dz_switch_id)
{
if (dz_id != 0)
@@ -351,6 +373,59 @@ public:
return all_entries;
}
struct CharacterDz
{
uint32_t id;
std::string name;
uint32_t dz_id;
};
// get character ids with possible active dz id by type
static std::vector<CharacterDz> GetCharactersWithDz(Database& db, const std::vector<std::string>& names, int type)
{
if (names.empty())
{
return {};
}
std::vector<CharacterDz> entries;
entries.reserve(names.size());
auto results = db.QueryDatabase(fmt::format(SQL(
SELECT
character_data.id,
character_data.name,
MAX(dynamic_zones.id)
FROM character_data
LEFT JOIN dynamic_zone_members
ON character_data.id = dynamic_zone_members.character_id
LEFT JOIN dynamic_zones
ON dynamic_zone_members.dynamic_zone_id = dynamic_zones.id
AND dynamic_zones.`type` = {0}
WHERE character_data.name IN ('{1}')
GROUP BY character_data.id
ORDER BY FIELD(character_data.name, '{1}')
),
type,
fmt::join(names, "','")
));
if (results.Success())
{
for (auto row = results.begin(); row != results.end(); ++row)
{
CharacterDz entry{};
entry.id = std::strtoul(row[0], nullptr, 10);
entry.name = row[1];
entry.dz_id = row[2] ? std::strtoul(row[2], nullptr, 10) : 0;
entries.push_back(std::move(entry));
}
}
return entries;
}
};
#endif //EQEMU_DYNAMIC_ZONES_REPOSITORY_H
@@ -1,102 +0,0 @@
#ifndef EQEMU_EXPEDITION_LOCKOUTS_REPOSITORY_H
#define EQEMU_EXPEDITION_LOCKOUTS_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
#include "base/base_expedition_lockouts_repository.h"
class ExpeditionLockoutsRepository: public BaseExpeditionLockoutsRepository {
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
*
* ExpeditionLockoutsRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* ExpeditionLockoutsRepository::GetWhereNeverExpires()
* ExpeditionLockoutsRepository::GetWhereXAndY()
* ExpeditionLockoutsRepository::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 ExpeditionLockoutsWithTimestamp {
uint32_t id;
uint32_t expedition_id;
std::string event_name;
time_t expire_time;
int duration;
std::string from_expedition_uuid;
};
static std::vector<ExpeditionLockoutsWithTimestamp> GetWithTimestamp(
Database& db, const std::vector<uint32_t>& expedition_ids)
{
if (expedition_ids.empty())
{
return {};
}
std::vector<ExpeditionLockoutsWithTimestamp> all_entries;
auto results = db.QueryDatabase(fmt::format(SQL(
SELECT
id,
expedition_id,
event_name,
UNIX_TIMESTAMP(expire_time),
duration,
from_expedition_uuid
FROM expedition_lockouts
WHERE expedition_id IN ({})
),
Strings::Join(expedition_ids, ",")
));
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row)
{
ExpeditionLockoutsWithTimestamp entry{};
int col = 0;
entry.id = strtoul(row[col++], nullptr, 10);
entry.expedition_id = strtoul(row[col++], nullptr, 10);
entry.event_name = row[col++];
entry.expire_time = strtoull(row[col++], nullptr, 10);
entry.duration = strtol(row[col++], nullptr, 10);
entry.from_expedition_uuid = row[col++];
all_entries.emplace_back(std::move(entry));
}
return all_entries;
}
};
#endif //EQEMU_EXPEDITION_LOCKOUTS_REPOSITORY_H
@@ -1,134 +0,0 @@
#ifndef EQEMU_EXPEDITIONS_REPOSITORY_H
#define EQEMU_EXPEDITIONS_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
#include "base/base_expeditions_repository.h"
class ExpeditionsRepository: public BaseExpeditionsRepository {
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
*
* ExpeditionsRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* ExpeditionsRepository::GetWhereNeverExpires()
* ExpeditionsRepository::GetWhereXAndY()
* ExpeditionsRepository::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 CharacterExpedition
{
uint32_t id;
std::string name;
uint32_t expedition_id;
};
static std::vector<CharacterExpedition> GetCharactersWithExpedition(
Database& db, const std::vector<std::string>& character_names)
{
if (character_names.empty())
{
return {};
}
std::vector<CharacterExpedition> entries;
auto joined_character_names = fmt::format("'{}'", Strings::Join(character_names, "','"));
auto results = db.QueryDatabase(fmt::format(SQL(
SELECT
character_data.id,
character_data.name,
MAX(expeditions.id)
FROM character_data
LEFT JOIN dynamic_zone_members
ON character_data.id = dynamic_zone_members.character_id
LEFT JOIN expeditions
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, {})
),
joined_character_names,
joined_character_names
));
if (results.Success())
{
entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row)
{
CharacterExpedition entry{};
entry.id = std::strtoul(row[0], nullptr, 10);
entry.name = row[1];
entry.expedition_id = row[2] ? std::strtoul(row[2], nullptr, 10) : 0;
entries.emplace_back(std::move(entry));
}
}
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 = {}
),
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
@@ -45,33 +45,26 @@ public:
// Custom extended repository methods here
static int InsertOrUpdateMany(Database& db,
const std::vector<InstanceListPlayer>& instance_list_player_entries)
static uint32_t InsertOrUpdateMany(Database& db, const std::vector<InstanceListPlayer>& entries)
{
std::vector<std::string> insert_chunks;
for (auto &instance_list_player_entry: instance_list_player_entries)
if (entries.empty())
{
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("(" + Strings::Implode(",", insert_values) + ")");
return 0;
}
std::vector<std::string> insert_values;
std::vector<std::string> values;
values.reserve(entries.size());
auto results = db.QueryDatabase(
fmt::format(
"INSERT INTO {} ({}) VALUES {} ON DUPLICATE KEY UPDATE id = VALUES(id)",
TableName(),
ColumnsRaw(),
Strings::Implode(",", insert_chunks)
)
);
for (const auto& entry : entries)
{
values.push_back(fmt::format("({},{})", entry.id, entry.charid));
}
return (results.Success() ? results.RowsAffected() : 0);
auto results = db.QueryDatabase(fmt::format(
"INSERT INTO {} ({}) VALUES {} ON DUPLICATE KEY UPDATE id = VALUES(id)",
TableName(), ColumnsRaw(), fmt::join(values, ",")));
return results.Success() ? results.RowsAffected() : 0;
}
static bool ReplaceOne(Database& db, InstanceListPlayer e)
+29 -36
View File
@@ -170,18 +170,6 @@
#define ServerOP_LFPMatches 0x0214
#define ServerOP_ClientVersionSummary 0x0215
// expedition
#define ServerOP_ExpeditionCreate 0x0400
#define ServerOP_ExpeditionLockout 0x0403
#define ServerOP_ExpeditionDzAddPlayer 0x0408
#define ServerOP_ExpeditionDzMakeLeader 0x0409
#define ServerOP_ExpeditionCharacterLockout 0x040d
#define ServerOP_ExpeditionSaveInvite 0x040e
#define ServerOP_ExpeditionRequestInvite 0x040f
#define ServerOP_ExpeditionReplayOnJoin 0x0410
#define ServerOP_ExpeditionLockState 0x0411
#define ServerOP_ExpeditionLockoutDuration 0x0414
// dz
#define ServerOP_DzAddRemoveMember 0x0450
#define ServerOP_DzRemoveAllMembers 0x0451
@@ -199,6 +187,15 @@
#define ServerOP_DzDeleted 0x045d
#define ServerOP_DzSetSwitchID 0x045e
#define ServerOP_DzMovePC 0x045f
#define ServerOP_DzLock 0x0460
#define ServerOP_DzReplayOnJoin 0x0461
#define ServerOP_DzLockout 0x0462
#define ServerOP_DzLockoutDuration 0x0463
#define ServerOP_DzCharacterLockout 0x0464
#define ServerOP_DzAddPlayer 0x0465
#define ServerOP_DzSaveInvite 0x0466
#define ServerOP_DzRequestInvite 0x0467
#define ServerOP_DzMakeLeader 0x0468
#define ServerOP_LSInfo 0x1000
#define ServerOP_LSStatus 0x1001
@@ -1543,10 +1540,8 @@ struct UCSServerStatus_Struct {
};
};
struct ServerExpeditionID_Struct {
uint32 expedition_id;
uint32 sender_zone_id;
uint32 sender_instance_id;
struct ServerCharacterID_Struct {
uint32_t char_id;
};
struct ServerDzLeaderID_Struct {
@@ -1580,45 +1575,42 @@ struct ServerDzMovePC_Struct {
uint32 character_id;
};
struct ServerExpeditionLockout_Struct {
uint32 expedition_id;
struct ServerDzLockout_Struct {
uint32 dz_id;
uint64 expire_time;
uint32 duration;
uint32 sender_zone_id;
uint16 sender_instance_id;
uint8 remove;
uint8 members_only;
int seconds_adjust;
int seconds;
char event_name[256];
};
struct ServerExpeditionLockState_Struct {
uint32 expedition_id;
struct ServerDzLock_Struct {
uint32 dz_id;
uint32 sender_zone_id;
uint16 sender_instance_id;
uint8 enabled;
bool lock;
uint8 lock_msg; // 0: none, 1: closing 2: trial begin
uint32 color;
};
struct ServerExpeditionSetting_Struct {
uint32 expedition_id;
struct ServerDzBool_Struct {
uint32 dz_id;
uint32 sender_zone_id;
uint16 sender_instance_id;
uint8 enabled;
bool enabled;
};
struct ServerExpeditionCharacterLockout_Struct {
struct ServerDzCharacterLockout_Struct {
uint8 remove;
uint32 character_id;
uint32 char_id;
uint64 expire_time;
uint32 duration;
char uuid[37];
char expedition_name[128];
char event_name[256];
};
struct ServerExpeditionCharacterID_Struct {
uint32_t character_id;
char expedition[128];
char event[256];
};
struct ServerDzExpireWarning_Struct {
@@ -1627,7 +1619,7 @@ struct ServerDzExpireWarning_Struct {
};
struct ServerDzCommand_Struct {
uint32 expedition_id;
uint32 dz_id;
uint8 is_char_online; // 0: target name is offline, 1: online
char requester_name[64];
char target_name[64];
@@ -1696,11 +1688,12 @@ struct ServerDzSetDuration_Struct {
uint32 seconds;
};
struct ServerDzCreateSerialized_Struct {
struct ServerDzCreate_Struct {
uint16_t origin_zone_id;
uint16_t origin_instance_id;
uint32_t dz_id;
uint32_t cereal_size;
char cereal_data[0];
char cereal_data[1];
};
struct ServerSendPlayerEvent_Struct {
+1 -1
View File
@@ -42,7 +42,7 @@
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/
#define CURRENT_BINARY_DATABASE_VERSION 9304
#define CURRENT_BINARY_DATABASE_VERSION 9305
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9054
#endif