Add api to add lockout duration

Also supports reducing lockout duration

Add Expedition::AddLockoutDuration

Add Client::AddExpeditionLockoutDuration

Some expeditions require adding to existing lockout durations
during progression. These add the specified seconds to individual
member lockout timers instead of setting a static duration based on
internal expedition lockout like UpdateLockoutDuration.
This commit is contained in:
hg 2020-09-20 10:58:21 -04:00
parent 8e52dd0579
commit b377fd183a
15 changed files with 261 additions and 25 deletions

View File

@ -161,6 +161,7 @@
#define ServerOP_ExpeditionLockState 0x0411
#define ServerOP_ExpeditionMembersRemoved 0x0412
#define ServerOP_ExpeditionDzDuration 0x0413
#define ServerOP_ExpeditionLockoutDuration 0x0414
#define ServerOP_DzCharacterChange 0x0450
#define ServerOP_DzRemoveAllCharacters 0x0451
@ -2048,6 +2049,7 @@ struct ServerExpeditionLockout_Struct {
uint16 sender_instance_id;
uint8 remove;
uint8 members_only;
int seconds_adjust;
char event_name[256];
};

View File

@ -1364,6 +1364,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
}
case ServerOP_ExpeditionLeaderChanged:
case ServerOP_ExpeditionLockout:
case ServerOP_ExpeditionLockoutDuration:
case ServerOP_ExpeditionLockState:
case ServerOP_ExpeditionMemberStatus:
case ServerOP_ExpeditionReplayOnJoin:

View File

