mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-13 14:41:28 +00:00
[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:
parent
d243cbf8a3
commit
1351f147f4
@ -555,6 +555,7 @@ RULE_BOOL(TaskSystem, RecordCompletedOptionalActivities, false, "Record complete
|
|||||||
RULE_BOOL(TaskSystem, KeepOneRecordPerCompletedTask, true, "Keep only one record per completed task")
|
RULE_BOOL(TaskSystem, KeepOneRecordPerCompletedTask, true, "Keep only one record per completed task")
|
||||||
RULE_BOOL(TaskSystem, EnableTaskProximity, true, "Enable task proximity system")
|
RULE_BOOL(TaskSystem, EnableTaskProximity, true, "Enable task proximity system")
|
||||||
RULE_INT(TaskSystem, RequestCooldownTimerSeconds, 15, "Seconds between allowing characters to request tasks (live-like default: 15 seconds)")
|
RULE_INT(TaskSystem, RequestCooldownTimerSeconds, 15, "Seconds between allowing characters to request tasks (live-like default: 15 seconds)")
|
||||||
|
RULE_INT(TaskSystem, SharedTasksWorldProcessRate, 6000, "Timer interval (milliseconds) that shared tasks are processed in world")
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Range)
|
RULE_CATEGORY(Range)
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
#define EQEMU_SHARED_TASKS_H
|
#define EQEMU_SHARED_TASKS_H
|
||||||
|
|
||||||
#include "database.h"
|
#include "database.h"
|
||||||
|
#include "timer.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "repositories/character_data_repository.h"
|
#include "repositories/character_data_repository.h"
|
||||||
#include "repositories/tasks_repository.h"
|
#include "repositories/tasks_repository.h"
|
||||||
@ -203,6 +204,8 @@ public:
|
|||||||
std::vector<uint32_t> member_id_history; // past and present members for replay timers
|
std::vector<uint32_t> member_id_history; // past and present members for replay timers
|
||||||
std::vector<uint32_t> dynamic_zone_ids;
|
std::vector<uint32_t> dynamic_zone_ids;
|
||||||
|
|
||||||
|
Timer terminate_timer;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SharedTasksRepository::SharedTasks m_db_shared_task;
|
SharedTasksRepository::SharedTasks m_db_shared_task;
|
||||||
|
|
||||||
|
|||||||
@ -389,7 +389,7 @@ namespace TaskStr {
|
|||||||
constexpr uint16 NO_LONGER_MEMBER = 8942; // You are no longer a member of the shared task.
|
constexpr uint16 NO_LONGER_MEMBER = 8942; // You are no longer a member of the shared task.
|
||||||
constexpr uint16 YOU_MAY_NOT_REQUEST_EXPANSION = 8943; // You may not request this shared task because you do not have the required expansion.
|
constexpr uint16 YOU_MAY_NOT_REQUEST_EXPANSION = 8943; // You may not request this shared task because you do not have the required expansion.
|
||||||
constexpr uint16 PLAYER_MAY_NOT_REQUEST_EXPANSION = 8944; // You may not request this shared task because %1 does not have the required expansion.
|
constexpr uint16 PLAYER_MAY_NOT_REQUEST_EXPANSION = 8944; // You may not request this shared task because %1 does not have the required expansion.
|
||||||
constexpr uint16 TWO_MIN_REQ_TASK_TERMINATED = 8945; // If your party does not meet the requirements in two minutes, the shared task will be terminated.
|
constexpr uint16 REQS_TWO_MIN = 8945; // If your party does not meet the requirements in two minutes, the shared task will be terminated.
|
||||||
constexpr uint16 YOU_REPLAY_TIMER = 8946; // You may not request this shared task because you must wait %1d:%2h:%3m before you can do another task of this type.
|
constexpr uint16 YOU_REPLAY_TIMER = 8946; // You may not request this shared task because you must wait %1d:%2h:%3m before you can do another task of this type.
|
||||||
constexpr uint16 PLAYER_REPLAY_TIMER = 8947; // You may not request this shared task because %1 must wait %2d:%3h:%4m before they can do another task of this type.
|
constexpr uint16 PLAYER_REPLAY_TIMER = 8947; // You may not request this shared task because %1 must wait %2d:%3h:%4m before they can do another task of this type.
|
||||||
constexpr uint16 PLAYER_NOW_LEADER = 8948; // %1 is now the leader of your shared task, '%2'.
|
constexpr uint16 PLAYER_NOW_LEADER = 8948; // %1 is now the leader of your shared task, '%2'.
|
||||||
|
|||||||
@ -427,6 +427,7 @@ int main(int argc, char **argv)
|
|||||||
launcher_list.Process();
|
launcher_list.Process();
|
||||||
LFPGroupList.Process();
|
LFPGroupList.Process();
|
||||||
adventure_manager.Process();
|
adventure_manager.Process();
|
||||||
|
shared_task_manager.Process();
|
||||||
dynamic_zone_manager.Process();
|
dynamic_zone_manager.Process();
|
||||||
|
|
||||||
if (InterserverTimer.Check()) {
|
if (InterserverTimer.Check()) {
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#include "zonelist.h"
|
#include "zonelist.h"
|
||||||
#include "zoneserver.h"
|
#include "zoneserver.h"
|
||||||
#include "shared_task_world_messaging.h"
|
#include "shared_task_world_messaging.h"
|
||||||
|
#include "../common/rulesys.h"
|
||||||
#include "../common/repositories/character_data_repository.h"
|
#include "../common/repositories/character_data_repository.h"
|
||||||
#include "../common/repositories/character_task_timers_repository.h"
|
#include "../common/repositories/character_task_timers_repository.h"
|
||||||
#include "../common/repositories/shared_task_members_repository.h"
|
#include "../common/repositories/shared_task_members_repository.h"
|
||||||
@ -20,6 +21,11 @@
|
|||||||
extern ClientList client_list;
|
extern ClientList client_list;
|
||||||
extern ZSList zoneserver_list;
|
extern ZSList zoneserver_list;
|
||||||
|
|
||||||
|
SharedTaskManager::SharedTaskManager()
|
||||||
|
: m_process_timer{ static_cast<uint32_t>(RuleI(TaskSystem, SharedTasksWorldProcessRate)) }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
SharedTaskManager *SharedTaskManager::SetDatabase(Database *db)
|
SharedTaskManager *SharedTaskManager::SetDatabase(Database *db)
|
||||||
{
|
{
|
||||||
SharedTaskManager::m_database = db;
|
SharedTaskManager::m_database = db;
|
||||||
@ -196,6 +202,13 @@ void SharedTaskManager::RemoveMember(SharedTask* s, const SharedTaskMember& memb
|
|||||||
if (member.is_leader) {
|
if (member.is_leader) {
|
||||||
ChooseNewLeader(s);
|
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)
|
void SharedTaskManager::RemoveEveryoneFromSharedTask(SharedTask *t, uint32 requested_character_id)
|
||||||
@ -226,6 +239,20 @@ void SharedTaskManager::RemoveEveryoneFromSharedTask(SharedTask *t, uint32 reque
|
|||||||
PrintSharedTaskState();
|
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)
|
void SharedTaskManager::DeleteSharedTask(int64 shared_task_id)
|
||||||
{
|
{
|
||||||
LogTasksDetail(
|
LogTasksDetail(
|
||||||
@ -995,6 +1022,12 @@ void SharedTaskManager::AddPlayerByCharacterIdAndName(
|
|||||||
SendSharedTaskMemberList(character_id, s->GetMembers()); // new member gets full member list
|
SendSharedTaskMemberList(character_id, s->GetMembers()); // new member gets full member list
|
||||||
s->AddCharacterToMemberHistory(character_id);
|
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
|
// add to dzs tied to shared task
|
||||||
for (const auto &dz_id : s->dynamic_zone_ids) {
|
for (const auto &dz_id : s->dynamic_zone_ids) {
|
||||||
auto dz = DynamicZone::FindDynamicZoneByID(dz_id);
|
auto dz = DynamicZone::FindDynamicZoneByID(dz_id);
|
||||||
@ -1339,6 +1372,7 @@ bool SharedTaskManager::CanAddPlayer(SharedTask *s, uint32_t character_id, std::
|
|||||||
player_name = cle->name();
|
player_name = cle->name();
|
||||||
|
|
||||||
// check if player is already in a shared task
|
// check if player is already in a shared task
|
||||||
|
// todo: do a memory search instead of query here
|
||||||
auto shared_task_members = SharedTaskMembersRepository::GetWhere(
|
auto shared_task_members = SharedTaskMembersRepository::GetWhere(
|
||||||
*m_database,
|
*m_database,
|
||||||
fmt::format("character_id = {} LIMIT 1", character_id)
|
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
|
// 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) {
|
if (s->GetTaskData().level_spread > 0) {
|
||||||
auto characters = CharacterDataRepository::GetWhere(
|
auto characters = CharacterDataRepository::GetWhere(
|
||||||
*m_database,
|
*m_database,
|
||||||
@ -1703,3 +1738,25 @@ void SharedTaskManager::HandleCompletedTask(SharedTask* s)
|
|||||||
|
|
||||||
AddReplayTimers(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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "../common/database.h"
|
#include "../common/database.h"
|
||||||
#include "../common/shared_tasks.h"
|
#include "../common/shared_tasks.h"
|
||||||
|
#include "../common/timer.h"
|
||||||
#include "../common/repositories/character_task_timers_repository.h"
|
#include "../common/repositories/character_task_timers_repository.h"
|
||||||
|
|
||||||
class DynamicZone;
|
class DynamicZone;
|
||||||
@ -20,6 +21,8 @@ struct SharedTaskActiveInvitation {
|
|||||||
|
|
||||||
class SharedTaskManager {
|
class SharedTaskManager {
|
||||||
public:
|
public:
|
||||||
|
SharedTaskManager();
|
||||||
|
|
||||||
SharedTaskManager *SetDatabase(Database *db);
|
SharedTaskManager *SetDatabase(Database *db);
|
||||||
SharedTaskManager *SetContentDatabase(Database *db);
|
SharedTaskManager *SetContentDatabase(Database *db);
|
||||||
|
|
||||||
@ -65,6 +68,7 @@ public:
|
|||||||
);
|
);
|
||||||
void RemovePlayerFromSharedTask(SharedTask *s, uint32 character_id);
|
void RemovePlayerFromSharedTask(SharedTask *s, uint32 character_id);
|
||||||
void PrintSharedTaskState();
|
void PrintSharedTaskState();
|
||||||
|
void Process();
|
||||||
void RemoveMember(SharedTask* s, const SharedTaskMember& member, bool remove_from_db);
|
void RemoveMember(SharedTask* s, const SharedTaskMember& member, bool remove_from_db);
|
||||||
void RemoveEveryoneFromSharedTask(SharedTask *s, uint32 requested_character_id);
|
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
|
// store a reference of active invitations that have been sent to players
|
||||||
std::vector<SharedTaskActiveInvitation> m_active_invitations{};
|
std::vector<SharedTaskActiveInvitation> m_active_invitations{};
|
||||||
|
|
||||||
|
Timer m_process_timer;
|
||||||
|
|
||||||
std::vector<CharacterTaskTimersRepository::CharacterTaskTimers> GetCharacterTimers(
|
std::vector<CharacterTaskTimersRepository::CharacterTaskTimers> GetCharacterTimers(
|
||||||
const std::vector<uint32_t>& character_ids, const TasksRepository::Tasks& task);
|
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 SendSharedTaskInvitePacket(SharedTask *s, int64 invited_character_id);
|
||||||
void RecordSharedTaskCompletion(SharedTask *s);
|
void RecordSharedTaskCompletion(SharedTask *s);
|
||||||
void RemoveAllMembersFromDynamicZones(SharedTask *s);
|
void RemoveAllMembersFromDynamicZones(SharedTask *s);
|
||||||
|
void StartTerminateTimer(SharedTask* s);
|
||||||
|
void Terminate(SharedTask* s);
|
||||||
|
|
||||||
// memory search
|
// memory search
|
||||||
std::vector<SharedTaskMember> FindCharactersInSharedTasks(const std::vector<uint32_t> &find_characters);
|
std::vector<SharedTaskMember> FindCharactersInSharedTasks(const std::vector<uint32_t> &find_characters);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user