diff --git a/world/cliententry.h b/world/cliententry.h index c7ce90859..7709d9215 100644 --- a/world/cliententry.h +++ b/world/cliententry.h @@ -96,6 +96,8 @@ public: inline int GetCurrentSharedTaskID() const { return shared_task_id; } inline void SetCurrentSharedTaskID(int in) { shared_task_id = in; } inline bool HasFreeSharedTaskSlot() const { return shared_task_id == 0; } + inline void SetSharedTask(SharedTask *in) { m_shared_task = in; } + inline SharedTask *GetSharedTask() const { return m_shared_task; } private: void ClearVars(bool iAll = false); diff --git a/world/shared_tasks.cpp b/world/shared_tasks.cpp index a9b689764..41d193b71 100644 --- a/world/shared_tasks.cpp +++ b/world/shared_tasks.cpp @@ -13,8 +13,19 @@ void SharedTaskManager::HandleTaskRequest(ServerPacket *pack) if (!pack) return; + /* + * Things done in zone: + * Verified we were requesting a shared task + * Verified leader has a slot available + * Verified leader met level reqs + * Verified repeatable or not completed (not doing that here?) + * Verified leader doesn't have a lock out + * Verified the group/raid met min/max player counts + */ + char tmp_str[64] = { 0 }; int task_id = pack->ReadUInt32(); + int npc_id = pack->ReadUInt32(); pack->ReadString(tmp_str); std::string leader_name = tmp_str; int player_count = pack->ReadUInt32(); @@ -30,8 +41,9 @@ void SharedTaskManager::HandleTaskRequest(ServerPacket *pack) auto pc = client_list.FindCharacter(leader_name.c_str()); if (pc) { // failure TODO: appropriate message - auto pack = new ServerPacket(ServerOP_TaskReject, leader_name.size() + 1 + 4); + auto pack = new ServerPacket(ServerOP_TaskReject, leader_name.size() + 1 + 8); pack->WriteUInt32(0); // string ID or just generic fail message + pack->WriteUInt32(npc_id); pack->WriteString(leader_name.c_str()); zoneserver_list.SendPacket(pc->zone(), pc->instance(), pack); safe_delete(pack); @@ -45,8 +57,9 @@ void SharedTaskManager::HandleTaskRequest(ServerPacket *pack) auto pc = client_list.FindCharacter(leader_name.c_str()); if (pc) { // failure TODO: appropriate message - auto pack = new ServerPacket(ServerOP_TaskReject, leader_name.size() + 1 + 4); + auto pack = new ServerPacket(ServerOP_TaskReject, leader_name.size() + 1 + 8); pack->WriteUInt32(0); // string ID or just generic fail message + pack->WriteUInt32(npc_id); pack->WriteString(leader_name.c_str()); zoneserver_list.SendPacket(pc->zone(), pc->instance(), pack); safe_delete(pack); @@ -66,13 +79,17 @@ void SharedTaskManager::HandleTaskRequest(ServerPacket *pack) if (players.empty()) { // send instant success to leader SerializeBuffer buf(10); - buf.WriteInt32(id); // task's ID + buf.WriteInt32(id); // shared task's ID + buf.WriteInt32(task_id); // ID of the task's data + buf.WriteInt32(npc_id); // NPC we're requesting from buf.WriteString(leader_name); // leader's name + buf.WriteInt32(0); // member list minus leader auto pack = new ServerPacket(ServerOP_TaskGrant, buf); zoneserver_list.SendPacket(cle_leader->zone(), cle_leader->instance(), pack); safe_delete(pack); - tasks.erase(ret.first); + + task.SetCLESharedTasks(); return; } @@ -83,8 +100,9 @@ void SharedTaskManager::HandleTaskRequest(ServerPacket *pack) // make sure we don't have a shared task already if (!cle->HasFreeSharedTaskSlot()) { // failure TODO: appropriate message - auto pack = new ServerPacket(ServerOP_TaskReject, leader_name.size() + 1 + 4); + auto pack = new ServerPacket(ServerOP_TaskReject, leader_name.size() + 1 + 8); pack->WriteUInt32(0); // string ID or just generic fail message + pack->WriteUInt32(npc_id); pack->WriteString(leader_name.c_str()); zoneserver_list.SendPacket(cle_leader->zone(), cle_leader->instance(), pack); safe_delete(pack); @@ -95,8 +113,9 @@ void SharedTaskManager::HandleTaskRequest(ServerPacket *pack) // make sure our level is right if (!AppropriateLevel(task_id, cle->level())) { // failure TODO: appropriate message - auto pack = new ServerPacket(ServerOP_TaskReject, leader_name.size() + 1 + 4); + auto pack = new ServerPacket(ServerOP_TaskReject, leader_name.size() + 1 + 8); pack->WriteUInt32(0); // string ID or just generic fail message + pack->WriteUInt32(npc_id); pack->WriteString(leader_name.c_str()); zoneserver_list.SendPacket(cle_leader->zone(), cle_leader->instance(), pack); safe_delete(pack); @@ -108,8 +127,9 @@ void SharedTaskManager::HandleTaskRequest(ServerPacket *pack) int expires = cle->GetTaskLockoutExpire(task_id); if ((expires - Timer::GetCurrentTime()) >= 0) { // failure TODO: appropriate message, we need to send the timestamp here - auto pack = new ServerPacket(ServerOP_TaskReject, leader_name.size() + 1 + 4); + auto pack = new ServerPacket(ServerOP_TaskReject, leader_name.size() + 1 + 8); pack->WriteUInt32(0); // string ID or just generic fail message + pack->WriteUInt32(npc_id); pack->WriteString(leader_name.c_str()); zoneserver_list.SendPacket(cle_leader->zone(), cle_leader->instance(), pack); safe_delete(pack); @@ -121,7 +141,21 @@ void SharedTaskManager::HandleTaskRequest(ServerPacket *pack) task.AddMember(name, cle); } } - // TODO: what do now! + + // fire off to zone we're done! + SerializeBuffer buf(10 + 10 * players.size()); + buf.WriteInt32(id); // shared task's ID + buf.WriteInt32(task_id); // ID of the task's data + buf.WriteInt32(npc_id); // NPC we're requesting from + buf.WriteString(leader_name); // leader's name + task.SerializeMembers(buf, false); // everyone but leader + + auto reply = new ServerPacket(ServerOP_TaskGrant, buf); + zoneserver_list.SendPacket(cle_leader->zone(), cle_leader->instance(), reply); + safe_delete(reply); + + task.SetCLESharedTasks(); + return; } /* @@ -171,6 +205,13 @@ bool SharedTaskManager::AppropriateLevel(int id, int level) const return true; } +/* + * This will check if any tasks have expired + */ +void SharedTaskManager::Process() +{ +} + /* * 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 @@ -187,3 +228,35 @@ void SharedTask::MemberLeftGame(ClientListEntry *cle) it->cle = nullptr; } +/* + * Serializes Members into the SerializeBuffer + * Starts with count then followed by names null-termed + * In the future this will include monster mission shit + */ +void SharedTask::SerializeMembers(SerializeBuffer &buf, bool include_leader) const +{ + buf.WriteInt32(include_leader ? members.size() : members.size() - 1); + + for (auto && m : members) { + if (!include_leader && m.leader) + continue; + + buf.WriteString(m.name); + // TODO: live also has monster mission class choice in here + } +} + +/* + * This sets the CLE's quick look up shared task stuff + */ +void SharedTask::SetCLESharedTasks() +{ + for (auto &&m : members) { + if (m.cle == nullptr) // shouldn't happen .... + continue; + + m.cle->SetSharedTask(this); + m.cle->SetCurrentSharedTaskID(id); + } +} + diff --git a/world/shared_tasks.h b/world/shared_tasks.h index dadf76050..7ef56d040 100644 --- a/world/shared_tasks.h +++ b/world/shared_tasks.h @@ -13,6 +13,7 @@ struct SharedTaskMember { std::string name; ClientListEntry *cle; bool leader; + // TODO: monster mission stuff SharedTaskMember() : leader(false), cle(nullptr) {} SharedTaskMember(std::string name, ClientListEntry *cle, bool leader) : name(name), cle(cle), leader(leader) {} }; @@ -32,6 +33,9 @@ public: void MemberLeftGame(ClientListEntry *cle); const std::string &GetLeaderName() const { return leader_name; } + void SerializeMembers(SerializeBuffer &buf, bool include_leader = true) const; + void SetCLESharedTasks(); + private: int id; // id we have in our map int task_id; // ID of the task we're on @@ -52,6 +56,8 @@ public: // IPC packet processing void HandleTaskRequest(ServerPacket *pack); + void Process(); + private: int GetNextID(); int next_id; diff --git a/zone/client.h b/zone/client.h index 9b40be60d..f6e8984af 100644 --- a/zone/client.h +++ b/zone/client.h @@ -229,15 +229,6 @@ struct ClientReward uint32 amount; }; -#define PENDING_TASK_TIMEOUT 60000 -struct PendingSharedTask { - int id; - int task_master_id; - Timer timeout; // so if we take a very long time to get messages back from world, we time out and fail - std::vector members; // members ahh I guess if verification takes a long time raid could change? - PendingSharedTask() : id(0), task_master_id(0) {} -}; - class ClientFactory { public: Client *MakeClient(std::shared_ptr ieqs); @@ -1035,7 +1026,7 @@ public: inline bool IsTaskEnabled(int TaskID) { return (taskstate ? taskstate->IsTaskEnabled(TaskID) : false); } 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 AssignSharedTask(int TaskID, int NPCID, int id, std::vector &members) { if (taskstate) taskstate->AcceptNewSharedTask(this, TaskID, NPCID, id, members); } 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); } @@ -1055,14 +1046,6 @@ public: 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; } - inline int GetPendingTaskID() const { return pending_task.id; } - inline int GetPendingTaskMasterID() const { return pending_task.task_master_id; } - inline void StartPendingTimer() { pending_task.timeout.Start(PENDING_TASK_TIMEOUT); } - inline void ResetPendingTask() { pending_task.id = 0; pending_task.task_master_id = 0; pending_task.timeout.Disable(); pending_task.members.clear(); } - inline void PendingTaskAddMember(const char *name) { pending_task.members.push_back(name); } - inline const EQEmu::versions::ClientVersion ClientVersion() const { return m_ClientVersion; } inline const uint32 ClientVersionBit() const { return m_ClientVersionBit; } inline void SetClientVersion(EQEmu::versions::ClientVersion client_version) { m_ClientVersion = client_version; } @@ -1586,7 +1569,6 @@ private: std::set zone_flags; ClientTaskState *taskstate; - PendingSharedTask pending_task; int TotalSecondsPlayed; //Anti Spam Stuff diff --git a/zone/client_process.cpp b/zone/client_process.cpp index e1a4a80ca..5c750f03a 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -159,11 +159,6 @@ bool Client::Process() { if (TaskPeriodic_Timer.Check() && taskstate) taskstate->TaskPeriodicChecks(this); - if (pending_task.timeout.Check(false)) { - Message(13, "Shared task timed out."); - ResetPendingTask(); - } - if (linkdead_timer.Check()) { LeaveGroup(); Save(); diff --git a/zone/tasks.cpp b/zone/tasks.cpp index d4b905e06..dcdc577c5 100644 --- a/zone/tasks.cpp +++ b/zone/tasks.cpp @@ -3429,8 +3429,6 @@ void ClientTaskState::PendSharedTask(Client *c, int TaskID, int NPCID, bool enfo player_count = raid->RaidCount(); } - // TODO: check task lockouts I guess it's simpler to require everyone to be in zone so we can verify lockouts ... - if (!EQEmu::ValueWithin(player_count, task->min_players, task->max_players)) { if (player_count < task->min_players) c->Message_StringID(13, TASK_REJECT_MIN_COUNT); @@ -3442,6 +3440,7 @@ void ClientTaskState::PendSharedTask(Client *c, int TaskID, int NPCID, bool enfo // 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.WriteInt32(NPCID); // NPC we're requesting from buf.WriteString(c->GetName()); // leader name buf.WriteInt32(player_count - 1); // count, not leader if (group) { @@ -3562,7 +3561,7 @@ void ClientTaskState::PendSharedTask(Client *c, int TaskID, int NPCID, bool enfo } -void ClientTaskState::AcceptNewSharedTask(Client *c, int TaskID, int NPCID, int id) +void ClientTaskState::AcceptNewSharedTask(Client *c, int TaskID, int NPCID, int id, std::vector &members) { } diff --git a/zone/tasks.h b/zone/tasks.h index b679b45e2..f7867364c 100644 --- a/zone/tasks.h +++ b/zone/tasks.h @@ -148,7 +148,7 @@ public: int GetTaskActivityDoneCountFromTaskID(int TaskID, int ActivityID); int GetTaskStartTime(TaskType type, int index); void AcceptNewTask(Client *c, int TaskID, int NPCID, bool enforce_level_requirement = false); - void AcceptNewSharedTask(Client *c, int TaskID, int NPCID, int id); + void AcceptNewSharedTask(Client *c, int TaskID, int NPCID, int id, std::vector &members); void PendSharedTask(Client *c, int TaskID, int NPCID, bool enforce_level_requirement = false); void FailTask(Client *c, int TaskID); int TaskTimeLeft(int TaskID); diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index 3662d9cff..21a7aec6a 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -1945,22 +1945,33 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) case ServerOP_TaskGrant: { int id = pack->ReadUInt32(); + int task_id = pack->ReadUInt32(); + int taskmaster_id = pack->ReadUInt32(); char name[64] = { 0 }; pack->ReadString(name); auto client = entity_list.GetClientByName(name); - if (client && client->HasPendingTask()) // if they don't have it, ignore it I guess :P - client->AssignSharedTask(client->GetPendingTaskID(), client->GetPendingTaskMasterID(), id); + if (client) { // guess we just do nothing if they're not here + std::vector members; + int count = pack->ReadUInt32(); + for (int i = 0; i < count; ++i) { + pack->ReadString(name); + members.push_back(name); + } + client->AssignSharedTask(task_id, taskmaster_id, id, members); + } else { + // TODO: something failed, tell world to clean up + } break; } 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(); + int taskmaster_id = pack->ReadUInt32(); char name[64] = { 0 }; pack->ReadString(name); auto client = entity_list.GetClientByName(name); - if (client && client->HasPendingTask()) { - client->ResetPendingTask(); + if (client) { if (message == 0) client->Message(13, "Shared task assignment has failed."); else if (message > 0)