@ -9642,6 +9642,38 @@ void Client::AddNewExpeditionLockout(
AddExpeditionLockout(lockout, true);
}
void Client::AddExpeditionLockoutDuration(
const std::string& expedition_name, const std::string& event_name, int seconds,
const std::string& uuid, bool update_db)
{
auto it = std::find_if(m_expedition_lockouts.begin(), m_expedition_lockouts.end(),
[&](const ExpeditionLockoutTimer& lockout) {
return lockout.IsSameLockout(expedition_name, event_name);
});
if (it != m_expedition_lockouts.end())
{
it->AddLockoutTime(seconds);
if (!uuid.empty())
{
it->SetUUID(uuid);
}
if (update_db)
{
ExpeditionDatabase::InsertCharacterLockouts(CharacterID(), { *it }, true);
}
SendExpeditionLockoutTimers();
}
else if (seconds > 0) // missing lockouts inserted for reductions would be instantly expired
{
auto lockout = ExpeditionLockoutTimer::CreateLockout(expedition_name, event_name, seconds, uuid);
AddExpeditionLockout(lockout, update_db);
}
}
void Client::RemoveExpeditionLockout(
const std::string& expedition_name, const std::string& event_name, bool update_db, bool update_client)
{

View File

@ -1118,8 +1118,10 @@ public:
uint32_t string_id, const std::initializer_list<std::string>& arguments = {});
void AddExpeditionLockout(const ExpeditionLockoutTimer& lockout, bool update_db = false);
void AddNewExpeditionLockout(
const std::string& expedition_name, const std::string& event_name, uint32_t duration, std::string uuid = {});
void AddExpeditionLockoutDuration(const std::string& expedition_name,
const std::string& event_Name, int seconds, const std::string& uuid = {}, bool update_db = false);
void AddNewExpeditionLockout(const std::string& expedition_name,
const std::string& event_name, uint32_t duration, std::string uuid = {});
Expedition* CreateExpedition(DynamicZone& dz_instance, ExpeditionRequest& request);
Expedition* CreateExpedition(
const std::string& zone_name, uint32 version, uint32 duration, const std::string& expedition_name,

View File

@ -448,8 +448,7 @@ void Expedition::AddReplayLockout(uint32_t seconds)
void Expedition::AddLockout(const std::string& event_name, uint32_t seconds)
{
ExpeditionLockoutTimer lockout{m_uuid, m_expedition_name, event_name, 0, seconds};
lockout.Reset(); // sets expire time
auto lockout = ExpeditionLockoutTimer::CreateLockout(m_expedition_name, event_name, seconds, m_uuid);
AddLockout(lockout);
}
@ -465,6 +464,33 @@ void Expedition::AddLockout(const ExpeditionLockoutTimer& lockout, bool members_
SendWorldLockoutUpdate(lockout, false, members_only);
}
void Expedition::AddLockoutDuration(const std::string& event_name, int seconds, bool members_only)
{
// lockout timers use unsigned durations to define intent but we may need
// to insert a new lockout while still supporting timer reductions
auto lockout = ExpeditionLockoutTimer::CreateLockout(
m_expedition_name, event_name, std::max(0, seconds), m_uuid);
if (!members_only)
{
auto it = m_lockouts.find(event_name);
if (it != m_lockouts.end())
{
it->second.AddLockoutTime(seconds);
ExpeditionDatabase::InsertLockout(m_id, it->second); // replaces current one
}
else
{
ExpeditionDatabase::InsertLockout(m_id, lockout);
}
}
ExpeditionDatabase::AddLockoutDuration(m_members, lockout, seconds);
ProcessLockoutDuration(lockout, seconds, members_only);
SendWorldLockoutDuration(lockout, seconds, members_only);
}
void Expedition::UpdateLockoutDuration(
const std::string& event_name, uint32_t seconds, bool members_only)
{
@ -473,8 +499,7 @@ void Expedition::UpdateLockoutDuration(
if (it != m_lockouts.end())
{
uint64_t expire_time = it->second.GetStartTime() + seconds;
ExpeditionLockoutTimer lockout{m_uuid, m_expedition_name, event_name, expire_time, seconds};
AddLockout(lockout, members_only);
AddLockout({ m_uuid, m_expedition_name, event_name, expire_time, seconds }, members_only);
}
}
@ -1265,6 +1290,58 @@ void Expedition::ProcessMemberRemoved(const std::string& removed_char_name, uint
);
}
void Expedition::ProcessLockoutDuration(
const ExpeditionLockoutTimer& lockout, int seconds, bool members_only)
{
if (!members_only)
{
auto it = m_lockouts.find(lockout.GetEventName());
if (it != m_lockouts.end())
{
it->second.AddLockoutTime(seconds);
}
else
{
m_lockouts[lockout.GetEventName()] = lockout;
}
}
for (const auto& member : m_members)
{
Client* member_client = entity_list.GetClientByCharID(member.char_id);
if (member_client)
{
member_client->AddExpeditionLockoutDuration(m_expedition_name,
lockout.GetEventName(), seconds, m_uuid);
}
}
if (m_dynamiczone.IsCurrentZoneDzInstance())
{
AddLockoutDurationNonMembers(lockout, seconds);
}
}
void Expedition::AddLockoutDurationNonMembers(const ExpeditionLockoutTimer& lockout, int seconds)
{
std::vector<ExpeditionMember> non_members;
for (const auto& client_iter : entity_list.GetClientList())
{
Client* client = client_iter.second;
if (client && client->GetExpeditionID() != GetID())
{
non_members.emplace_back(client->CharacterID(), client->GetName());
client->AddExpeditionLockoutDuration(m_expedition_name,
lockout.GetEventName(), seconds, m_uuid);
}
}
if (!non_members.empty())
{
ExpeditionDatabase::AddLockoutDuration(non_members, lockout, seconds);
}
}
void Expedition::ProcessLockoutUpdate(
const ExpeditionLockoutTimer& lockout, bool remove, bool members_only)
{
@ -1301,22 +1378,27 @@ void Expedition::ProcessLockoutUpdate(
// members leave the expedition but haven't been kicked from zone yet
if (!remove && m_dynamiczone.IsCurrentZoneDzInstance())
{
std::vector<ExpeditionMember> non_members;
for (const auto& client_iter : entity_list.GetClientList())
{
Client* client = client_iter.second;
if (client && client->GetExpeditionID() != GetID())
{
non_members.emplace_back(client->CharacterID(), client->GetName());
client->AddExpeditionLockout(lockout);
}
}
AddLockoutNonMembers(lockout);
}
}
if (!non_members.empty())
void Expedition::AddLockoutNonMembers(const ExpeditionLockoutTimer& lockout)
{
std::vector<ExpeditionMember> non_members;
for (const auto& client_iter : entity_list.GetClientList())
{
Client* client = client_iter.second;
if (client && client->GetExpeditionID() != GetID())
{
ExpeditionDatabase::InsertMembersLockout(non_members, lockout);
non_members.emplace_back(client->CharacterID(), client->GetName());
client->AddExpeditionLockout(lockout);
}
}
if (!non_members.empty())
{
ExpeditionDatabase::InsertMembersLockout(non_members, lockout);
}
}
void Expedition::SendUpdatesToZoneMembers(bool clear, bool message_on_clear)
@ -1492,6 +1574,23 @@ void Expedition::SendWorldLeaderChanged()
worldserver.SendPacket(pack.get());
}
void Expedition::SendWorldLockoutDuration(
const ExpeditionLockoutTimer& lockout, int seconds, bool members_only)
{
uint32_t pack_size = sizeof(ServerExpeditionLockout_Struct);
auto pack = std::unique_ptr<ServerPacket>(new ServerPacket(ServerOP_ExpeditionLockoutDuration, pack_size));
auto buf = reinterpret_cast<ServerExpeditionLockout_Struct*>(pack->pBuffer);
buf->expedition_id = GetID();
buf->expire_time = lockout.GetExpireTime();
buf->duration = lockout.GetDuration();
buf->sender_zone_id = zone ? zone->GetZoneID() : 0;
buf->sender_instance_id = zone ? zone->GetInstanceID() : 0;
buf->members_only = members_only;
buf->seconds_adjust = seconds;
strn0cpy(buf->event_name, lockout.GetEventName().c_str(), sizeof(buf->event_name));
worldserver.SendPacket(pack.get());
}
void Expedition::SendWorldLockoutUpdate(
const ExpeditionLockoutTimer& lockout, bool remove, bool members_only)
{
@ -1766,6 +1865,7 @@ void Expedition::HandleWorldMessage(ServerPacket* pack)
break;
}
case ServerOP_ExpeditionLockout:
case ServerOP_ExpeditionLockoutDuration:
{
auto buf = reinterpret_cast<ServerExpeditionLockout_Struct*>(pack->pBuffer);
if (zone && !zone->IsZone(buf->sender_zone_id, buf->sender_instance_id))
@ -1773,10 +1873,17 @@ void Expedition::HandleWorldMessage(ServerPacket* pack)
auto expedition = Expedition::FindCachedExpeditionByID(buf->expedition_id);
if (expedition)
{
ExpeditionLockoutTimer lockout{
expedition->GetUUID(), expedition->GetName(), buf->event_name, buf->expire_time, buf->duration
};
expedition->ProcessLockoutUpdate(lockout, buf->remove, buf->members_only);
ExpeditionLockoutTimer lockout{ expedition->GetUUID(), expedition->GetName(),
buf->event_name, buf->expire_time, buf->duration };
if (pack->opcode == ServerOP_ExpeditionLockout)
{
expedition->ProcessLockoutUpdate(lockout, buf->remove, buf->members_only);
}
else if (pack->opcode == ServerOP_ExpeditionLockoutDuration)
{
expedition->ProcessLockoutDuration(lockout, buf->seconds_adjust, buf->members_only);
}
}
}
break;

View File

@ -126,6 +126,7 @@ public:
bool update_db = false, uint32_t msg_color = Chat::Yellow);
void AddLockout(const std::string& event_name, uint32_t seconds);
void AddLockoutDuration(const std::string& event_name, int seconds, bool members_only = true);
void AddReplayLockout(uint32_t seconds);
bool HasLockout(const std::string& event_name);
bool HasReplayLockout();
@ -168,11 +169,14 @@ private:
static void SendWorldCharacterLockout(uint32_t character_id, const ExpeditionLockoutTimer& lockout, bool remove);
void AddLockout(const ExpeditionLockoutTimer& lockout, bool members_only = false);
void AddLockoutDurationNonMembers(const ExpeditionLockoutTimer& lockout, int seconds);
void AddLockoutNonMembers(const ExpeditionLockoutTimer& lockout);
void AddInternalMember(const std::string& char_name, uint32_t char_id, ExpeditionMemberStatus status);
bool ChooseNewLeader();
bool ConfirmLeaderCommand(Client* requester);
bool ProcessAddConflicts(Client* leader_client, Client* add_client, bool swapping);
void ProcessLeaderChanged(uint32_t new_leader_id, const std::string& new_leader_name);
void ProcessLockoutDuration(const ExpeditionLockoutTimer& lockout, int seconds, bool members_only = false);
void ProcessLockoutUpdate(const ExpeditionLockoutTimer& lockout, bool remove, bool members_only = false);
void ProcessMakeLeader(Client* old_leader, Client* new_leader, const std::string& new_leader_name, bool is_online);
void ProcessMemberAdded(const std::string& added_char_name, uint32_t added_char_id);
@ -189,7 +193,10 @@ private:
void SendWorldAddPlayerInvite(const std::string& inviter_name, const std::string& swap_remove_name,
const std::string& add_name, bool pending = false);
void SendWorldLeaderChanged();
void SendWorldLockoutUpdate(const ExpeditionLockoutTimer& lockout, bool remove, bool members_only = false);
void SendWorldLockoutDuration(
const ExpeditionLockoutTimer& lockout, int seconds, bool members_only = false);
void SendWorldLockoutUpdate(
const ExpeditionLockoutTimer& lockout, bool remove, bool members_only = false);
void SendWorldMakeLeaderRequest(const std::string& requester_name, const std::string& new_leader_name);
void SendWorldMemberChanged(const std::string& char_name, uint32_t char_id, bool remove);
void SendWorldMemberStatus(uint32_t character_id, ExpeditionMemberStatus status);

