[Shared Tasks] Enforce task reqs on player removal (#2342)

This verifies a shared task's minimum players requirement is still met
when a member is removed and schedules it for termination if not
This commit is contained in:
hg
2022-07-30 21:49:57 -04:00
committed by GitHub
parent d243cbf8a3
commit 1351f147f4
6 changed files with 71 additions and 1 deletions
+1
View File
@@ -427,6 +427,7 @@ int main(int argc, char **argv)
launcher_list.Process();
LFPGroupList.Process();
adventure_manager.Process();
shared_task_manager.Process();
dynamic_zone_manager.Process();
if (InterserverTimer.Check()) {
+57
View File
@@ -6,6 +6,7 @@
#include "zonelist.h"
#include "zoneserver.h"
#include "shared_task_world_messaging.h"
#include "../common/rulesys.h"
#include "../common/repositories/character_data_repository.h"
#include "../common/repositories/character_task_timers_repository.h"
#include "../common/repositories/shared_task_members_repository.h"
@@ -20,6 +21,11 @@
extern ClientList client_list;
extern ZSList zoneserver_list;
SharedTaskManager::SharedTaskManager()
: m_process_timer{ static_cast<uint32_t>(RuleI(TaskSystem, SharedTasksWorldProcessRate)) }
{
}
SharedTaskManager *SharedTaskManager::SetDatabase(Database *db)
{
SharedTaskManager::m_database = db;
@@ -196,6 +202,13 @@ void SharedTaskManager::RemoveMember(SharedTask* s, const SharedTaskMember& memb
if (member.is_leader) {
ChooseNewLeader(s);
}
// todo: filter requirements
if (s->GetMembers().size() < s->GetTaskData().min_players)
{
SendMembersMessageID(s, Chat::Red, TaskStr::MIN_PLAYERS);
StartTerminateTimer(s);
}
}
void SharedTaskManager::RemoveEveryoneFromSharedTask(SharedTask *t, uint32 requested_character_id)
@@ -226,6 +239,20 @@ void SharedTaskManager::RemoveEveryoneFromSharedTask(SharedTask *t, uint32 reque
PrintSharedTaskState();
}
void SharedTaskManager::Terminate(SharedTask* s)
{
LogTasksDetail("[Process] Terminating shared task [{}]", s->GetDbSharedTask().id);
for (const auto& member : s->GetMembers())
{
SendRemovePlayerFromSharedTaskPacket(member.character_id, s->GetTaskData().id, true);
client_list.SendCharacterMessageID(member.character_id, Chat::Yellow, TaskStr::HAS_ENDED, {s->GetTaskData().title});
}
RemoveAllMembersFromDynamicZones(s);
DeleteSharedTask(s->GetDbSharedTask().id);
}
void SharedTaskManager::DeleteSharedTask(int64 shared_task_id)
{
LogTasksDetail(
@@ -995,6 +1022,12 @@ void SharedTaskManager::AddPlayerByCharacterIdAndName(
SendSharedTaskMemberList(character_id, s->GetMembers()); // new member gets full member list
s->AddCharacterToMemberHistory(character_id);
// min players should be the only thing to check, other failed reqs prevent player add
if (s->GetMembers().size() >= s->GetTaskData().min_players)
{
s->terminate_timer.Disable();
}
// add to dzs tied to shared task
for (const auto &dz_id : s->dynamic_zone_ids) {
auto dz = DynamicZone::FindDynamicZoneByID(dz_id);
@@ -1339,6 +1372,7 @@ bool SharedTaskManager::CanAddPlayer(SharedTask *s, uint32_t character_id, std::
player_name = cle->name();
// check if player is already in a shared task
// todo: do a memory search instead of query here
auto shared_task_members = SharedTaskMembersRepository::GetWhere(
*m_database,
fmt::format("character_id = {} LIMIT 1", character_id)
@@ -1399,6 +1433,7 @@ bool SharedTaskManager::CanAddPlayer(SharedTask *s, uint32_t character_id, std::
}
// check if task would exceed max level spread
// todo: cache low/high levels on SharedTask to avoid query for offline members (also usable by RemoveMember)
if (s->GetTaskData().level_spread > 0) {
auto characters = CharacterDataRepository::GetWhere(
*m_database,
@@ -1703,3 +1738,25 @@ void SharedTaskManager::HandleCompletedTask(SharedTask* s)
AddReplayTimers(s);
}
void SharedTaskManager::StartTerminateTimer(SharedTask* s)
{
s->terminate_timer.Start(120000); // 2min
SendMembersMessageID(s, Chat::Red, TaskStr::REQS_TWO_MIN);
}
void SharedTaskManager::Process()
{
if (!m_process_timer.Check())
{
return;
}
for (auto& shared_task : m_shared_tasks)
{
if (shared_task.terminate_timer.Check())
{
Terminate(&shared_task);
}
}
}
+8
View File
@@ -3,6 +3,7 @@
#include "../common/database.h"
#include "../common/shared_tasks.h"
#include "../common/timer.h"
#include "../common/repositories/character_task_timers_repository.h"
class DynamicZone;
@@ -20,6 +21,8 @@ struct SharedTaskActiveInvitation {
class SharedTaskManager {
public:
SharedTaskManager();
SharedTaskManager *SetDatabase(Database *db);
SharedTaskManager *SetContentDatabase(Database *db);
@@ -65,6 +68,7 @@ public:
);
void RemovePlayerFromSharedTask(SharedTask *s, uint32 character_id);
void PrintSharedTaskState();
void Process();
void RemoveMember(SharedTask* s, const SharedTaskMember& member, bool remove_from_db);
void RemoveEveryoneFromSharedTask(SharedTask *s, uint32 requested_character_id);
@@ -108,6 +112,8 @@ protected:
// store a reference of active invitations that have been sent to players
std::vector<SharedTaskActiveInvitation> m_active_invitations{};
Timer m_process_timer;
std::vector<CharacterTaskTimersRepository::CharacterTaskTimers> GetCharacterTimers(
const std::vector<uint32_t>& character_ids, const TasksRepository::Tasks& task);
@@ -124,6 +130,8 @@ protected:
void SendSharedTaskInvitePacket(SharedTask *s, int64 invited_character_id);
void RecordSharedTaskCompletion(SharedTask *s);
void RemoveAllMembersFromDynamicZones(SharedTask *s);
void StartTerminateTimer(SharedTask* s);
void Terminate(SharedTask* s);
// memory search
std::vector<SharedTaskMember> FindCharactersInSharedTasks(const std::vector<uint32_t> &find_characters);