mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-16 22:58:34 +00:00
[Tasks] Reward clients on shared task completion sync (#2306)
If a member is offline (or possibly during a race while zoning?) when the shared task is completed they will not receive the reward. On live the character receives their reward (with an updated replay timer) if they enter back into game while the shared task is still active. They keep the original replay timer if the shared task is no longer active and do not receive a reward. This makes it so clients are issued rewards (and a task completed event is dispatch) if the client's task state was out of sync with a completed shared task. To prevent characters being rewarded more than once in case of bad sync checks, a 'was_rewarded' field has been added to the character_tasks table and updated when rewards are assigned. This fixes a couple bugs so the character_activities table is correctly updated with shared task states to better detect when out of sync: - The character_activities table is now flagged to update after syncing shared task states. This table was not being updated if a client was offline or inaccessible for a shared task element update. - The character_activities table is now updated when a task element is completed. This was only being updated for activity increments and on completing the entire task. SaveClientState is now called at the end of ClientTaskState::IncrementDoneCount to cover all cases. This also has a cosmetic change to show replay timers before rewards like live, though this will not work for shared tasks until refactoring world code
This commit is contained in:
+36
-5
@@ -314,13 +314,14 @@ bool TaskManager::SaveClientState(Client *client, ClientTaskState *client_task_s
|
||||
);
|
||||
|
||||
std::string query = StringFormat(
|
||||
"REPLACE INTO character_tasks (charid, taskid, slot, type, acceptedtime) "
|
||||
"VALUES (%i, %i, %i, %i, %i)",
|
||||
"REPLACE INTO character_tasks (charid, taskid, slot, type, acceptedtime, was_rewarded) "
|
||||
"VALUES (%i, %i, %i, %i, %i, %d)",
|
||||
character_id,
|
||||
task_id,
|
||||
slot,
|
||||
static_cast<int>(m_task_data[task_id]->type),
|
||||
active_task.accepted_time
|
||||
active_task.accepted_time,
|
||||
active_task.was_rewarded
|
||||
);
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
@@ -1326,6 +1327,7 @@ bool TaskManager::LoadClientState(Client *client, ClientTaskState *client_task_s
|
||||
task_info->current_step = -1;
|
||||
task_info->accepted_time = character_task.acceptedtime;
|
||||
task_info->updated = false;
|
||||
task_info->was_rewarded = character_task.was_rewarded;
|
||||
|
||||
for (auto &i : task_info->activity) {
|
||||
i.activity_id = -1;
|
||||
@@ -1337,11 +1339,12 @@ bool TaskManager::LoadClientState(Client *client, ClientTaskState *client_task_s
|
||||
}
|
||||
|
||||
LogTasks(
|
||||
"[LoadClientState] character_id [{}] task_id [{}] slot [{}] accepted_time [{}]",
|
||||
"[LoadClientState] character_id [{}] task_id [{}] slot [{}] accepted_time [{}] was_rewarded [{}]",
|
||||
character_id,
|
||||
task_id,
|
||||
slot,
|
||||
character_task.acceptedtime
|
||||
character_task.acceptedtime,
|
||||
character_task.was_rewarded
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1685,6 +1688,9 @@ void TaskManager::SyncClientSharedTaskWithPersistedState(Client *c, ClientTaskSt
|
||||
shared_task->activity[a.activity_id].activity_state =
|
||||
(a.completed_time > 0 ? ActivityCompleted : ActivityHidden);
|
||||
|
||||
// flag to update character_activities table entry on save
|
||||
shared_task->activity[a.activity_id].updated = true;
|
||||
|
||||
// set flag to persist later
|
||||
fell_behind_state = true;
|
||||
}
|
||||
@@ -1692,6 +1698,17 @@ void TaskManager::SyncClientSharedTaskWithPersistedState(Client *c, ClientTaskSt
|
||||
|
||||
// fell behind, force a save of client state
|
||||
if (fell_behind_state) {
|
||||
// give reward if member was offline for shared task completion
|
||||
// live does this as long as the shared task is still active when entering game
|
||||
if (!shared_task->was_rewarded && IsActiveTaskComplete(*shared_task))
|
||||
{
|
||||
LogTasksDetail("[LoadClientState] Syncing shared task completion for client [{}]", c->GetName());
|
||||
auto task_info = task_manager->m_task_data[shared_task->task_id];
|
||||
cts->AddReplayTimer(c, *shared_task, *task_info); // live updates a fresh timer
|
||||
cts->DispatchEventTaskComplete(c, *shared_task, task_info->activity_count - 1);
|
||||
cts->RewardTask(c, task_info, *shared_task);
|
||||
}
|
||||
|
||||
SaveClientState(c, cts);
|
||||
}
|
||||
|
||||
@@ -1915,3 +1932,17 @@ void TaskManager::HandleUpdateTasksOnKill(Client *client, uint32 npc_type_id, st
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TaskManager::IsActiveTaskComplete(ClientTaskInformation& client_task)
|
||||
{
|
||||
auto task_info = task_manager->m_task_data[client_task.task_id];
|
||||
for (int i = 0; i < task_info->activity_count; ++i)
|
||||
{
|
||||
if (client_task.activity[i].activity_state != ActivityCompleted &&
|
||||
!task_info->activity_information[i].optional)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user