View File

@ -711,3 +711,42 @@ void ExpeditionDatabase::UpdateReplayLockoutOnJoin(uint32_t expedition_id, bool
database.QueryDatabase(query);
}
void ExpeditionDatabase::AddLockoutDuration(const std::vector<ExpeditionMember>& members,
const ExpeditionLockoutTimer& lockout, int seconds)
{
LogExpeditionsDetail(
"Adding duration [{}] seconds to members lockouts [{}]:[{}]",
seconds, lockout.GetExpeditionName(), lockout.GetEventName());
std::string insert_values;
for (const auto& member : members)
{
fmt::format_to(std::back_inserter(insert_values),
"({}, FROM_UNIXTIME({}), {}, '{}', '{}', '{}'),",
member.char_id,
lockout.GetExpireTime(),
lockout.GetDuration(),
lockout.GetExpeditionUUID(),
EscapeString(lockout.GetExpeditionName()),
EscapeString(lockout.GetEventName())
);
}
if (!insert_values.empty())
{
insert_values.pop_back(); // trailing comma
auto query = fmt::format(SQL(
INSERT INTO expedition_character_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 = DATE_ADD(expire_time, INTERVAL {} SECOND),
duration = GREATEST(0, CAST(duration AS SIGNED) + {});
), insert_values, seconds, seconds);
database.QueryDatabase(query);
}
}

