From e1bb3301a5810d4cd6e54d9c67ec60b004889b01 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sat, 18 May 2019 17:26:09 -0400 Subject: [PATCH] World should verify the full task to simplify things --- common/CMakeLists.txt | 1 + common/global_tasks.h | 155 ++++++++++++++++++++++++++++++++++++++++ common/servertalk.h | 1 - world/cliententry.cpp | 46 ++++++++++++ world/cliententry.h | 15 ++++ world/shared_tasks.cpp | 143 +++++++++++++++---------------------- world/shared_tasks.h | 28 +++++--- world/zoneserver.cpp | 5 -- zone/client.h | 2 +- zone/tasks.cpp | 156 ++++++++++++++--------------------------- zone/tasks.h | 127 +-------------------------------- zone/worldserver.cpp | 13 +--- 12 files changed, 349 insertions(+), 343 deletions(-) create mode 100644 common/global_tasks.h diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 3b4fbd870..57fd3b9ae 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -151,6 +151,7 @@ SET(common_headers fixed_memory_hash_set.h fixed_memory_variable_hash_set.h global_define.h + global_tasks.h guild_base.h guilds.h inventory_profile.h diff --git a/common/global_tasks.h b/common/global_tasks.h new file mode 100644 index 000000000..8c840248b --- /dev/null +++ b/common/global_tasks.h @@ -0,0 +1,155 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#ifndef GLOBAL_TASKS_H +#define GLOBAL_TASKS_H + +#include +#include +#include + +#include "types.h" + +/* This file contains what is needed for both zone and world managers + */ + +#define MAXTASKS 10000 +#define MAXTASKSETS 1000 +// The Client has a hard cap of 19 active quests, 29 in SoD+ +#define MAXACTIVEQUESTS 19 +// The Max Chooser (Task Selector entries) is capped at 40 in the Titanium Client. +#define MAXCHOOSERENTRIES 40 +// The Client has a hard cap of 20 activities per task. +#define MAXACTIVITIESPERTASK 20 +// This is used to determine if a client's active task slot is empty. +#define TASKSLOTEMPTY 0 + +// Command Codes for worldserver ServerOP_ReloadTasks +#define RELOADTASKS 0 +#define RELOADTASKGOALLISTS 1 +#define RELOADTASKPROXIMITIES 2 +#define RELOADTASKSETS 3 + +// used for timer lockouts and /tasktimers +struct TaskTimer { + int ID; // ID used in task timer (replay group) + int original_id; // original ID of the task (book keeping) + int expires; // UNIX timestamp of when it expires, what happens with DLS? Fuck it. +}; + +typedef enum { METHODSINGLEID = 0, METHODLIST = 1, METHODQUEST = 2 } TaskMethodType; + +struct ActivityInformation { + int StepNumber; + int Type; + std::string target_name; // name mob, location -- default empty + std::string item_list; // likely defaults to empty + std::string skill_list; // IDs ; separated -- default -1 + std::string spell_list; // IDs ; separated -- default 0 + std::string desc_override; // overrides auto generated description -- default empty + int skill_id; // older clients, first id from above + int spell_id; // older clients, first id from above + int GoalID; + TaskMethodType GoalMethod; + int GoalCount; + int DeliverToNPC; + std::vector ZoneIDs; + std::string zones; // IDs ; searated, ZoneID is the first in this list for older clients -- default empty string + bool Optional; + + inline bool CheckZone(int zone_id) { + if (ZoneIDs.empty()) + return true; + return std::find(ZoneIDs.begin(), ZoneIDs.end(), zone_id) != ZoneIDs.end(); + } +}; + +typedef enum { ActivitiesSequential = 0, ActivitiesStepped = 1 } SequenceType; + +enum class TaskType { + Task = 0, // can have at max 1 + Shared = 1, // can have at max 1 + Quest = 2, // can have at max 19 or 29 depending on client + E = 3 // can have at max 19 or 29 depending on client, not present in live anymore +}; + +enum class DurationCode { + None = 0, + Short = 1, + Medium = 2, + Long = 3 +}; + +// need to capture more, shared are just Radiant/Ebon though +enum class PointType { + None = 0, + Radiant = 4, + Ebon = 5, +}; + +struct TaskInformation { + TaskType type; + int Duration; + DurationCode dur_code; // description for time investment for when Duration == 0 + std::string Title; // max length 64 + std::string Description; // max length 4000, 2048 on Tit + std::string Reward; + std::string item_link; // max length 128 older clients, item link gets own string + std::string completion_emote; // emote after completing task, yellow. Maybe should make more generic ... but yellow for now! + int RewardID; + int CashReward; // Expressed in copper + int XPReward; + int faction_reward; // just a npc_faction_id + TaskMethodType RewardMethod; + int reward_points; // DoN crystals for shared. Generic "points" for non-shared + PointType reward_type; // 4 for Radiant Crystals else Ebon crystals when shared task + int ActivityCount; + SequenceType SequenceMode; + int LastStep; + short MinLevel; + short MaxLevel; + bool Repeatable; + int replay_group; // ID of our replay timer group (0 means none) + int min_players; // shared tasks + int max_players; + int task_lock_step; // task locks after this step is completed + uint32 instance_zone_id; // instance shit + uint32 zone_version; + uint16 zone_in_zone_id; + float zone_in_x; + float zone_in_y; + uint16 zone_in_object_id; + float dest_x; + float dest_y; + float dest_z; + float dest_h; + /* int graveyard_zone_id; + float graveyard_x; + float graveyard_y; + float graveyard_z; + float graveyard_radius; */ + ActivityInformation Activity[MAXACTIVITIESPERTASK]; +}; + +typedef enum { ActivityHidden = 0, ActivityActive = 1, ActivityCompleted = 2 } ActivityState; + +typedef enum { ActivityDeliver = 1, ActivityKill = 2, ActivityLoot = 3, ActivitySpeakWith = 4, ActivityExplore = 5, + ActivityTradeSkill = 6, ActivityFish = 7, ActivityForage = 8, ActivityCastOn = 9, ActivitySkillOn = 10, + ActivityTouch = 11, ActivityCollect = 13, ActivityGiveCash = 100 } ActivityType; + + +#endif /* !GLOBAL_TASKS_H */ diff --git a/common/servertalk.h b/common/servertalk.h index 459008709..22e021fc8 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -157,7 +157,6 @@ #define ServerOP_TaskReject 0x0302 #define ServerOP_TaskAddPlayer 0x0303 #define ServerOP_TaskRemovePlayer 0x0304 -#define ServerOP_TaskRequestReply 0x0305 #define ServerOP_EncapPacket 0x2007 // Packet within a packet #define ServerOP_WorldListUpdate 0x2008 diff --git a/world/cliententry.cpp b/world/cliententry.cpp index be8916676..0c9f05b90 100644 --- a/world/cliententry.cpp +++ b/world/cliententry.cpp @@ -25,6 +25,9 @@ #include "world_config.h" #include "../common/guilds.h" #include "../common/string_util.h" +#include "shared_tasks.h" + +#include extern uint32 numplayers; extern LoginServerList loginserverlist; @@ -50,6 +53,8 @@ ClientListEntry::ClientListEntry(uint32 in_id, uint32 iLSID, const char* iLoginN pLFGToLevel = 0; pLFGMatchFilter = false; memset(pLFGComments, 0, 64); + shared_task_id = 0; + m_shared_task = nullptr; } ClientListEntry::ClientListEntry(uint32 in_id, uint32 iAccID, const char* iAccName, MD5& iMD5Pass, int16 iAdmin) @@ -71,6 +76,8 @@ ClientListEntry::ClientListEntry(uint32 in_id, uint32 iAccID, const char* iAccNa pLFGToLevel = 0; pLFGMatchFilter = false; memset(pLFGComments, 0, 64); + shared_task_id = 0; + m_shared_task = nullptr; } ClientListEntry::ClientListEntry(uint32 in_id, ZoneServer* iZS, ServerClientList_Struct* scl, int8 iOnline) @@ -93,6 +100,8 @@ ClientListEntry::ClientListEntry(uint32 in_id, ZoneServer* iZS, ServerClientList pLFGToLevel = 0; pLFGMatchFilter = false; memset(pLFGComments, 0, 64); + shared_task_id = 0; + m_shared_task = nullptr; if (iOnline >= CLE_Status_Zoning) Update(iZS, scl, iOnline); @@ -105,6 +114,8 @@ ClientListEntry::~ClientListEntry() { Camp(); // updates zoneserver's numplayers client_list.RemoveCLEReferances(this); } + if (m_shared_task != nullptr) + m_shared_task->MemberLeftGame(this); for (auto &elem : tell_queue) safe_delete_array(elem); tell_queue.clear(); @@ -248,6 +259,10 @@ void ClientListEntry::ClearVars(bool iAll) { pLFG = 0; gm = 0; pClientVersion = 0; + shared_task_id = 0; + if (m_shared_task != nullptr) + m_shared_task->MemberLeftGame(this); + m_shared_task = nullptr; for (auto &elem : tell_queue) safe_delete_array(elem); tell_queue.clear(); @@ -331,3 +346,34 @@ void ClientListEntry::ProcessTellQueue() return; } +/* + * returns expire timestamp + */ + +int ClientListEntry::GetTaskLockoutExpire(int id) const +{ + auto it = std::find_if(m_task_replay_timers.begin(), m_task_replay_timers.end(), + [id](const TaskTimer &a) { return a.ID == id; }); + + if (it != m_task_replay_timers.end()) + return it->expires; + + return 0; +} + +/* + * returns seconds until expires + * returns <= 0 if expired + */ + +int ClientListEntry::GetTaskLockoutTimeLeft(int id) const +{ + auto it = std::find_if(m_task_replay_timers.begin(), m_task_replay_timers.end(), + [id](const TaskTimer &a) { return a.ID == id; }); + + if (it != m_task_replay_timers.end()) + return it->expires - Timer::GetCurrentTime(); + + return 0; +} + diff --git a/world/cliententry.h b/world/cliententry.h index 24a837ae9..5b18d0417 100644 --- a/world/cliententry.h +++ b/world/cliententry.h @@ -6,6 +6,7 @@ //#include "../common/eq_packet_structs.h" #include "../common/servertalk.h" #include "../common/rulesys.h" +#include "../common/global_tasks.h" #include @@ -18,6 +19,7 @@ class ZoneServer; struct ServerClientList_Struct; +class SharedTask; class ClientListEntry { public: @@ -88,6 +90,12 @@ public: inline void PushToTellQueue(ServerChannelMessage_Struct *scm) { tell_queue.push_back(scm); } void ProcessTellQueue(); + // shared task stuff + int GetTaskLockoutExpire(int id) const; + int GetTaskLockoutTimeLeft(int id) const; + inline int GetCurrentSharedTaskID() const { return shared_task_id; } + inline void SetCurrentSharedTaskID(int in) { shared_task_id = in; } + private: void ClearVars(bool iAll = false); @@ -129,6 +137,13 @@ private: bool pLFGMatchFilter; char pLFGComments[64]; + // shared task stuff + // stub for now + int shared_task_id; // ID in the TaskManager + SharedTask *m_shared_task; // just for quick reference so we can tell it to clean up our pointer + + std::vector m_task_replay_timers; + // Tell Queue -- really a vector :D std::vector tell_queue; }; diff --git a/world/shared_tasks.cpp b/world/shared_tasks.cpp index 4fbb153b5..5ec43a031 100644 --- a/world/shared_tasks.cpp +++ b/world/shared_tasks.cpp @@ -3,6 +3,8 @@ #include "cliententry.h" #include "zonelist.h" +#include + extern ClientList client_list; extern ZSList zoneserver_list; @@ -15,11 +17,25 @@ void SharedTaskManager::HandleTaskRequest(ServerPacket *pack) int task_id = pack->ReadUInt32(); pack->ReadString(tmp_str); std::string leader_name = tmp_str; - int missing_count = pack->ReadUInt32(); - std::vector missing_players; - for (int i = 0; i < missing_count; ++i) { + int player_count = pack->ReadUInt32(); + std::vector players; + for (int i = 0; i < player_count; ++i) { pack->ReadString(tmp_str); - missing_players.push_back(tmp_str); + players.push_back(tmp_str); + } + + // check if the task exist, we only load shared tasks in world, so we know the type is correct if found + auto it = task_information.find(task_id); + if (it == task_information.end()) { // not loaded! bad id or not shared task + auto pc = client_list.FindCharacter(leader_name.c_str()); + if (pc) { + auto pack = new ServerPacket(ServerOP_TaskReject, leader_name.size() + 1 + 4); + pack->WriteUInt32(0); // string ID or just generic fail message + pack->WriteString(leader_name.c_str()); + zoneserver_list.SendPacket(pc->zone(), pc->instance(), pack); + safe_delete(pack); + } // oh well + return; } int id = GetNextID(); @@ -33,85 +49,46 @@ void SharedTaskManager::HandleTaskRequest(ServerPacket *pack) zoneserver_list.SendPacket(pc->zone(), pc->instance(), pack); safe_delete(pack); } // oh well + return; + } + + auto cle = client_list.FindCharacter(leader_name.c_str()); + if (cle == nullptr) {// something went wrong + tasks.erase(ret.first); + return; } auto &task = ret.first->second; - task.AddMember(leader_name, true); + task.AddMember(leader_name, cle, true); - if (missing_players.empty()) { + if (players.empty()) { // send instant success to leader - auto pc = client_list.FindCharacter(leader_name.c_str()); - if (pc) { - SerializeBuffer buf(10); - buf.WriteInt32(id); // task's ID - buf.WriteString(leader_name); // leader's name + SerializeBuffer buf(10); + buf.WriteInt32(id); // task's ID + buf.WriteString(leader_name); // leader's name - auto pack = new ServerPacket(ServerOP_TaskGrant, buf); - zoneserver_list.SendPacket(pc->zone(), pc->instance(), pack); - safe_delete(pack); - } else { // well fuck - tasks.erase(ret.first); - } + auto pack = new ServerPacket(ServerOP_TaskGrant, buf); + zoneserver_list.SendPacket(cle->zone(), cle->instance(), pack); + safe_delete(pack); return; } - task.SetMissingCount(missing_count); - for (auto &&name : missing_players) { + for (auto &&name : players) { // look up CLEs by name, tell them we need to know if they can be added - auto pc = client_list.FindCharacter(name.c_str()); - if (pc) { - SerializeBuffer buf(10); - buf.WriteInt32(id); - buf.WriteInt32(task_id); - buf.WriteString(name); + cle = client_list.FindCharacter(name.c_str()); + if (cle) { + // make sure we don't have a shared task already - auto pack = new ServerPacket(ServerOP_TaskRequest, buf); - zoneserver_list.SendPacket(pc->zone(), pc->instance(), pack); - safe_delete(pack); - } else { // asked for a toon we couldn't find ABORT! - auto pc = client_list.FindCharacter(leader_name.c_str()); - if (pc) { - auto pack = new ServerPacket(ServerOP_TaskReject, leader_name.size() + 1 + 4); - pack->WriteUInt32(0); // string ID or just generic fail message - pack->WriteString(leader_name.c_str()); - zoneserver_list.SendPacket(pc->zone(), pc->instance(), pack); - safe_delete(pack); - } // oh well - tasks.erase(ret.first); - break; + // make sure our level is right + + // check our lock out timer + + // we're good, add to task + task.AddMember(name, cle); } } } -void SharedTaskManager::HandleTaskRequestReply(ServerPacket *pack) -{ - if (!pack) - return; - - int id = pack->ReadUInt32(); - - char name[64] = { 0 }; - pack->ReadString(name); - - int status = pack->ReadUInt32(); - - auto it = tasks.find(id); - if (it == tasks.end()) { - // task already errored and no longer existed, we can ignore - return; - } - - auto &task = it->second; - - if (status != TASKJOINOOZ_CAN) { - // TODO: forward to leader - return; - } - - if (!task.DecrementMissingCount()) - tasks.erase(it); -} - /* * This is called once during boot of world * We need to load next_id, clean up expired tasks (?), and populate the map @@ -138,23 +115,19 @@ int SharedTaskManager::GetNextID() return next_id; } -bool SharedTask::DecrementMissingCount() -{ - --missing_count; - if (missing_count == 0) { - auto pc = client_list.FindCharacter(leader_name.c_str()); - if (pc) { - SerializeBuffer buf(10); - buf.WriteInt32(id); // task's ID - buf.WriteString(leader_name); // leader's name +/* + * When a player leaves world they will tell us to clean up their pointer + * This is NOT leaving the shared task, just crashed or something + */ - auto pack = new ServerPacket(ServerOP_TaskGrant, buf); - zoneserver_list.SendPacket(pc->zone(), pc->instance(), pack); - safe_delete(pack); - } else { - return false; // error, please clean us up - } - } - return true; +void SharedTask::MemberLeftGame(ClientListEntry *cle) +{ + auto it = std::find_if(members.begin(), members.end(), [cle](SharedTaskMember &m) { return m.cle == cle; }); + + // ahh okay ... + if (it == members.end()) + return; + + it->cle = nullptr; } diff --git a/world/shared_tasks.h b/world/shared_tasks.h index 791c7cf30..9771c4343 100644 --- a/world/shared_tasks.h +++ b/world/shared_tasks.h @@ -5,29 +5,36 @@ #include #include "../common/servertalk.h" +#include "../common/global_tasks.h" + +class ClientListEntry; struct SharedTaskMember { std::string name; + ClientListEntry *cle; bool leader; - SharedTaskMember() : leader(false) {} - SharedTaskMember(std::string name, bool leader) : name(name), leader(leader) {} + SharedTaskMember() : leader(false), cle(nullptr) {} + SharedTaskMember(std::string name, ClientListEntry *cle, bool leader) : name(name), cle(cle), leader(leader) {} }; class SharedTask { public: - SharedTask() : id(0), task_id(0), missing_count(0) {} - SharedTask(int id, int task_id) : id(id), task_id(task_id), missing_count(0) {} + SharedTask() : id(0), task_id(0) {} + SharedTask(int id, int task_id) : id(id), task_id(task_id) {} ~SharedTask() {} - void AddMember(std::string name, bool leader = false) { members.push_back({name, leader}); if (leader) leader_name = name; } - inline void SetMissingCount(int in) { missing_count = in; } - bool DecrementMissingCount(); // if we failed, tell who called us to clean us up basically + void AddMember(std::string name, ClientListEntry *cle = nullptr, bool leader = false) + { + members.push_back({name, cle, leader}); + if (leader) + leader_name = name; + } + void MemberLeftGame(ClientListEntry *cle); const std::string &GetLeaderName() const { return leader_name; } private: int id; // id we have in our map int task_id; // ID of the task we're on - int missing_count; // other toons waiting to verify (out of zone, etc) std::string leader_name; std::vector members; }; @@ -38,15 +45,16 @@ public: ~SharedTaskManager() {} bool LoadSharedTaskState(); + bool LoadSharedTasks(); // IPC packet processing void HandleTaskRequest(ServerPacket *pack); - void HandleTaskRequestReply(ServerPacket *pack); private: int GetNextID(); int next_id; - std::unordered_map tasks; + std::unordered_map tasks; // current active shared task states + std::unordered_map task_information; // task info shit }; #endif /* !SHARED_TASKS_H */ diff --git a/world/zoneserver.cpp b/world/zoneserver.cpp index ab99e144f..e66bd797d 100644 --- a/world/zoneserver.cpp +++ b/world/zoneserver.cpp @@ -1356,11 +1356,6 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) { shared_tasks.HandleTaskRequest(pack); break; } - case ServerOP_TaskRequestReply: - { - shared_tasks.HandleTaskRequestReply(pack); - break; - } default: { Log(Logs::Detail, Logs::World_Server, "Unknown ServerOPcode from zone 0x%04x, size %d", pack->opcode, pack->size); diff --git a/zone/client.h b/zone/client.h index 2931b674d..9b40be60d 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1036,7 +1036,6 @@ public: inline void ProcessTaskProximities(float X, float Y, float Z) { if(taskstate) taskstate->ProcessTaskProximities(this, X, Y, Z); } inline void AssignTask(int TaskID, int NPCID, bool enforce_level_requirement = false) { if (taskstate) taskstate->AcceptNewTask(this, TaskID, NPCID, enforce_level_requirement); } inline void AssignSharedTask(int TaskID, int NPCID, int id) { if (taskstate) taskstate->AcceptNewSharedTask(this, TaskID, NPCID, id); } - inline void HandleCanJoinSharedTask(int TaskID, int id) { if (taskstate) taskstate->HandleCanJoinSharedTask(this, TaskID, id); } inline int ActiveSpeakTask(int NPCID) { if(taskstate) return taskstate->ActiveSpeakTask(NPCID); else return 0; } inline int ActiveSpeakActivity(int NPCID, int TaskID) { if(taskstate) return taskstate->ActiveSpeakActivity(NPCID, TaskID); else return 0; } inline void FailTask(int TaskID) { if(taskstate) taskstate->FailTask(this, TaskID); } @@ -1054,6 +1053,7 @@ public: inline int ActiveTasksInSet(int TaskSet) { return (taskstate ? taskstate->ActiveTasksInSet(TaskSet) :0); } inline int CompletedTasksInSet(int TaskSet) { return (taskstate ? taskstate->CompletedTasksInSet(TaskSet) :0); } inline int GetTaskLockoutExpire(int id) { return 0; } // stub + inline int GetTaskLockoutTimeLeft(int id) { return 0; } // stub inline void SetPendingTask(int id, int task_master_id) { pending_task.id = id; pending_task.task_master_id = task_master_id; } inline bool HasPendingTask() const { return pending_task.id != 0; } diff --git a/zone/tasks.cpp b/zone/tasks.cpp index 3748b4d6d..d4b905e06 100644 --- a/zone/tasks.cpp +++ b/zone/tasks.cpp @@ -3405,14 +3405,13 @@ void ClientTaskState::PendSharedTask(Client *c, int TaskID, int NPCID, bool enfo return; if (task->replay_group) { - auto expires = c->GetTaskLockoutExpire(task->replay_group); - if (expires) { - auto diff = expires - Timer::GetCurrentTime(); - std::string days = std::to_string(diff / 86400); - diff = diff % 86400; - std::string hours = std::to_string(diff / 3600); - diff = diff % 3600; - std::string minutes = std::to_string(diff / 60); + auto expires = c->GetTaskLockoutTimeLeft(task->replay_group); + if (expires > 0) { + std::string days = std::to_string(expires / 86400); + expires = expires % 86400; + std::string hours = std::to_string(expires / 3600); + expires = expires % 3600; + std::string minutes = std::to_string(expires / 60); c->Message_StringID(13, TASK_REJECT_LOCKEDOUT, days.c_str(), hours.c_str(), minutes.c_str()); return; } @@ -3440,6 +3439,37 @@ void ClientTaskState::PendSharedTask(Client *c, int TaskID, int NPCID, bool enfo return; } + // okay, we verified a few things on the requestor, now we need to fire off to world to do the rest + SerializeBuffer buf(25 + 10 * player_count); + buf.WriteInt32(TaskID); // Task ID + buf.WriteString(c->GetName()); // leader name + buf.WriteInt32(player_count - 1); // count, not leader + if (group) { + for (int i = 0; i < MAX_GROUP_MEMBERS; ++i) { + if (group->members[i] == c) // skipping requestor + continue; + + // TODO: mercs/bots + if (group->members[i] != nullptr && group->members[i]->IsClient()) + buf.WriteString(group->membername[i]); + } + } else if (raid) { + for (int i = 0; i < MAX_RAID_MEMBERS; ++i) { + if (raid->members[i].member == c) // skipping requestor + continue; + // TODO: bots if they ever can live in a raid + if (raid->members[i].membername[0] != '\0') + buf.WriteString(raid->members[i].membername); + } + } + + auto pack = new ServerPacket(ServerOP_TaskRequest, buf); + worldserver.SendPacket(pack); + delete pack; + + return; + + /* std::vector missing_players; // names of players not in this zone so we can put the checks off to world bool task_failed = false; if (group) { @@ -3458,15 +3488,14 @@ void ClientTaskState::PendSharedTask(Client *c, int TaskID, int NPCID, bool enfo break; } else { if (task->replay_group) { - auto expires = client->GetTaskLockoutExpire(task->replay_group); - if (expires) { + auto expires = client->GetTaskLockoutTimeLeft(task->replay_group); + if (expires > 0) { task_failed = true; - auto diff = expires - Timer::GetCurrentTime(); - std::string days = std::to_string(diff / 86400); - diff = diff % 86400; - std::string hours = std::to_string(diff / 3600); - diff = diff % 3600; - std::string minutes = std::to_string(diff / 60); + std::string days = std::to_string(expires / 86400); + expires = expires % 86400; + std::string hours = std::to_string(expires / 3600); + expires = expires % 3600; + std::string minutes = std::to_string(expires / 60); c->Message_StringID(13, TASK_REJECT_LOCKEDOUT_OTHER, client->GetName(), days.c_str(), hours.c_str(), minutes.c_str()); @@ -3497,15 +3526,14 @@ void ClientTaskState::PendSharedTask(Client *c, int TaskID, int NPCID, bool enfo break; } else { if (task->replay_group) { - auto expires = client->GetTaskLockoutExpire(task->replay_group); - if (expires) { + auto expires = client->GetTaskLockoutTimeLeft(task->replay_group); + if (expires > 0) { task_failed = true; - auto diff = expires - Timer::GetCurrentTime(); - std::string days = std::to_string(diff / 86400); - diff = diff % 86400; - std::string hours = std::to_string(diff / 3600); - diff = diff % 3600; - std::string minutes = std::to_string(diff / 60); + std::string days = std::to_string(expires / 86400); + expires = expires % 86400; + std::string hours = std::to_string(expires / 3600); + expires = expires % 3600; + std::string minutes = std::to_string(expires / 60); c->Message_StringID(13, TASK_REJECT_LOCKEDOUT_OTHER, client->GetName(), days.c_str(), hours.c_str(), minutes.c_str()); @@ -3530,17 +3558,8 @@ void ClientTaskState::PendSharedTask(Client *c, int TaskID, int NPCID, bool enfo // so we've verified all the clients we can and didn't fail, time to pend and yell at world c->SetPendingTask(TaskID, NPCID); c->StartPendingTimer(); // in case something goes wrong and takes ages, we time out + */ - SerializeBuffer buf(25 + 10 * missing_players.size()); - buf.WriteInt32(TaskID); // Task ID - buf.WriteString(c->GetName()); // leader name - buf.WriteInt32(missing_players.size()); // count - for (auto && name : missing_players) - buf.WriteString(name); - - auto pack = new ServerPacket(ServerOP_TaskRequest, buf); - worldserver.SendPacket(pack); - delete pack; } void ClientTaskState::AcceptNewSharedTask(Client *c, int TaskID, int NPCID, int id) @@ -3548,75 +3567,6 @@ void ClientTaskState::AcceptNewSharedTask(Client *c, int TaskID, int NPCID, int } -void ClientTaskState::HandleCanJoinSharedTask(Client *c, int TaskID, int id) -{ - if (!c) - return; - - SerializeBuffer buf(15); - buf.WriteInt32(id); - buf.WriteString(c->GetName()); - - if (!taskmanager || TaskID < 0 || TaskID >= MAXTASKS) { - buf.WriteInt32(TASKJOINOOZ_NOTASK); - auto pack = new ServerPacket(ServerOP_TaskRequestReply, buf); - worldserver.SendPacket(pack); - delete pack; - return; - } - - auto task = taskmanager->Tasks[TaskID]; - - if (task == nullptr) { - buf.WriteInt32(TASKJOINOOZ_NOTASK); - auto pack = new ServerPacket(ServerOP_TaskRequestReply, buf); - worldserver.SendPacket(pack); - delete pack; - return; - } - - if (task->type != TaskType::Shared) { - buf.WriteInt32(TASKJOINOOZ_NOTASK); - auto pack = new ServerPacket(ServerOP_TaskRequestReply, buf); - worldserver.SendPacket(pack); - delete pack; - return; - } - - if (ActiveSharedTask != nullptr) { - buf.WriteInt32(TASKJOINOOZ_HAVEONE); - auto pack = new ServerPacket(ServerOP_TaskRequestReply, buf); - worldserver.SendPacket(pack); - delete pack; - return; - } - - if (!taskmanager->AppropriateLevel(TaskID, c->GetLevel())) { - buf.WriteInt32(TASKJOINOOZ_LEVEL); - auto pack = new ServerPacket(ServerOP_TaskRequestReply, buf); - worldserver.SendPacket(pack); - delete pack; - return; - } - - if (task->replay_group) { - auto expires = c->GetTaskLockoutExpire(task->replay_group); - if (expires) { - buf.WriteInt32(TASKJOINOOZ_TIMER); - buf.WriteInt32(expires); - auto pack = new ServerPacket(ServerOP_TaskRequestReply, buf); - worldserver.SendPacket(pack); - delete pack; - return; - } - } - - buf.WriteInt32(TASKJOINOOZ_CAN); - auto pack = new ServerPacket(ServerOP_TaskRequestReply, buf); - worldserver.SendPacket(pack); - delete pack; -} - void ClientTaskState::ProcessTaskProximities(Client *c, float X, float Y, float Z) { float LastX = c->ProximityX(); diff --git a/zone/tasks.h b/zone/tasks.h index ee3b61a87..b679b45e2 100644 --- a/zone/tasks.h +++ b/zone/tasks.h @@ -21,6 +21,7 @@ Copyright (C) 2001-2004 EQEMu Development Team (http://eqemulator.net) #define TASKS_H #include "../common/types.h" +#include "../common/global_tasks.h" #include #include @@ -29,24 +30,6 @@ Copyright (C) 2001-2004 EQEMu Development Team (http://eqemulator.net) #include #include -#define MAXTASKS 10000 -#define MAXTASKSETS 1000 -// The Client has a hard cap of 19 active quests, 29 in SoD+ -#define MAXACTIVEQUESTS 19 -// The Max Chooser (Task Selector entries) is capped at 40 in the Titanium Client. -#define MAXCHOOSERENTRIES 40 -// The Client has a hard cap of 20 activities per task. -#define MAXACTIVITIESPERTASK 20 -// This is used to determine if a client's active task slot is empty. -#define TASKSLOTEMPTY 0 - -// Command Codes for worldserver ServerOP_ReloadTasks -// -#define RELOADTASKS 0 -#define RELOADTASKGOALLISTS 1 -#define RELOADTASKPROXIMITIES 2 -#define RELOADTASKSETS 3 - class Client; class Mob; @@ -100,106 +83,6 @@ private: std::vector TaskProximities; }; -typedef enum { METHODSINGLEID = 0, METHODLIST = 1, METHODQUEST = 2 } TaskMethodType; - -struct ActivityInformation { - int StepNumber; - int Type; - std::string target_name; // name mob, location -- default empty - std::string item_list; // likely defaults to empty - std::string skill_list; // IDs ; separated -- default -1 - std::string spell_list; // IDs ; separated -- default 0 - std::string desc_override; // overrides auto generated description -- default empty - int skill_id; // older clients, first id from above - int spell_id; // older clients, first id from above - int GoalID; - TaskMethodType GoalMethod; - int GoalCount; - int DeliverToNPC; - std::vector ZoneIDs; - std::string zones; // IDs ; searated, ZoneID is the first in this list for older clients -- default empty string - bool Optional; - - inline bool CheckZone(int zone_id) { - if (ZoneIDs.empty()) - return true; - return std::find(ZoneIDs.begin(), ZoneIDs.end(), zone_id) != ZoneIDs.end(); - } -}; - -typedef enum { ActivitiesSequential = 0, ActivitiesStepped = 1 } SequenceType; - -enum class TaskType { - Task = 0, // can have at max 1 - Shared = 1, // can have at max 1 - Quest = 2, // can have at max 19 or 29 depending on client - E = 3 // can have at max 19 or 29 depending on client, not present in live anymore -}; - -enum class DurationCode { - None = 0, - Short = 1, - Medium = 2, - Long = 3 -}; - -// need to capture more, shared are just Radiant/Ebon though -enum class PointType { - None = 0, - Radiant = 4, - Ebon = 5, -}; - -struct TaskInformation { - TaskType type; - int Duration; - DurationCode dur_code; // description for time investment for when Duration == 0 - std::string Title; // max length 64 - std::string Description; // max length 4000, 2048 on Tit - std::string Reward; - std::string item_link; // max length 128 older clients, item link gets own string - std::string completion_emote; // emote after completing task, yellow. Maybe should make more generic ... but yellow for now! - int RewardID; - int CashReward; // Expressed in copper - int XPReward; - int faction_reward; // just a npc_faction_id - TaskMethodType RewardMethod; - int reward_points; // DoN crystals for shared. Generic "points" for non-shared - PointType reward_type; // 4 for Radiant Crystals else Ebon crystals when shared task - int ActivityCount; - SequenceType SequenceMode; - int LastStep; - short MinLevel; - short MaxLevel; - bool Repeatable; - int replay_group; // ID of our replay timer group (0 means none) - int min_players; // shared tasks - int max_players; - int task_lock_step; // task locks after this step is completed - uint32 instance_zone_id; // instance shit - uint32 zone_version; - uint16 zone_in_zone_id; - float zone_in_x; - float zone_in_y; - uint16 zone_in_object_id; - float dest_x; - float dest_y; - float dest_z; - float dest_h; - /* int graveyard_zone_id; - float graveyard_x; - float graveyard_y; - float graveyard_z; - float graveyard_radius; */ - ActivityInformation Activity[MAXACTIVITIESPERTASK]; -}; - -typedef enum { ActivityHidden = 0, ActivityActive = 1, ActivityCompleted = 2 } ActivityState; - -typedef enum { ActivityDeliver = 1, ActivityKill = 2, ActivityLoot = 3, ActivitySpeakWith = 4, ActivityExplore = 5, - ActivityTradeSkill = 6, ActivityFish = 7, ActivityForage = 8, ActivityCastOn = 9, ActivitySkillOn = 10, - ActivityTouch = 11, ActivityCollect = 13, ActivityGiveCash = 100 } ActivityType; - struct ClientActivityInformation { int ActivityID; @@ -267,7 +150,6 @@ public: void AcceptNewTask(Client *c, int TaskID, int NPCID, bool enforce_level_requirement = false); void AcceptNewSharedTask(Client *c, int TaskID, int NPCID, int id); void PendSharedTask(Client *c, int TaskID, int NPCID, bool enforce_level_requirement = false); - void HandleCanJoinSharedTask(Client *c, int TaskID, int id); void FailTask(Client *c, int TaskID); int TaskTimeLeft(int TaskID); int IsTaskCompleted(int TaskID); @@ -345,13 +227,6 @@ private: bool CheckedTouchActivities; }; -// used for timer lockouts and /tasktimers -struct TaskTimer { - int ID; // ID used in task timer - int original_id; // original ID of the task - int expires; // UNIX timestamp of when it expires, what happens with DLS? Fuck it. -}; - struct TaskReplayGroups { std::string name; int duration; diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index b507cfdea..3662d9cff 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -1954,6 +1954,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) } case ServerOP_TaskReject: { + // this will be reworked to not use the pend shit, we will depend on hoping successive requests just get thrown out int message = pack->ReadUInt32(); char name[64] = { 0 }; pack->ReadString(name); @@ -1968,18 +1969,6 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) } break; } - case ServerOP_TaskRequest: - { - int id = pack->ReadUInt32(); // we need the ID when reply to world so we know which shared task we're going to - int task_id = pack->ReadUInt32(); - char name[64] = { 0 }; - pack->ReadString(name); - auto client = entity_list.GetClientByName(name); - if (client) { - client->HandleCanJoinSharedTask(task_id, id); - } - break; - } default: { std::cout << " Unknown ZSopcode:" << (int)pack->opcode; std::cout << " size:" << pack->size << std::endl;