mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-26 15:11:30 +00:00
[Expeditions] Create common dz abstract class (#1312)
This creates an abstract class in common so zone and world can share most of the implementation. World now has access to the same dz data and api as zone. Rename CharacterChange to AddRemoveCharacter for clarity Rename GetRemainingDuration to GetDurationRemaining for consistency Move dynamic zone queries to custom repository methods
This commit is contained in:
parent
f5cf566fca
commit
049fe55c7f
@ -16,6 +16,7 @@ SET(common_sources
|
||||
database_instances.cpp
|
||||
dbcore.cpp
|
||||
deity.cpp
|
||||
dynamic_zone_base.cpp
|
||||
emu_constants.cpp
|
||||
emu_limits.cpp
|
||||
emu_opcodes.cpp
|
||||
@ -466,6 +467,7 @@ SET(common_headers
|
||||
database_schema.h
|
||||
dbcore.h
|
||||
deity.h
|
||||
dynamic_zone_base.h
|
||||
emu_constants.h
|
||||
emu_limits.h
|
||||
emu_opcodes.h
|
||||
|
||||
289
common/dynamic_zone_base.cpp
Normal file
289
common/dynamic_zone_base.cpp
Normal file
@ -0,0 +1,289 @@
|
||||
#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 "servertalk.h"
|
||||
|
||||
DynamicZoneBase::DynamicZoneBase(DynamicZonesRepository::DynamicZoneInstance&& entry)
|
||||
{
|
||||
LoadRepositoryResult(std::move(entry));
|
||||
}
|
||||
|
||||
uint32_t DynamicZoneBase::Create()
|
||||
{
|
||||
if (m_id != 0)
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
if (GetInstanceID() == 0)
|
||||
{
|
||||
CreateInstance();
|
||||
}
|
||||
|
||||
m_id = SaveToDatabase();
|
||||
|
||||
return m_id;
|
||||
}
|
||||
|
||||
uint32_t DynamicZoneBase::CreateInstance()
|
||||
{
|
||||
if (m_instance_id)
|
||||
{
|
||||
LogDynamicZones("CreateInstance failed, instance id [{}] already created", m_instance_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!m_zone_id)
|
||||
{
|
||||
LogDynamicZones("CreateInstance failed, invalid zone id [{}]", m_zone_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t unused_instance_id = 0;
|
||||
if (!GetDatabase().GetUnusedInstanceID(unused_instance_id)) // todo: doesn't this race with insert?
|
||||
{
|
||||
LogDynamicZones("Failed to find unused instance id");
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_start_time = std::chrono::system_clock::now();
|
||||
m_expire_time = m_start_time + m_duration;
|
||||
|
||||
auto insert_instance = InstanceListRepository::NewEntity();
|
||||
insert_instance.id = unused_instance_id;
|
||||
insert_instance.zone = m_zone_id;
|
||||
insert_instance.version = m_zone_version;
|
||||
insert_instance.start_time = static_cast<int>(std::chrono::system_clock::to_time_t(m_start_time));
|
||||
insert_instance.duration = static_cast<int>(m_duration.count());
|
||||
insert_instance.never_expires = m_never_expires;
|
||||
|
||||
auto instance = InstanceListRepository::InsertOne(GetDatabase(), insert_instance);
|
||||
if (instance.id == 0)
|
||||
{
|
||||
LogDynamicZones("Failed to create instance [{}] for zone [{}]", unused_instance_id, m_zone_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_instance_id = instance.id;
|
||||
|
||||
return m_instance_id;
|
||||
}
|
||||
|
||||
void DynamicZoneBase::LoadRepositoryResult(DynamicZonesRepository::DynamicZoneInstance&& dz_entry)
|
||||
{
|
||||
m_id = dz_entry.id;
|
||||
m_instance_id = dz_entry.instance_id;
|
||||
m_type = static_cast<DynamicZoneType>(dz_entry.type);
|
||||
m_compass.zone_id = dz_entry.compass_zone_id;
|
||||
m_compass.x = dz_entry.compass_x;
|
||||
m_compass.y = dz_entry.compass_y;
|
||||
m_compass.z = dz_entry.compass_z;
|
||||
m_safereturn.zone_id = dz_entry.safe_return_zone_id;
|
||||
m_safereturn.x = dz_entry.safe_return_x;
|
||||
m_safereturn.y = dz_entry.safe_return_y;
|
||||
m_safereturn.z = dz_entry.safe_return_z;
|
||||
m_safereturn.heading = dz_entry.safe_return_heading;
|
||||
m_zonein.x = dz_entry.zone_in_x;
|
||||
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);
|
||||
// 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_expire_time = m_start_time + m_duration;
|
||||
}
|
||||
|
||||
uint32_t DynamicZoneBase::SaveToDatabase()
|
||||
{
|
||||
LogDynamicZonesDetail("Saving dz instance [{}] to database", m_instance_id);
|
||||
|
||||
if (m_instance_id != 0)
|
||||
{
|
||||
auto insert_dz = DynamicZonesRepository::NewEntity();
|
||||
insert_dz.instance_id = m_instance_id,
|
||||
insert_dz.type = static_cast<int>(m_type);
|
||||
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;
|
||||
}
|
||||
|
||||
void DynamicZoneBase::AddCharacter(uint32_t character_id)
|
||||
{
|
||||
GetDatabase().AddClientToInstance(m_instance_id, character_id);
|
||||
SendInstanceAddRemoveCharacter(character_id, false); // stops client kick timer
|
||||
}
|
||||
|
||||
void DynamicZoneBase::RemoveCharacter(uint32_t character_id)
|
||||
{
|
||||
GetDatabase().RemoveClientFromInstance(m_instance_id, character_id);
|
||||
SendInstanceAddRemoveCharacter(character_id, true); // start client kick timer
|
||||
}
|
||||
|
||||
void DynamicZoneBase::RemoveAllCharacters(bool enable_removal_timers)
|
||||
{
|
||||
if (GetInstanceID() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (enable_removal_timers)
|
||||
{
|
||||
SendInstanceRemoveAllCharacters();
|
||||
}
|
||||
|
||||
GetDatabase().RemoveClientsFromInstance(GetInstanceID());
|
||||
}
|
||||
|
||||
void DynamicZoneBase::SaveInstanceMembersToDatabase(const std::vector<uint32_t>& character_ids)
|
||||
{
|
||||
LogDynamicZonesDetail("Saving [{}] members for instance [{}]", character_ids.size(), m_instance_id);
|
||||
|
||||
std::vector<InstanceListPlayerRepository::InstanceListPlayer> insert_players;
|
||||
|
||||
for (const auto& character_id : character_ids)
|
||||
{
|
||||
InstanceListPlayerRepository::InstanceListPlayer entry{};
|
||||
entry.id = static_cast<int>(m_instance_id);
|
||||
entry.charid = static_cast<int>(character_id);
|
||||
insert_players.emplace_back(entry);
|
||||
}
|
||||
|
||||
InstanceListPlayerRepository::InsertMany(GetDatabase(), insert_players);
|
||||
}
|
||||
|
||||
void DynamicZoneBase::SetCompass(const DynamicZoneLocation& location, bool update_db)
|
||||
{
|
||||
ProcessCompassChange(location);
|
||||
|
||||
if (update_db)
|
||||
{
|
||||
LogDynamicZonesDetail("Saving [{}] compass zone: [{}] xyz: ([{}], [{}], [{}])",
|
||||
m_id, m_compass.zone_id, m_compass.x, m_compass.y, m_compass.z);
|
||||
|
||||
DynamicZonesRepository::UpdateCompass(GetDatabase(),
|
||||
m_id, m_compass.zone_id, m_compass.x, m_compass.y, m_compass.z);
|
||||
|
||||
SendGlobalLocationChange(ServerOP_DzSetCompass, location);
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicZoneBase::SetCompass(uint32_t zone_id, float x, float y, float z, bool update_db)
|
||||
{
|
||||
SetCompass({ zone_id, x, y, z, 0.0f }, update_db);
|
||||
}
|
||||
|
||||
void DynamicZoneBase::SetSafeReturn(const DynamicZoneLocation& location, bool update_db)
|
||||
{
|
||||
m_safereturn = location;
|
||||
|
||||
if (update_db)
|
||||
{
|
||||
LogDynamicZonesDetail("Saving [{}] safereturn zone: [{}] xyzh: ([{}], [{}], [{}], [{}])",
|
||||
m_id, m_safereturn.zone_id, m_safereturn.x, m_safereturn.y, m_safereturn.z, m_safereturn.heading);
|
||||
|
||||
DynamicZonesRepository::UpdateSafeReturn(GetDatabase(), m_id, m_safereturn.zone_id,
|
||||
m_safereturn.x, m_safereturn.y, m_safereturn.z, m_safereturn.heading);
|
||||
|
||||
SendGlobalLocationChange(ServerOP_DzSetSafeReturn, location);
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicZoneBase::SetSafeReturn(uint32_t zone_id, float x, float y, float z, float heading, bool update_db)
|
||||
{
|
||||
SetSafeReturn({ zone_id, x, y, z, heading }, update_db);
|
||||
}
|
||||
|
||||
void DynamicZoneBase::SetZoneInLocation(const DynamicZoneLocation& location, bool update_db)
|
||||
{
|
||||
m_zonein = location;
|
||||
m_has_zonein = true;
|
||||
|
||||
if (update_db)
|
||||
{
|
||||
LogDynamicZonesDetail("Saving [{}] zonein zone: [{}] xyzh: ([{}], [{}], [{}], [{}])",
|
||||
m_id, m_zone_id, m_zonein.x, m_zonein.y, m_zonein.z, m_zonein.heading);
|
||||
|
||||
DynamicZonesRepository::UpdateZoneIn(GetDatabase(), m_id, m_zone_id,
|
||||
m_zonein.x, m_zonein.y, m_zonein.z, m_zonein.heading, m_has_zonein);
|
||||
|
||||
SendGlobalLocationChange(ServerOP_DzSetZoneIn, location);
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicZoneBase::SetZoneInLocation(float x, float y, float z, float heading, bool update_db)
|
||||
{
|
||||
SetZoneInLocation({ 0, x, y, z, heading }, update_db);
|
||||
}
|
||||
|
||||
uint32_t DynamicZoneBase::GetSecondsRemaining() const
|
||||
{
|
||||
auto remaining = std::chrono::duration_cast<std::chrono::seconds>(GetDurationRemaining()).count();
|
||||
return std::max(0, static_cast<int>(remaining));
|
||||
}
|
||||
|
||||
std::unique_ptr<ServerPacket> DynamicZoneBase::CreateServerAddRemoveCharacterPacket(
|
||||
uint32_t character_id, bool removed)
|
||||
{
|
||||
constexpr uint32_t pack_size = sizeof(ServerDzCharacter_Struct);
|
||||
auto pack = std::make_unique<ServerPacket>(ServerOP_DzAddRemoveCharacter, pack_size);
|
||||
auto buf = reinterpret_cast<ServerDzCharacter_Struct*>(pack->pBuffer);
|
||||
buf->zone_id = GetZoneID();
|
||||
buf->instance_id = GetInstanceID();
|
||||
buf->remove = removed;
|
||||
buf->character_id = character_id;
|
||||
|
||||
return pack;
|
||||
}
|
||||
|
||||
std::unique_ptr<ServerPacket> DynamicZoneBase::CreateServerRemoveAllCharactersPacket()
|
||||
{
|
||||
constexpr uint32_t pack_size = sizeof(ServerDzCharacter_Struct);
|
||||
auto pack = std::make_unique<ServerPacket>(ServerOP_DzRemoveAllCharacters, pack_size);
|
||||
auto buf = reinterpret_cast<ServerDzCharacter_Struct*>(pack->pBuffer);
|
||||
buf->zone_id = GetZoneID();
|
||||
buf->instance_id = GetInstanceID();
|
||||
buf->remove = true;
|
||||
buf->character_id = 0;
|
||||
|
||||
return pack;
|
||||
}
|
||||
|
||||
std::unique_ptr<ServerPacket> DynamicZoneBase::CreateServerDzLocationPacket(
|
||||
uint16_t server_opcode, const DynamicZoneLocation& location)
|
||||
{
|
||||
constexpr uint32_t pack_size = sizeof(ServerDzLocation_Struct);
|
||||
auto pack = std::make_unique<ServerPacket>(server_opcode, pack_size);
|
||||
auto buf = reinterpret_cast<ServerDzLocation_Struct*>(pack->pBuffer);
|
||||
buf->dz_id = GetID();
|
||||
buf->sender_zone_id = GetCurrentZoneID();
|
||||
buf->sender_instance_id = GetCurrentInstanceID();
|
||||
buf->zone_id = location.zone_id;
|
||||
buf->x = location.x;
|
||||
buf->y = location.y;
|
||||
buf->z = location.z;
|
||||
buf->heading = location.heading;
|
||||
|
||||
return pack;
|
||||
}
|
||||
112
common/dynamic_zone_base.h
Normal file
112
common/dynamic_zone_base.h
Normal file
@ -0,0 +1,112 @@
|
||||
#ifndef COMMON_DYNAMIC_ZONE_BASE_H
|
||||
#define COMMON_DYNAMIC_ZONE_BASE_H
|
||||
|
||||
#include "eq_constants.h"
|
||||
#include "repositories/dynamic_zones_repository.h"
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class Database;
|
||||
class ServerPacket;
|
||||
|
||||
struct DynamicZoneLocation
|
||||
{
|
||||
uint32_t zone_id = 0;
|
||||
float x = 0.0f;
|
||||
float y = 0.0f;
|
||||
float z = 0.0f;
|
||||
float heading = 0.0f;
|
||||
|
||||
DynamicZoneLocation() = default;
|
||||
DynamicZoneLocation(uint32_t zone_id_, float x_, float y_, float z_, float heading_)
|
||||
: zone_id(zone_id_), x(x_), y(y_), z(z_), heading(heading_) {}
|
||||
};
|
||||
|
||||
class DynamicZoneBase
|
||||
{
|
||||
public:
|
||||
virtual ~DynamicZoneBase() = default;
|
||||
DynamicZoneBase(const DynamicZoneBase&) = default;
|
||||
DynamicZoneBase(DynamicZoneBase&&) = default;
|
||||
DynamicZoneBase& operator=(const DynamicZoneBase&) = default;
|
||||
DynamicZoneBase& operator=(DynamicZoneBase&&) = default;
|
||||
DynamicZoneBase() = default;
|
||||
DynamicZoneBase(uint32_t dz_id) : m_id(dz_id) {}
|
||||
DynamicZoneBase(DynamicZoneType type) : m_type(type) {}
|
||||
DynamicZoneBase(DynamicZonesRepository::DynamicZoneInstance&& entry);
|
||||
|
||||
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 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& GetName() const { return m_name; }
|
||||
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);
|
||||
uint32_t Create();
|
||||
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); }
|
||||
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 RemoveAllCharacters(bool enable_removal_timers = true);
|
||||
void RemoveCharacter(uint32_t character_id);
|
||||
void SaveInstanceMembersToDatabase(const std::vector<uint32_t>& character_ids);
|
||||
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; }
|
||||
void SetName(const std::string& name) { m_name = name; }
|
||||
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 SetZoneInLocation(const DynamicZoneLocation& location, bool update_db = false);
|
||||
void SetZoneInLocation(float x, float y, float z, float heading, bool update_db = false);
|
||||
|
||||
protected:
|
||||
virtual uint16_t GetCurrentInstanceID() { return 0; }
|
||||
virtual uint16_t GetCurrentZoneID() { return 0; }
|
||||
virtual Database& GetDatabase() = 0;
|
||||
virtual void ProcessCompassChange(const DynamicZoneLocation& location) { m_compass = location; }
|
||||
virtual void SendInstanceAddRemoveCharacter(uint32_t character_id, bool remove) = 0;
|
||||
virtual void SendInstanceRemoveAllCharacters() = 0;
|
||||
virtual void SendGlobalLocationChange(uint16_t server_opcode, const DynamicZoneLocation& location) = 0;
|
||||
|
||||
uint32_t CreateInstance();
|
||||
void LoadRepositoryResult(DynamicZonesRepository::DynamicZoneInstance&& dz_entry);
|
||||
uint32_t SaveToDatabase();
|
||||
|
||||
std::unique_ptr<ServerPacket> CreateServerAddRemoveCharacterPacket(uint32_t character_id, bool removed);
|
||||
std::unique_ptr<ServerPacket> CreateServerRemoveAllCharactersPacket();
|
||||
std::unique_ptr<ServerPacket> CreateServerDzLocationPacket(uint16_t server_opcode, const DynamicZoneLocation& location);
|
||||
|
||||
uint32_t m_id = 0;
|
||||
uint32_t m_zone_id = 0;
|
||||
uint32_t m_instance_id = 0;
|
||||
uint32_t m_zone_version = 0;
|
||||
bool m_never_expires = false;
|
||||
bool m_has_zonein = false;
|
||||
std::string m_name;
|
||||
std::string m_leader_name;
|
||||
DynamicZoneType m_type{ DynamicZoneType::None };
|
||||
DynamicZoneLocation m_compass;
|
||||
DynamicZoneLocation m_safereturn;
|
||||
DynamicZoneLocation m_zonein;
|
||||
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;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -65,6 +65,241 @@ public:
|
||||
|
||||
// Custom extended repository methods here
|
||||
|
||||
struct DynamicZoneInstance
|
||||
{
|
||||
uint32_t id;
|
||||
int instance_id;
|
||||
int type;
|
||||
int compass_zone_id;
|
||||
float compass_x;
|
||||
float compass_y;
|
||||
float compass_z;
|
||||
int safe_return_zone_id;
|
||||
float safe_return_x;
|
||||
float safe_return_y;
|
||||
float safe_return_z;
|
||||
float safe_return_heading;
|
||||
float zone_in_x;
|
||||
float zone_in_y;
|
||||
float zone_in_z;
|
||||
float zone_in_heading;
|
||||
int has_zone_in;
|
||||
int zone;
|
||||
int version;
|
||||
int is_global;
|
||||
uint32_t start_time;
|
||||
int duration;
|
||||
int never_expires;
|
||||
};
|
||||
|
||||
static std::string SelectDynamicZoneJoinInstance()
|
||||
{
|
||||
return std::string(SQL(
|
||||
SELECT
|
||||
dynamic_zones.id,
|
||||
dynamic_zones.instance_id,
|
||||
dynamic_zones.type,
|
||||
dynamic_zones.compass_zone_id,
|
||||
dynamic_zones.compass_x,
|
||||
dynamic_zones.compass_y,
|
||||
dynamic_zones.compass_z,
|
||||
dynamic_zones.safe_return_zone_id,
|
||||
dynamic_zones.safe_return_x,
|
||||
dynamic_zones.safe_return_y,
|
||||
dynamic_zones.safe_return_z,
|
||||
dynamic_zones.safe_return_heading,
|
||||
dynamic_zones.zone_in_x,
|
||||
dynamic_zones.zone_in_y,
|
||||
dynamic_zones.zone_in_z,
|
||||
dynamic_zones.zone_in_heading,
|
||||
dynamic_zones.has_zone_in,
|
||||
instance_list.zone,
|
||||
instance_list.version,
|
||||
instance_list.is_global,
|
||||
instance_list.start_time,
|
||||
instance_list.duration,
|
||||
instance_list.never_expires
|
||||
FROM dynamic_zones
|
||||
INNER JOIN instance_list ON dynamic_zones.instance_id = instance_list.id
|
||||
));
|
||||
}
|
||||
|
||||
static DynamicZoneInstance FillWithInstanceFromRow(MySQLRequestRow& row)
|
||||
{
|
||||
DynamicZoneInstance entry{};
|
||||
|
||||
int col = 0;
|
||||
entry.id = strtoul(row[col++], nullptr, 10);
|
||||
entry.instance_id = strtol(row[col++], nullptr, 10);
|
||||
entry.type = strtol(row[col++], nullptr, 10);
|
||||
entry.compass_zone_id = strtol(row[col++], nullptr, 10);
|
||||
entry.compass_x = strtof(row[col++], nullptr);
|
||||
entry.compass_y = strtof(row[col++], nullptr);
|
||||
entry.compass_z = strtof(row[col++], nullptr);
|
||||
entry.safe_return_zone_id = strtol(row[col++], nullptr, 10);
|
||||
entry.safe_return_x = strtof(row[col++], nullptr);
|
||||
entry.safe_return_y = strtof(row[col++], nullptr);
|
||||
entry.safe_return_z = strtof(row[col++], nullptr);
|
||||
entry.safe_return_heading = strtof(row[col++], nullptr);
|
||||
entry.zone_in_x = strtof(row[col++], nullptr);
|
||||
entry.zone_in_y = strtof(row[col++], nullptr);
|
||||
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;
|
||||
// from instance_list
|
||||
entry.zone = strtol(row[col++], nullptr, 10);
|
||||
entry.version = strtol(row[col++], nullptr, 10);
|
||||
entry.is_global = strtol(row[col++], nullptr, 10);
|
||||
entry.start_time = strtoul(row[col++], nullptr, 10);
|
||||
entry.duration = strtol(row[col++], nullptr, 10);
|
||||
entry.never_expires = strtol(row[col++], nullptr, 10);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
static std::vector<DynamicZoneInstance> GetWithInstance(Database& db,
|
||||
const std::vector<uint32_t>& dynamic_zone_ids)
|
||||
{
|
||||
if (dynamic_zone_ids.empty())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<DynamicZoneInstance> all_entries;
|
||||
|
||||
auto results = db.QueryDatabase(fmt::format(
|
||||
"{} WHERE dynamic_zones.id IN ({}) ORDER BY dynamic_zones.id;",
|
||||
SelectDynamicZoneJoinInstance(),
|
||||
fmt::join(dynamic_zone_ids, ",")
|
||||
));
|
||||
|
||||
if (results.Success())
|
||||
{
|
||||
all_entries.reserve(results.RowCount());
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
{
|
||||
DynamicZoneInstance entry = FillWithInstanceFromRow(row);
|
||||
all_entries.emplace_back(std::move(entry));
|
||||
}
|
||||
}
|
||||
|
||||
return all_entries;
|
||||
}
|
||||
|
||||
static void UpdateCompass(Database& db, uint32_t dz_id, int zone_id, float x, float y, float z)
|
||||
{
|
||||
if (dz_id != 0)
|
||||
{
|
||||
std::string query = fmt::format(SQL(
|
||||
UPDATE {} SET
|
||||
compass_zone_id = {},
|
||||
compass_x = {},
|
||||
compass_y = {},
|
||||
compass_z = {}
|
||||
WHERE {} = {};
|
||||
), TableName(), zone_id, x, y, z, PrimaryKey(), dz_id);
|
||||
|
||||
db.QueryDatabase(query);
|
||||
}
|
||||
}
|
||||
|
||||
static void UpdateSafeReturn(Database& db, uint32_t dz_id, int zone_id, float x, float y, float z, float heading)
|
||||
{
|
||||
if (dz_id != 0)
|
||||
{
|
||||
std::string query = fmt::format(SQL(
|
||||
UPDATE {} SET
|
||||
safe_return_zone_id = {},
|
||||
safe_return_x = {},
|
||||
safe_return_y = {},
|
||||
safe_return_z = {},
|
||||
safe_return_heading = {}
|
||||
WHERE {} = {};
|
||||
), TableName(), zone_id, x, y, z, heading, PrimaryKey(), dz_id);
|
||||
|
||||
db.QueryDatabase(query);
|
||||
}
|
||||
}
|
||||
|
||||
static void UpdateZoneIn(Database& db, uint32_t dz_id, uint32_t zone_id, float x, float y, float z, float heading, bool has_zone_in)
|
||||
{
|
||||
if (dz_id != 0)
|
||||
{
|
||||
std::string query = fmt::format(SQL(
|
||||
UPDATE {} SET
|
||||
zone_in_x = {},
|
||||
zone_in_y = {},
|
||||
zone_in_z = {},
|
||||
zone_in_heading = {},
|
||||
has_zone_in = {}
|
||||
WHERE {} = {};
|
||||
), TableName(), x, y, z, heading, has_zone_in, PrimaryKey(), dz_id);
|
||||
|
||||
db.QueryDatabase(query);
|
||||
}
|
||||
}
|
||||
|
||||
struct DynamicZoneInstancePlayerCount
|
||||
{
|
||||
uint32_t id;
|
||||
int type;
|
||||
int instance;
|
||||
int zone;
|
||||
int version;
|
||||
uint32_t start_time;
|
||||
int duration;
|
||||
int player_count;
|
||||
};
|
||||
|
||||
static std::string SelectDynamicZoneInstancePlayerCount()
|
||||
{
|
||||
return std::string(SQL(
|
||||
SELECT
|
||||
dynamic_zones.id,
|
||||
dynamic_zones.type,
|
||||
instance_list.id,
|
||||
instance_list.zone,
|
||||
instance_list.version,
|
||||
instance_list.start_time,
|
||||
instance_list.duration,
|
||||
COUNT(instance_list_player.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
|
||||
GROUP BY instance_list.id
|
||||
ORDER BY dynamic_zones.id;
|
||||
));
|
||||
};
|
||||
|
||||
static std::vector<DynamicZoneInstancePlayerCount> AllDzInstancePlayerCounts(Database& db)
|
||||
{
|
||||
std::vector<DynamicZoneInstancePlayerCount> all_entries;
|
||||
|
||||
auto results = db.QueryDatabase(SelectDynamicZoneInstancePlayerCount());
|
||||
if (results.Success())
|
||||
{
|
||||
all_entries.reserve(results.RowCount());
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
{
|
||||
DynamicZoneInstancePlayerCount entry{};
|
||||
|
||||
int col = 0;
|
||||
entry.id = strtoul(row[col++], nullptr, 10);
|
||||
entry.type = strtol(row[col++], nullptr, 10);
|
||||
entry.instance = strtol(row[col++], nullptr, 10);
|
||||
entry.zone = strtol(row[col++], nullptr, 10);
|
||||
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);
|
||||
|
||||
all_entries.emplace_back(std::move(entry));
|
||||
}
|
||||
}
|
||||
return all_entries;
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_DYNAMIC_ZONES_REPOSITORY_H
|
||||
|
||||
@ -161,7 +161,7 @@
|
||||
#define ServerOP_ExpeditionExpireWarning 0x0416
|
||||
#define ServerOP_ExpeditionChooseNewLeader 0x0417
|
||||
|
||||
#define ServerOP_DzCharacterChange 0x0450
|
||||
#define ServerOP_DzAddRemoveCharacter 0x0450
|
||||
#define ServerOP_DzRemoveAllCharacters 0x0451
|
||||
#define ServerOP_DzSetSecondsRemaining 0x0452
|
||||
#define ServerOP_DzDurationUpdate 0x0453
|
||||
|
||||
@ -12,16 +12,21 @@ extern ZSList zoneserver_list;
|
||||
DynamicZone::DynamicZone(
|
||||
uint32_t id, uint32_t zone_id, uint32_t instance_id, uint32_t zone_version,
|
||||
uint32_t start_time, uint32_t duration, DynamicZoneType type
|
||||
) :
|
||||
m_id(id),
|
||||
m_instance_id(instance_id),
|
||||
m_zone_id(zone_id),
|
||||
m_zone_version(zone_version),
|
||||
m_start_time(std::chrono::system_clock::from_time_t(start_time)),
|
||||
m_duration(duration),
|
||||
m_type(type),
|
||||
m_expire_time(m_start_time + m_duration)
|
||||
)
|
||||
{
|
||||
m_id = id;
|
||||
m_instance_id = instance_id;
|
||||
m_zone_id = zone_id;
|
||||
m_zone_version = zone_version;
|
||||
m_start_time = std::chrono::system_clock::from_time_t(start_time);
|
||||
m_duration = std::chrono::seconds(duration);
|
||||
m_type = type;
|
||||
m_expire_time = m_start_time + m_duration;
|
||||
}
|
||||
|
||||
Database& DynamicZone::GetDatabase()
|
||||
{
|
||||
return database;
|
||||
}
|
||||
|
||||
DynamicZone* DynamicZone::FindDynamicZoneByID(uint32_t dz_id)
|
||||
@ -99,10 +104,27 @@ void DynamicZone::HandleZoneMessage(ServerPacket* pack)
|
||||
case ServerOP_DzSetSafeReturn:
|
||||
case ServerOP_DzSetZoneIn:
|
||||
{
|
||||
auto buf = reinterpret_cast<ServerDzLocation_Struct*>(pack->pBuffer);
|
||||
auto dz = DynamicZone::FindDynamicZoneByID(buf->dz_id);
|
||||
if (dz)
|
||||
{
|
||||
if (pack->opcode == ServerOP_DzSetCompass)
|
||||
{
|
||||
dz->SetCompass(buf->zone_id, buf->x, buf->y, buf->z, false);
|
||||
}
|
||||
else if (pack->opcode == ServerOP_DzSetSafeReturn)
|
||||
{
|
||||
dz->SetSafeReturn(buf->zone_id, buf->x, buf->y, buf->z, buf->heading, false);
|
||||
}
|
||||
else if (pack->opcode == ServerOP_DzSetZoneIn)
|
||||
{
|
||||
dz->SetZoneInLocation(buf->x, buf->y, buf->z, buf->heading, false);
|
||||
}
|
||||
}
|
||||
zoneserver_list.SendPacket(pack);
|
||||
break;
|
||||
}
|
||||
case ServerOP_DzCharacterChange:
|
||||
case ServerOP_DzAddRemoveCharacter:
|
||||
case ServerOP_DzRemoveAllCharacters:
|
||||
{
|
||||
auto buf = reinterpret_cast<ServerDzCharacter_Struct*>(pack->pBuffer);
|
||||
@ -125,3 +147,29 @@ void DynamicZone::HandleZoneMessage(ServerPacket* pack)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void DynamicZone::SendInstanceAddRemoveCharacter(uint32_t character_id, bool remove)
|
||||
{
|
||||
ZoneServer* instance_zs = zoneserver_list.FindByInstanceID(GetInstanceID());
|
||||
if (instance_zs)
|
||||
{
|
||||
auto pack = CreateServerAddRemoveCharacterPacket(character_id, remove);
|
||||
instance_zs->SendPacket(pack.get());
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicZone::SendInstanceRemoveAllCharacters()
|
||||
{
|
||||
ZoneServer* instance_zs = zoneserver_list.FindByInstanceID(GetInstanceID());
|
||||
if (instance_zs)
|
||||
{
|
||||
auto pack = CreateServerRemoveAllCharactersPacket();
|
||||
instance_zs->SendPacket(pack.get());
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicZone::SendGlobalLocationChange(uint16_t server_opcode, const DynamicZoneLocation& location)
|
||||
{
|
||||
auto pack = CreateServerDzLocationPacket(server_opcode, location);
|
||||
zoneserver_list.SendPacket(pack.get());
|
||||
}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
#ifndef WORLD_DYNAMIC_ZONE_H
|
||||
#define WORLD_DYNAMIC_ZONE_H
|
||||
|
||||
#include "../common/eq_constants.h"
|
||||
#include <chrono>
|
||||
#include "../common/dynamic_zone_base.h"
|
||||
|
||||
class Database;
|
||||
class ServerPacket;
|
||||
|
||||
enum class DynamicZoneStatus
|
||||
@ -14,9 +14,11 @@ enum class DynamicZoneStatus
|
||||
ExpiredEmpty,
|
||||
};
|
||||
|
||||
class DynamicZone
|
||||
class DynamicZone : public DynamicZoneBase
|
||||
{
|
||||
public:
|
||||
using DynamicZoneBase::DynamicZoneBase; // inherit base constructors
|
||||
|
||||
DynamicZone() = default;
|
||||
DynamicZone(uint32_t id, uint32_t zone_id, uint32_t instance_id, uint32_t zone_version,
|
||||
uint32_t start_time, uint32_t duration, DynamicZoneType type);
|
||||
@ -24,29 +26,20 @@ public:
|
||||
static DynamicZone* FindDynamicZoneByID(uint32_t dz_id);
|
||||
static void HandleZoneMessage(ServerPacket* pack);
|
||||
|
||||
uint32_t GetID() const { return m_id; }
|
||||
uint16_t GetInstanceID() const { return static_cast<uint16_t>(m_instance_id); }
|
||||
uint16_t GetZoneID() const { return static_cast<uint16_t>(m_zone_id); }
|
||||
uint32_t GetZoneVersion() const { return m_zone_version; }
|
||||
std::chrono::system_clock::duration GetRemainingDuration() const {
|
||||
return m_expire_time - std::chrono::system_clock::now(); }
|
||||
void SetSecondsRemaining(uint32_t seconds_remaining) override;
|
||||
|
||||
DynamicZoneStatus Process(bool force_expire);
|
||||
bool IsExpired() const { return m_expire_time < std::chrono::system_clock::now(); }
|
||||
void SetSecondsRemaining(uint32_t seconds_remaining);
|
||||
|
||||
protected:
|
||||
Database& GetDatabase() override;
|
||||
void SendInstanceAddRemoveCharacter(uint32_t character_id, bool remove) override;
|
||||
void SendInstanceRemoveAllCharacters() override;
|
||||
void SendGlobalLocationChange(uint16_t server_opcode, const DynamicZoneLocation& location) override;
|
||||
|
||||
private:
|
||||
void SendZonesDurationUpdate();
|
||||
|
||||
uint32_t m_id = 0;
|
||||
uint32_t m_instance_id = 0;
|
||||
uint32_t m_zone_id = 0;
|
||||
uint32_t m_zone_version = 0;
|
||||
bool m_is_pending_early_shutdown = false;
|
||||
DynamicZoneType m_type{ DynamicZoneType::None };
|
||||
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;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -142,7 +142,7 @@ void Expedition::CheckExpireWarning()
|
||||
if (m_warning_cooldown_timer.Check(false))
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
auto remaining = GetDynamicZone().GetRemainingDuration();
|
||||
auto remaining = GetDynamicZone().GetDurationRemaining();
|
||||
if ((remaining > 14min && remaining < 15min) ||
|
||||
(remaining > 4min && remaining < 5min) ||
|
||||
(remaining > 0min && remaining < 1min))
|
||||
|
||||
@ -1388,7 +1388,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
||||
ExpeditionMessage::HandleZoneMessage(pack);
|
||||
break;
|
||||
}
|
||||
case ServerOP_DzCharacterChange:
|
||||
case ServerOP_DzAddRemoveCharacter:
|
||||
case ServerOP_DzRemoveAllCharacters:
|
||||
case ServerOP_DzSetSecondsRemaining:
|
||||
case ServerOP_DzSetCompass:
|
||||
|
||||
@ -9595,7 +9595,7 @@ Expedition* Client::CreateExpedition(
|
||||
const std::string& zone_name, uint32 version, uint32 duration, const std::string& expedition_name,
|
||||
uint32 min_players, uint32 max_players, bool disable_messages)
|
||||
{
|
||||
DynamicZone dz_instance{ zone_name, version, duration, DynamicZoneType::Expedition };
|
||||
DynamicZone dz_instance{ ZoneID(zone_name), version, duration, DynamicZoneType::Expedition };
|
||||
ExpeditionRequest request{ expedition_name, min_players, max_players, disable_messages };
|
||||
return Expedition::TryCreate(this, dz_instance, request);
|
||||
}
|
||||
|
||||
@ -57,6 +57,7 @@
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "../common/profanity_manager.h"
|
||||
#include "../common/net/eqstream.h"
|
||||
#include "../common/repositories/dynamic_zones_repository.h"
|
||||
|
||||
#include "data_bucket.h"
|
||||
#include "command.h"
|
||||
@ -6960,58 +6961,36 @@ void command_dz(Client* c, const Seperator* sep)
|
||||
}
|
||||
else if (strcasecmp(sep->arg[1], "list") == 0)
|
||||
{
|
||||
std::string query = SQL(
|
||||
SELECT
|
||||
dynamic_zones.id,
|
||||
dynamic_zones.type,
|
||||
instance_list.id,
|
||||
instance_list.zone,
|
||||
instance_list.version,
|
||||
instance_list.start_time,
|
||||
instance_list.duration,
|
||||
COUNT(instance_list_player.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
|
||||
GROUP BY instance_list.id
|
||||
ORDER BY dynamic_zones.id;
|
||||
);
|
||||
auto dz_list = DynamicZonesRepository::AllDzInstancePlayerCounts(database);
|
||||
c->Message(Chat::White, fmt::format("Total Dynamic Zones: [{}]", dz_list.size()).c_str());
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (results.Success())
|
||||
auto now = std::chrono::system_clock::now();
|
||||
|
||||
for (const auto& dz : dz_list)
|
||||
{
|
||||
c->Message(Chat::White, fmt::format("Total Dynamic Zones: [{}]", results.RowCount()).c_str());
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
auto expire_time = std::chrono::system_clock::from_time_t(dz.start_time + dz.duration);
|
||||
auto remaining = std::chrono::duration_cast<std::chrono::seconds>(expire_time - now);
|
||||
auto seconds = std::max(0, static_cast<int>(remaining.count()));
|
||||
bool is_expired = now > expire_time;
|
||||
|
||||
if (!is_expired || strcasecmp(sep->arg[2], "all") == 0)
|
||||
{
|
||||
auto start_time = strtoul(row[5], nullptr, 10);
|
||||
auto duration = strtoul(row[6], nullptr, 10);
|
||||
auto expire_time = std::chrono::system_clock::from_time_t(start_time + duration);
|
||||
auto zone_saylink = is_expired ? "zone" : EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
fmt::format("#zoneinstance {}", dz.instance), false, "zone");
|
||||
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto remaining = std::chrono::duration_cast<std::chrono::seconds>(expire_time - now);
|
||||
auto seconds = std::max(0, static_cast<int>(remaining.count()));
|
||||
|
||||
bool is_expired = now > expire_time;
|
||||
if (!is_expired || strcasecmp(sep->arg[2], "all") == 0)
|
||||
{
|
||||
uint32_t instance_id = strtoul(row[2], nullptr, 10);
|
||||
auto zone_saylink = is_expired ? "zone" : EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
fmt::format("#zoneinstance {}", instance_id), false, "zone");
|
||||
|
||||
c->Message(Chat::White, fmt::format(
|
||||
"dz id: [{}] type: [{}] {}: [{}]:[{}]:[{}] members: [{}] remaining: [{:02}:{:02}:{:02}]",
|
||||
strtoul(row[0], nullptr, 10), // dynamic_zone_id
|
||||
strtoul(row[1], nullptr, 10), // dynamic_zone_type
|
||||
zone_saylink,
|
||||
strtoul(row[3], nullptr, 10), // instance_zone_id
|
||||
instance_id, // instance_id
|
||||
strtoul(row[4], nullptr, 10), // instance_zone_version
|
||||
strtoul(row[7], nullptr, 10), // instance member_count
|
||||
seconds / 3600, // hours
|
||||
(seconds / 60) % 60, // minutes
|
||||
seconds % 60 // seconds
|
||||
).c_str());
|
||||
}
|
||||
c->Message(Chat::White, fmt::format(
|
||||
"dz id: [{}] type: [{}] {}: [{}]:[{}]:[{}] members: [{}] remaining: [{:02}:{:02}:{:02}]",
|
||||
dz.id,
|
||||
dz.type,
|
||||
zone_saylink,
|
||||
dz.zone,
|
||||
dz.instance,
|
||||
dz.version,
|
||||
dz.player_count,
|
||||
seconds / 3600, // hours
|
||||
(seconds / 60) % 60, // minutes
|
||||
seconds % 60 // seconds
|
||||
).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,30 +22,35 @@
|
||||
#include "client.h"
|
||||
#include "expedition.h"
|
||||
#include "worldserver.h"
|
||||
#include "zonedb.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
|
||||
extern WorldServer worldserver;
|
||||
|
||||
DynamicZone::DynamicZone(
|
||||
uint32_t zone_id, uint32_t version, uint32_t duration, DynamicZoneType type
|
||||
) :
|
||||
m_zone_id(zone_id),
|
||||
m_version(version),
|
||||
m_duration(duration),
|
||||
m_type(type)
|
||||
{
|
||||
}
|
||||
// message string 8312 added in September 08 2020 Test patch (used by both dz and shared tasks)
|
||||
const char* const CREATE_NOT_ALL_ADDED = "Not all players in your {} were added to the {}. The {} can take a maximum of {} players, and your {} has {}.";
|
||||
|
||||
DynamicZone::DynamicZone(
|
||||
std::string zone_name, uint32_t version, uint32_t duration, DynamicZoneType type
|
||||
) :
|
||||
DynamicZone(ZoneID(zone_name), version, duration, type)
|
||||
uint32_t zone_id, uint32_t version, uint32_t duration, DynamicZoneType type)
|
||||
{
|
||||
if (!m_zone_id)
|
||||
{
|
||||
LogDynamicZones("Failed to get zone id for zone [{}]", zone_name);
|
||||
}
|
||||
m_zone_id = zone_id;
|
||||
m_zone_version = version;
|
||||
m_duration = std::chrono::seconds(duration);
|
||||
m_type = type;
|
||||
}
|
||||
|
||||
Database& DynamicZone::GetDatabase()
|
||||
{
|
||||
return database;
|
||||
}
|
||||
|
||||
uint16_t DynamicZone::GetCurrentInstanceID()
|
||||
{
|
||||
return zone ? static_cast<uint16_t>(zone->GetInstanceID()) : 0;
|
||||
}
|
||||
|
||||
uint16_t DynamicZone::GetCurrentZoneID()
|
||||
{
|
||||
return zone ? static_cast<uint16_t>(zone->GetZoneID()) : 0;
|
||||
}
|
||||
|
||||
DynamicZone* DynamicZone::FindDynamicZoneByID(uint32_t dz_id)
|
||||
@ -64,366 +69,43 @@ std::unordered_map<uint32_t, DynamicZone> DynamicZone::LoadMultipleDzFromDatabas
|
||||
{
|
||||
LogDynamicZonesDetail("Loading dynamic zone data for [{}] instances", dynamic_zone_ids.size());
|
||||
|
||||
std::string in_dynamic_zone_ids_query = fmt::format("{}", fmt::join(dynamic_zone_ids, ","));
|
||||
|
||||
std::unordered_map<uint32_t, DynamicZone> dynamic_zones;
|
||||
|
||||
if (!in_dynamic_zone_ids_query.empty())
|
||||
auto entries = DynamicZonesRepository::GetWithInstance(database, dynamic_zone_ids);
|
||||
for (auto& entry : entries)
|
||||
{
|
||||
std::string query = fmt::format(SQL(
|
||||
{} WHERE dynamic_zones.id IN ({});
|
||||
), DynamicZoneSelectQuery(), in_dynamic_zone_ids_query);
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (results.Success())
|
||||
{
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
{
|
||||
DynamicZone dz;
|
||||
dz.LoadDatabaseResult(row);
|
||||
dynamic_zones.emplace(dz.GetID(), dz);
|
||||
}
|
||||
}
|
||||
dynamic_zones.emplace(entry.id, std::move(entry));
|
||||
}
|
||||
|
||||
return dynamic_zones;
|
||||
}
|
||||
|
||||
uint32_t DynamicZone::Create()
|
||||
void DynamicZone::StartAllClientRemovalTimers()
|
||||
{
|
||||
if (m_id != 0)
|
||||
for (const auto& client_iter : entity_list.GetClientList())
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
if (GetInstanceID() == 0)
|
||||
{
|
||||
CreateInstance();
|
||||
}
|
||||
|
||||
m_id = SaveToDatabase();
|
||||
|
||||
return m_id;
|
||||
}
|
||||
|
||||
uint32_t DynamicZone::CreateInstance()
|
||||
{
|
||||
if (m_instance_id)
|
||||
{
|
||||
LogDynamicZones("CreateInstance failed, instance id [{}] already created", m_instance_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!m_zone_id)
|
||||
{
|
||||
LogDynamicZones("CreateInstance failed, invalid zone id [{}]", m_zone_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t instance_id = 0;
|
||||
if (!database.GetUnusedInstanceID(instance_id)) // todo: doesn't this race with insert?
|
||||
{
|
||||
LogDynamicZones("Failed to find unused instance id");
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_start_time = std::chrono::system_clock::now();
|
||||
auto start_time = std::chrono::system_clock::to_time_t(m_start_time);
|
||||
|
||||
std::string query = fmt::format(SQL(
|
||||
INSERT INTO instance_list
|
||||
(id, zone, version, start_time, duration)
|
||||
VALUES
|
||||
({}, {}, {}, {}, {})
|
||||
), instance_id, m_zone_id, m_version, start_time, m_duration.count());
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
{
|
||||
LogDynamicZones("Failed to create instance [{}] for Dynamic Zone [{}]", instance_id, m_zone_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_instance_id = instance_id;
|
||||
m_never_expires = false;
|
||||
m_expire_time = m_start_time + m_duration;
|
||||
|
||||
return m_instance_id;
|
||||
}
|
||||
|
||||
std::string DynamicZone::DynamicZoneSelectQuery()
|
||||
{
|
||||
return std::string(SQL(
|
||||
SELECT
|
||||
instance_list.id,
|
||||
instance_list.zone,
|
||||
instance_list.version,
|
||||
instance_list.start_time,
|
||||
instance_list.duration,
|
||||
instance_list.never_expires,
|
||||
dynamic_zones.id,
|
||||
dynamic_zones.type,
|
||||
dynamic_zones.compass_zone_id,
|
||||
dynamic_zones.compass_x,
|
||||
dynamic_zones.compass_y,
|
||||
dynamic_zones.compass_z,
|
||||
dynamic_zones.safe_return_zone_id,
|
||||
dynamic_zones.safe_return_x,
|
||||
dynamic_zones.safe_return_y,
|
||||
dynamic_zones.safe_return_z,
|
||||
dynamic_zones.safe_return_heading,
|
||||
dynamic_zones.zone_in_x,
|
||||
dynamic_zones.zone_in_y,
|
||||
dynamic_zones.zone_in_z,
|
||||
dynamic_zones.zone_in_heading,
|
||||
dynamic_zones.has_zone_in
|
||||
FROM dynamic_zones
|
||||
INNER JOIN instance_list ON dynamic_zones.instance_id = instance_list.id
|
||||
));
|
||||
}
|
||||
|
||||
void DynamicZone::LoadDatabaseResult(MySQLRequestRow& row)
|
||||
{
|
||||
m_instance_id = strtoul(row[0], nullptr, 10);
|
||||
m_zone_id = strtoul(row[1], nullptr, 10);
|
||||
m_version = strtoul(row[2], nullptr, 10);
|
||||
m_start_time = std::chrono::system_clock::from_time_t(strtoul(row[3], nullptr, 10));
|
||||
m_duration = std::chrono::seconds(strtoul(row[4], nullptr, 10));
|
||||
m_expire_time = m_start_time + m_duration;
|
||||
m_never_expires = (strtoul(row[5], nullptr, 10) != 0);
|
||||
m_id = strtoul(row[6], nullptr, 10);
|
||||
m_type = static_cast<DynamicZoneType>(strtoul(row[7], nullptr, 10));
|
||||
m_compass.zone_id = strtoul(row[8], nullptr, 10);
|
||||
m_compass.x = strtof(row[9], nullptr);
|
||||
m_compass.y = strtof(row[10], nullptr);
|
||||
m_compass.z = strtof(row[11], nullptr);
|
||||
m_safereturn.zone_id = strtoul(row[12], nullptr, 10);
|
||||
m_safereturn.x = strtof(row[13], nullptr);
|
||||
m_safereturn.y = strtof(row[14], nullptr);
|
||||
m_safereturn.z = strtof(row[15], nullptr);
|
||||
m_safereturn.heading = strtof(row[16], nullptr);
|
||||
m_zonein.x = strtof(row[17], nullptr);
|
||||
m_zonein.y = strtof(row[18], nullptr);
|
||||
m_zonein.z = strtof(row[19], nullptr);
|
||||
m_zonein.heading = strtof(row[20], nullptr);
|
||||
m_has_zonein = (strtoul(row[21], nullptr, 10) != 0);
|
||||
}
|
||||
|
||||
uint32_t DynamicZone::SaveToDatabase()
|
||||
{
|
||||
LogDynamicZonesDetail("Saving dz instance [{}] to database", m_instance_id);
|
||||
|
||||
if (m_instance_id != 0)
|
||||
{
|
||||
std::string query = fmt::format(SQL(
|
||||
INSERT INTO dynamic_zones
|
||||
(
|
||||
instance_id,
|
||||
type,
|
||||
compass_zone_id,
|
||||
compass_x,
|
||||
compass_y,
|
||||
compass_z,
|
||||
safe_return_zone_id,
|
||||
safe_return_x,
|
||||
safe_return_y,
|
||||
safe_return_z,
|
||||
safe_return_heading,
|
||||
zone_in_x,
|
||||
zone_in_y,
|
||||
zone_in_z,
|
||||
zone_in_heading,
|
||||
has_zone_in
|
||||
)
|
||||
VALUES
|
||||
({}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {});
|
||||
),
|
||||
m_instance_id,
|
||||
static_cast<uint8_t>(m_type),
|
||||
m_compass.zone_id,
|
||||
m_compass.x,
|
||||
m_compass.y,
|
||||
m_compass.z,
|
||||
m_safereturn.zone_id,
|
||||
m_safereturn.x,
|
||||
m_safereturn.y,
|
||||
m_safereturn.z,
|
||||
m_safereturn.heading,
|
||||
m_zonein.x,
|
||||
m_zonein.y,
|
||||
m_zonein.z,
|
||||
m_zonein.heading,
|
||||
m_has_zonein
|
||||
);
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (results.Success())
|
||||
if (client_iter.second)
|
||||
{
|
||||
return results.LastInsertedID();
|
||||
client_iter.second->SetDzRemovalTimer(true);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DynamicZone::SaveCompassToDatabase()
|
||||
void DynamicZone::SendInstanceRemoveAllCharacters()
|
||||
{
|
||||
LogDynamicZonesDetail(
|
||||
"Instance [{}] saving compass zone: [{}] xyz: ([{}], [{}], [{}])",
|
||||
m_instance_id, m_compass.zone_id, m_compass.x, m_compass.y, m_compass.z
|
||||
);
|
||||
|
||||
if (m_instance_id != 0)
|
||||
// just remove all clients in bulk instead of only characters assigned to the instance
|
||||
if (IsCurrentZoneDzInstance())
|
||||
{
|
||||
std::string query = fmt::format(SQL(
|
||||
UPDATE dynamic_zones SET
|
||||
compass_zone_id = {},
|
||||
compass_x = {},
|
||||
compass_y = {},
|
||||
compass_z = {}
|
||||
WHERE instance_id = {};
|
||||
),
|
||||
m_compass.zone_id,
|
||||
m_compass.x,
|
||||
m_compass.y,
|
||||
m_compass.z,
|
||||
m_instance_id
|
||||
);
|
||||
|
||||
database.QueryDatabase(query);
|
||||
DynamicZone::StartAllClientRemovalTimers();
|
||||
}
|
||||
else if (GetInstanceID() != 0)
|
||||
{
|
||||
auto pack = CreateServerRemoveAllCharactersPacket();
|
||||
worldserver.SendPacket(pack.get());
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicZone::SaveSafeReturnToDatabase()
|
||||
{
|
||||
LogDynamicZonesDetail(
|
||||
"Instance [{}] saving safereturn zone: [{}] xyzh: ([{}], [{}], [{}], [{}])",
|
||||
m_instance_id, m_safereturn.zone_id, m_safereturn.x, m_safereturn.y, m_safereturn.z, m_safereturn.heading
|
||||
);
|
||||
|
||||
if (m_instance_id != 0)
|
||||
{
|
||||
std::string query = fmt::format(SQL(
|
||||
UPDATE dynamic_zones SET
|
||||
safe_return_zone_id = {},
|
||||
safe_return_x = {},
|
||||
safe_return_y = {},
|
||||
safe_return_z = {},
|
||||
safe_return_heading = {}
|
||||
WHERE instance_id = {};
|
||||
),
|
||||
m_safereturn.zone_id,
|
||||
m_safereturn.x,
|
||||
m_safereturn.y,
|
||||
m_safereturn.z,
|
||||
m_safereturn.heading,
|
||||
m_instance_id
|
||||
);
|
||||
|
||||
database.QueryDatabase(query);
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicZone::SaveZoneInLocationToDatabase()
|
||||
{
|
||||
LogDynamicZonesDetail(
|
||||
"Instance [{}] saving zonein zone: [{}] xyzh: ([{}], [{}], [{}], [{}]) has: [{}]",
|
||||
m_instance_id, m_zone_id, m_zonein.x, m_zonein.y, m_zonein.z, m_zonein.heading, m_has_zonein
|
||||
);
|
||||
|
||||
if (m_instance_id != 0)
|
||||
{
|
||||
std::string query = fmt::format(SQL(
|
||||
UPDATE dynamic_zones SET
|
||||
zone_in_x = {},
|
||||
zone_in_y = {},
|
||||
zone_in_z = {},
|
||||
zone_in_heading = {},
|
||||
has_zone_in = {}
|
||||
WHERE instance_id = {};
|
||||
),
|
||||
m_zonein.x,
|
||||
m_zonein.y,
|
||||
m_zonein.z,
|
||||
m_zonein.heading,
|
||||
m_has_zonein,
|
||||
m_instance_id
|
||||
);
|
||||
|
||||
database.QueryDatabase(query);
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicZone::AddCharacter(uint32_t character_id)
|
||||
{
|
||||
database.AddClientToInstance(m_instance_id, character_id);
|
||||
SendInstanceCharacterChange(character_id, false); // stops client kick timer
|
||||
}
|
||||
|
||||
void DynamicZone::RemoveCharacter(uint32_t character_id)
|
||||
{
|
||||
database.RemoveClientFromInstance(m_instance_id, character_id);
|
||||
SendInstanceCharacterChange(character_id, true); // start client kick timer
|
||||
}
|
||||
|
||||
void DynamicZone::RemoveAllCharacters(bool enable_removal_timers)
|
||||
{
|
||||
if (GetInstanceID() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (enable_removal_timers)
|
||||
{
|
||||
// just remove all clients in bulk instead of only characters assigned to the instance
|
||||
if (IsCurrentZoneDzInstance())
|
||||
{
|
||||
for (const auto& client_iter : entity_list.GetClientList())
|
||||
{
|
||||
if (client_iter.second)
|
||||
{
|
||||
client_iter.second->SetDzRemovalTimer(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (GetInstanceID() != 0)
|
||||
{
|
||||
uint32_t packsize = sizeof(ServerDzCharacter_Struct);
|
||||
auto pack = std::make_unique<ServerPacket>(ServerOP_DzRemoveAllCharacters, packsize);
|
||||
auto packbuf = reinterpret_cast<ServerDzCharacter_Struct*>(pack->pBuffer);
|
||||
packbuf->zone_id = GetZoneID();
|
||||
packbuf->instance_id = GetInstanceID();
|
||||
packbuf->remove = true;
|
||||
packbuf->character_id = 0;
|
||||
worldserver.SendPacket(pack.get());
|
||||
}
|
||||
}
|
||||
|
||||
database.RemoveClientsFromInstance(GetInstanceID());
|
||||
}
|
||||
|
||||
void DynamicZone::SaveInstanceMembersToDatabase(const std::vector<uint32_t>& character_ids)
|
||||
{
|
||||
LogDynamicZonesDetail("Saving [{}] instance members to database", character_ids.size());
|
||||
|
||||
std::string insert_values;
|
||||
for (const auto& character_id : character_ids)
|
||||
{
|
||||
fmt::format_to(std::back_inserter(insert_values), "({}, {}),", m_instance_id, character_id);
|
||||
}
|
||||
|
||||
if (!insert_values.empty())
|
||||
{
|
||||
insert_values.pop_back(); // trailing comma
|
||||
|
||||
std::string query = fmt::format(SQL(
|
||||
REPLACE INTO instance_list_player (id, charid) VALUES {};
|
||||
), insert_values);
|
||||
|
||||
database.QueryDatabase(query);
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicZone::SendInstanceCharacterChange(uint32_t character_id, bool removed)
|
||||
void DynamicZone::SendInstanceAddRemoveCharacter(uint32_t character_id, bool removed)
|
||||
{
|
||||
// if removing, sets removal timer on client inside the instance
|
||||
if (IsCurrentZoneDzInstance())
|
||||
@ -436,97 +118,16 @@ void DynamicZone::SendInstanceCharacterChange(uint32_t character_id, bool remove
|
||||
}
|
||||
else if (GetInstanceID() != 0)
|
||||
{
|
||||
uint32_t packsize = sizeof(ServerDzCharacter_Struct);
|
||||
auto pack = std::make_unique<ServerPacket>(ServerOP_DzCharacterChange, packsize);
|
||||
auto packbuf = reinterpret_cast<ServerDzCharacter_Struct*>(pack->pBuffer);
|
||||
packbuf->zone_id = GetZoneID();
|
||||
packbuf->instance_id = GetInstanceID();
|
||||
packbuf->remove = removed;
|
||||
packbuf->character_id = character_id;
|
||||
auto pack = CreateServerAddRemoveCharacterPacket(character_id, removed);
|
||||
worldserver.SendPacket(pack.get());
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicZone::SetCompass(const DynamicZoneLocation& location, bool update_db)
|
||||
{
|
||||
m_compass = location;
|
||||
|
||||
if (m_on_compass_change)
|
||||
{
|
||||
m_on_compass_change();
|
||||
}
|
||||
|
||||
if (update_db)
|
||||
{
|
||||
SaveCompassToDatabase();
|
||||
SendWorldSetLocation(ServerOP_DzSetCompass, location);
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicZone::SetCompass(uint32_t zone_id, float x, float y, float z, bool update_db)
|
||||
{
|
||||
SetCompass({ zone_id, x, y, z, 0.0f }, update_db);
|
||||
}
|
||||
|
||||
void DynamicZone::SetSafeReturn(const DynamicZoneLocation& location, bool update_db)
|
||||
{
|
||||
m_safereturn = location;
|
||||
|
||||
if (update_db)
|
||||
{
|
||||
SaveSafeReturnToDatabase();
|
||||
SendWorldSetLocation(ServerOP_DzSetSafeReturn, location);
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicZone::SetSafeReturn(uint32_t zone_id, float x, float y, float z, float heading, bool update_db)
|
||||
{
|
||||
SetSafeReturn({ zone_id, x, y, z, heading }, update_db);
|
||||
}
|
||||
|
||||
void DynamicZone::SetZoneInLocation(const DynamicZoneLocation& location, bool update_db)
|
||||
{
|
||||
m_zonein = location;
|
||||
m_has_zonein = true;
|
||||
|
||||
if (update_db)
|
||||
{
|
||||
SaveZoneInLocationToDatabase();
|
||||
SendWorldSetLocation(ServerOP_DzSetZoneIn, location);
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicZone::SetZoneInLocation(float x, float y, float z, float heading, bool update_db)
|
||||
{
|
||||
SetZoneInLocation({ 0, x, y, z, heading }, update_db);
|
||||
}
|
||||
|
||||
bool DynamicZone::IsCurrentZoneDzInstance() const
|
||||
{
|
||||
return (zone && zone->GetInstanceID() != 0 && zone->GetInstanceID() == GetInstanceID());
|
||||
}
|
||||
|
||||
bool DynamicZone::IsInstanceID(uint32_t instance_id) const
|
||||
{
|
||||
return (GetInstanceID() != 0 && GetInstanceID() == instance_id);
|
||||
}
|
||||
|
||||
bool DynamicZone::IsSameDz(uint32_t zone_id, uint32_t instance_id) const
|
||||
{
|
||||
return zone_id == m_zone_id && instance_id == m_instance_id;
|
||||
}
|
||||
|
||||
uint32_t DynamicZone::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;
|
||||
}
|
||||
|
||||
void DynamicZone::SetSecondsRemaining(uint32_t seconds_remaining)
|
||||
{
|
||||
// async
|
||||
@ -553,19 +154,9 @@ void DynamicZone::SetUpdatedDuration(uint32_t new_duration)
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicZone::SendWorldSetLocation(uint16_t server_opcode, const DynamicZoneLocation& location)
|
||||
void DynamicZone::SendGlobalLocationChange(uint16_t server_opcode, const DynamicZoneLocation& location)
|
||||
{
|
||||
uint32_t pack_size = sizeof(ServerDzLocation_Struct);
|
||||
auto pack = std::make_unique<ServerPacket>(server_opcode, pack_size);
|
||||
auto buf = reinterpret_cast<ServerDzLocation_Struct*>(pack->pBuffer);
|
||||
buf->dz_id = GetID();
|
||||
buf->sender_zone_id = zone ? zone->GetZoneID() : 0;
|
||||
buf->sender_instance_id = zone ? zone->GetInstanceID() : 0;
|
||||
buf->zone_id = location.zone_id;
|
||||
buf->x = location.x;
|
||||
buf->y = location.y;
|
||||
buf->z = location.z;
|
||||
buf->heading = location.heading;
|
||||
auto pack = CreateServerDzLocationPacket(server_opcode, location);
|
||||
worldserver.SendPacket(pack.get());
|
||||
}
|
||||
|
||||
@ -573,7 +164,7 @@ void DynamicZone::HandleWorldMessage(ServerPacket* pack)
|
||||
{
|
||||
switch (pack->opcode)
|
||||
{
|
||||
case ServerOP_DzCharacterChange:
|
||||
case ServerOP_DzAddRemoveCharacter:
|
||||
{
|
||||
auto buf = reinterpret_cast<ServerDzCharacter_Struct*>(pack->pBuffer);
|
||||
Client* client = entity_list.GetClientByCharID(buf->character_id);
|
||||
@ -588,13 +179,7 @@ void DynamicZone::HandleWorldMessage(ServerPacket* pack)
|
||||
auto buf = reinterpret_cast<ServerDzCharacter_Struct*>(pack->pBuffer);
|
||||
if (buf->remove)
|
||||
{
|
||||
for (const auto& client_list_iter : entity_list.GetClientList())
|
||||
{
|
||||
if (client_list_iter.second)
|
||||
{
|
||||
client_list_iter.second->SetDzRemovalTimer(true);
|
||||
}
|
||||
}
|
||||
DynamicZone::StartAllClientRemovalTimers();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -636,3 +221,12 @@ void DynamicZone::HandleWorldMessage(ServerPacket* pack)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicZone::ProcessCompassChange(const DynamicZoneLocation& location)
|
||||
{
|
||||
DynamicZoneBase::ProcessCompassChange(location);
|
||||
if (m_on_compass_change)
|
||||
{
|
||||
m_on_compass_change();
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,106 +21,49 @@
|
||||
#ifndef DYNAMIC_ZONE_H
|
||||
#define DYNAMIC_ZONE_H
|
||||
|
||||
#include "../common/eq_constants.h"
|
||||
#include <chrono>
|
||||
#include "../common/dynamic_zone_base.h"
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
class MySQLRequestRow;
|
||||
class Database;
|
||||
class ServerPacket;
|
||||
|
||||
struct DynamicZoneLocation
|
||||
{
|
||||
uint32_t zone_id = 0;
|
||||
float x = 0.0f;
|
||||
float y = 0.0f;
|
||||
float z = 0.0f;
|
||||
float heading = 0.0f;
|
||||
extern const char* const CREATE_NOT_ALL_ADDED;
|
||||
|
||||
DynamicZoneLocation() = default;
|
||||
DynamicZoneLocation(uint32_t zone_id_, float x_, float y_, float z_, float heading_)
|
||||
: zone_id(zone_id_), x(x_), y(y_), z(z_), heading(heading_) {}
|
||||
};
|
||||
|
||||
class DynamicZone
|
||||
class DynamicZone : public DynamicZoneBase
|
||||
{
|
||||
public:
|
||||
using DynamicZoneBase::DynamicZoneBase; // inherit base constructors
|
||||
|
||||
DynamicZone() = default;
|
||||
DynamicZone(uint32_t zone_id, uint32_t version, uint32_t duration, DynamicZoneType type);
|
||||
DynamicZone(std::string zone_shortname, uint32_t version, uint32_t duration, DynamicZoneType type);
|
||||
DynamicZone(uint32_t dz_id) : m_id(dz_id) {}
|
||||
DynamicZone(DynamicZoneType type) : m_type(type) {}
|
||||
|
||||
static DynamicZone* FindDynamicZoneByID(uint32_t dz_id);
|
||||
static std::unordered_map<uint32_t, DynamicZone> LoadMultipleDzFromDatabase(
|
||||
const std::vector<uint32_t>& dynamic_zone_ids);
|
||||
static void HandleWorldMessage(ServerPacket* pack);
|
||||
|
||||
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 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_version; }
|
||||
const std::string& GetLeaderName() const { return m_leader_name; }
|
||||
const std::string& GetName() const { return m_name; }
|
||||
DynamicZoneType GetType() const { return m_type; }
|
||||
DynamicZoneLocation GetCompassLocation() const { return m_compass; }
|
||||
DynamicZoneLocation GetSafeReturnLocation() const { return m_safereturn; }
|
||||
DynamicZoneLocation GetZoneInLocation() const { return m_zonein; }
|
||||
void SetSecondsRemaining(uint32_t seconds_remaining) override;
|
||||
|
||||
void AddCharacter(uint32_t character_id);
|
||||
uint32_t Create();
|
||||
uint32_t CreateInstance();
|
||||
bool HasZoneInLocation() const { return m_has_zonein; }
|
||||
bool IsCurrentZoneDzInstance() const;
|
||||
bool IsInstanceID(uint32_t instance_id) const;
|
||||
bool IsValid() const { return m_instance_id != 0; }
|
||||
bool IsSameDz(uint32_t zone_id, uint32_t instance_id) const;
|
||||
void RegisterOnCompassChange(const std::function<void()>& on_change) { m_on_compass_change = on_change; }
|
||||
void RemoveAllCharacters(bool enable_removal_timers = true);
|
||||
void RemoveCharacter(uint32_t character_id);
|
||||
void SaveInstanceMembersToDatabase(const std::vector<uint32_t>& character_ids);
|
||||
void SendInstanceCharacterChange(uint32_t character_id, bool removed);
|
||||
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; }
|
||||
void SetName(const std::string& name) { m_name = name; }
|
||||
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 SetSecondsRemaining(uint32_t seconds_remaining);
|
||||
void SetZoneInLocation(const DynamicZoneLocation& location, bool update_db = false);
|
||||
void SetZoneInLocation(float x, float y, float z, float heading, bool update_db = false);
|
||||
void SetUpdatedDuration(uint32_t seconds);
|
||||
bool IsCurrentZoneDzInstance() const;
|
||||
void RegisterOnCompassChange(const std::function<void()>& on_change) { m_on_compass_change = on_change; }
|
||||
void SetUpdatedDuration(uint32_t seconds);
|
||||
|
||||
protected:
|
||||
uint16_t GetCurrentInstanceID() override;
|
||||
uint16_t GetCurrentZoneID() override;
|
||||
Database& GetDatabase() override;
|
||||
void ProcessCompassChange(const DynamicZoneLocation& location) override;
|
||||
void SendInstanceAddRemoveCharacter(uint32_t character_id, bool remove) override;
|
||||
void SendInstanceRemoveAllCharacters() override;
|
||||
void SendGlobalLocationChange(uint16_t server_opcode, const DynamicZoneLocation& location) override;
|
||||
|
||||
private:
|
||||
static std::string DynamicZoneSelectQuery();
|
||||
void LoadDatabaseResult(MySQLRequestRow& row);
|
||||
void SaveCompassToDatabase();
|
||||
void SaveSafeReturnToDatabase();
|
||||
void SaveZoneInLocationToDatabase();
|
||||
void SendWorldSetLocation(uint16_t server_opcode, const DynamicZoneLocation& location);
|
||||
uint32_t SaveToDatabase();
|
||||
static void StartAllClientRemovalTimers();
|
||||
|
||||
uint32_t m_id = 0;
|
||||
uint32_t m_zone_id = 0;
|
||||
uint32_t m_instance_id = 0;
|
||||
uint32_t m_version = 0;
|
||||
bool m_never_expires = false;
|
||||
bool m_has_zonein = false;
|
||||
std::string m_name;
|
||||
std::string m_leader_name;
|
||||
DynamicZoneType m_type{ DynamicZoneType::None };
|
||||
DynamicZoneLocation m_compass;
|
||||
DynamicZoneLocation m_safereturn;
|
||||
DynamicZoneLocation m_zonein;
|
||||
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::function<void()> m_on_compass_change;
|
||||
};
|
||||
|
||||
|
||||
@ -39,9 +39,6 @@ const char* const EXPEDITION_OTHER_BELONGS = "{} attempted to create an expedi
|
||||
// lockout warnings were added to live in March 11 2020 patch
|
||||
const char* const DZADD_INVITE_WARNING = "Warning! You will be given replay timers for the following events if you enter %s:";
|
||||
const char* const DZADD_INVITE_WARNING_TIMER = "%s - %sD:%sH:%sM";
|
||||
const char* const KICKPLAYERS_EVERYONE = "Everyone";
|
||||
// message string 8312 added in September 08 2020 Test patch (used by both dz and shared tasks)
|
||||
const char* const CREATE_NOT_ALL_ADDED = "Not all players in your {} were added to the {}. The {} can take a maximum of {} players, and your {} has {}.";
|
||||
// various expeditions re-use these strings when locking
|
||||
constexpr char LOCK_CLOSE[] = "Your expedition is nearing its close. You cannot bring any additional people into your expedition at this time.";
|
||||
constexpr char LOCK_BEGIN[] = "The trial has begun. You cannot bring any additional people into your expedition at this time.";
|
||||
@ -1107,7 +1104,7 @@ void Expedition::DzKickPlayers(Client* requester)
|
||||
}
|
||||
|
||||
RemoveAllMembers();
|
||||
requester->MessageString(Chat::Red, EXPEDITION_REMOVED, KICKPLAYERS_EVERYONE, m_expedition_name.c_str());
|
||||
requester->MessageString(Chat::Red, EXPEDITION_REMOVED, "Everyone", m_expedition_name.c_str());
|
||||
}
|
||||
|
||||
void Expedition::SetLocked(
|
||||
|
||||
@ -39,7 +39,6 @@ class ServerPacket;
|
||||
|
||||
extern const char* const DZ_YOU_NOT_ASSIGNED;
|
||||
extern const char* const EXPEDITION_OTHER_BELONGS;
|
||||
extern const char* const CREATE_NOT_ALL_ADDED;
|
||||
|
||||
enum class ExpeditionMemberStatus : uint8_t
|
||||
{
|
||||
|
||||
@ -2906,7 +2906,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
Expedition::HandleWorldMessage(pack);
|
||||
break;
|
||||
}
|
||||
case ServerOP_DzCharacterChange:
|
||||
case ServerOP_DzAddRemoveCharacter:
|
||||
case ServerOP_DzRemoveAllCharacters:
|
||||
case ServerOP_DzDurationUpdate:
|
||||
case ServerOP_DzSetCompass:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user