View File

@ -44,7 +44,8 @@ namespace ExpeditionDatabase
MySQLRequestResult LoadMembersForCreateRequest(
const std::vector<std::string>& character_names, const std::string& expedition_name);
std::vector<ExpeditionLockoutTimer> LoadCharacterLockouts(uint32_t character_id);
std::vector<ExpeditionLockoutTimer> LoadCharacterLockouts(uint32_t character_id, const std::string& expedition_name);
std::vector<ExpeditionLockoutTimer> LoadCharacterLockouts(uint32_t character_id,
const std::string& expedition_name);
std::unordered_map<uint32_t, std::unordered_map<std::string, ExpeditionLockoutTimer>>
LoadMultipleExpeditionLockouts(const std::vector<uint32_t>& expedition_ids);
void DeleteAllMembers(uint32_t expedition_id);
@ -60,6 +61,9 @@ namespace ExpeditionDatabase
void DeleteAllMembersPendingLockouts(const std::vector<ExpeditionMember>& members);
uint32_t GetExpeditionIDFromCharacterID(uint32_t character_id);
ExpeditionMember GetExpeditionLeader(uint32_t expedition_id);
std::pair<std::vector<ExpeditionLockoutTimer>, std::vector<uint32_t>> GetMembersLockout(
const std::vector<ExpeditionMember>& members, const std::string& expedition_name,
const std::string& event_name);
void InsertCharacterLockouts(
uint32_t character_id, const std::vector<ExpeditionLockoutTimer>& lockouts,
bool replace_timer, bool is_pending = false);
@ -71,6 +75,8 @@ namespace ExpeditionDatabase
void UpdateLeaderID(uint32_t expedition_id, uint32_t leader_id);
void UpdateLockState(uint32_t expedition_id, bool is_locked);
void UpdateReplayLockoutOnJoin(uint32_t expedition_id, bool add_on_join);
void AddLockoutDuration(const std::vector<ExpeditionMember>& members,
const ExpeditionLockoutTimer& lockout, int seconds);
};
namespace LoadExpeditionColumns

View File

@ -85,3 +85,12 @@ bool ExpeditionLockoutTimer::IsSameLockout(
{
return GetExpeditionName() == expedition_name && GetEventName() == event_name;
}
void ExpeditionLockoutTimer::AddLockoutTime(int seconds)
{
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;
}

View File

@ -45,6 +45,7 @@ public:
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); }
@ -59,6 +60,7 @@ public:
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 SetUUID(const std::string& uuid) { m_expedition_uuid = uuid; }
private:
bool m_is_replay_timer = false;

View File

@ -1802,6 +1802,16 @@ void Lua_Client::AddExpeditionLockout(std::string expedition_name, std::string e
self->AddNewExpeditionLockout(expedition_name, event_name, seconds, uuid);
}
void Lua_Client::AddExpeditionLockoutDuration(std::string expedition_name, std::string event_name, int seconds) {
Lua_Safe_Call_Void();
self->AddExpeditionLockoutDuration(expedition_name, event_name, seconds, {}, true);
}
void Lua_Client::AddExpeditionLockoutDuration(std::string expedition_name, std::string event_name, int seconds, std::string uuid) {
Lua_Safe_Call_Void();
self->AddExpeditionLockoutDuration(expedition_name, event_name, seconds, uuid, true);
}
void Lua_Client::RemoveAllExpeditionLockouts() {
Lua_Safe_Call_Void();
self->RemoveAllExpeditionLockouts({}, true);
@ -2148,6 +2158,8 @@ luabind::scope lua_register_client() {
.def("GetLockoutExpeditionUUID", (std::string(Lua_Client::*)(std::string, std::string))&Lua_Client::GetLockoutExpeditionUUID)
.def("AddExpeditionLockout", (void(Lua_Client::*)(std::string, std::string, uint32))&Lua_Client::AddExpeditionLockout)
.def("AddExpeditionLockout", (void(Lua_Client::*)(std::string, std::string, uint32, std::string))&Lua_Client::AddExpeditionLockout)
.def("AddExpeditionLockoutDuration", (void(Lua_Client::*)(std::string, std::string, int))&Lua_Client::AddExpeditionLockoutDuration)
.def("AddExpeditionLockoutDuration", (void(Lua_Client::*)(std::string, std::string, int, std::string))&Lua_Client::AddExpeditionLockoutDuration)
.def("RemoveAllExpeditionLockouts", (void(Lua_Client::*)(void))&Lua_Client::RemoveAllExpeditionLockouts)
.def("RemoveAllExpeditionLockouts", (void(Lua_Client::*)(std::string))&Lua_Client::RemoveAllExpeditionLockouts)
.def("RemoveExpeditionLockout", (void(Lua_Client::*)(std::string, std::string))&Lua_Client::RemoveExpeditionLockout)

View File

@ -348,6 +348,8 @@ public:
std::string GetLockoutExpeditionUUID(std::string expedition_name, std::string event_name);
void AddExpeditionLockout(std::string expedition_name, std::string event_name, uint32 seconds);
void AddExpeditionLockout(std::string expedition_name, std::string event_name, uint32 seconds, std::string uuid);
void AddExpeditionLockoutDuration(std::string expedition_name, std::string event_name, int seconds);
void AddExpeditionLockoutDuration(std::string expedition_name, std::string event_name, int seconds, std::string uuid);
void RemoveAllExpeditionLockouts();
void RemoveAllExpeditionLockouts(std::string expedition_name);
void RemoveExpeditionLockout(std::string expedition_name, std::string event_name);

View File

@ -31,6 +31,16 @@ void Lua_Expedition::AddLockout(std::string event_name, uint32_t seconds) {
self->AddLockout(event_name, seconds);
}
void Lua_Expedition::AddLockoutDuration(std::string event_name, int seconds) {
Lua_Safe_Call_Void();
self->AddLockoutDuration(event_name, seconds);
}
void Lua_Expedition::AddLockoutDuration(std::string event_name, int seconds, bool members_only) {
Lua_Safe_Call_Void();
self->AddLockoutDuration(event_name, seconds, members_only);
}
void Lua_Expedition::AddReplayLockout(uint32_t seconds) {
Lua_Safe_Call_Void();
self->AddReplayLockout(seconds);
@ -211,6 +221,8 @@ luabind::scope lua_register_expedition() {
.property("null", &Lua_Expedition::Null)
.property("valid", &Lua_Expedition::Valid)
.def("AddLockout", (void(Lua_Expedition::*)(std::string, uint32_t))&Lua_Expedition::AddLockout)
.def("AddLockoutDuration", (void(Lua_Expedition::*)(std::string, int))&Lua_Expedition::AddLockoutDuration)
.def("AddLockoutDuration", (void(Lua_Expedition::*)(std::string, int, bool))&Lua_Expedition::AddLockoutDuration)
.def("AddReplayLockout", (void(Lua_Expedition::*)(uint32_t))&Lua_Expedition::AddReplayLockout)
.def("GetID", (uint32_t(Lua_Expedition::*)(void))&Lua_Expedition::GetID)
.def("GetInstanceID", (int(Lua_Expedition::*)(void))&Lua_Expedition::GetInstanceID)

View File

@ -54,6 +54,8 @@ public:
}
void AddLockout(std::string event_name, uint32_t seconds);
void AddLockoutDuration(std::string event_name, int seconds);
void AddLockoutDuration(std::string event_name, int seconds, bool members_only);
void AddReplayLockout(uint32_t seconds);
uint32_t GetID();
int GetInstanceID();

View File

@ -2894,6 +2894,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
case ServerOP_ExpeditionDeleted:
case ServerOP_ExpeditionLeaderChanged:
case ServerOP_ExpeditionLockout:
case ServerOP_ExpeditionLockoutDuration:
case ServerOP_ExpeditionLockState:
case ServerOP_ExpeditionMemberChange:
case ServerOP_ExpeditionMemberSwap:
@ -3302,4 +3303,4 @@ void WorldServer::OnKeepAlive(EQ::Timer *t)
{
ServerPacket pack(ServerOP_KeepAlive, 0);
SendPacket(&pack);
}
}