diff --git a/common/servertalk.h b/common/servertalk.h index ce390bcb6..2e68373a1 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -157,6 +157,7 @@ #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 @@ -1333,6 +1334,14 @@ struct UCSServerStatus_Struct { }; }; +// shared task related communications +// error constants +#define TASKJOINOOZ_CAN 0 +#define TASKJOINOOZ_NOTASK 1 +#define TASKJOINOOZ_HAVEONE 2 +#define TASKJOINOOZ_LEVEL 3 +#define TASKJOINOOZ_TIMER 4 + #pragma pack() #endif diff --git a/world/shared_tasks.cpp b/world/shared_tasks.cpp index abe341d3d..ee8fdbbd1 100644 --- a/world/shared_tasks.cpp +++ b/world/shared_tasks.cpp @@ -83,3 +83,52 @@ void SharedTaskManager::HandleTaskRequest(ServerPacket *pack) } } +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); +} + +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 + + 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; +} + diff --git a/world/shared_tasks.h b/world/shared_tasks.h index 48722c377..620db404d 100644 --- a/world/shared_tasks.h +++ b/world/shared_tasks.h @@ -19,13 +19,16 @@ public: SharedTask(int id, int task_id) : id(id), task_id(task_id), missing_count(0) {} ~SharedTask() {} - void AddMember(std::string name, bool leader = false) { members.push_back({name, leader}); } + 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 + 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; }; @@ -36,6 +39,7 @@ public: // IPC packet processing void HandleTaskRequest(ServerPacket *pack); + void HandleTaskRequestReply(ServerPacket *pack); private: inline int GetNextID() { return ++next_id; } diff --git a/world/zoneserver.cpp b/world/zoneserver.cpp index e3d43669e..fc7e13743 100644 --- a/world/zoneserver.cpp +++ b/world/zoneserver.cpp @@ -1352,6 +1352,11 @@ 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 7adba5214..c8c854d12 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1038,6 +1038,7 @@ 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); } diff --git a/zone/tasks.cpp b/zone/tasks.cpp index 5a68f1fc7..f42740f57 100644 --- a/zone/tasks.cpp +++ b/zone/tasks.cpp @@ -3455,6 +3455,7 @@ void ClientTaskState::PendSharedTask(Client *c, int TaskID, int NPCID, bool enfo if (!task_state->HasSlotForTask(task)) { task_failed = true; c->Message_StringID(13, TASK_REJECT_GROUP_HAVE_ONE, c->GetName()); + break; } else { if (task->replay_group) { auto expires = client->GetTaskLockoutExpire(task->replay_group); @@ -3472,6 +3473,7 @@ void ClientTaskState::PendSharedTask(Client *c, int TaskID, int NPCID, bool enfo client->Message_StringID(13, TASK_REJECT_LOCKEDOUT_ME, days.c_str(), hours.c_str(), minutes.c_str()); + break; } } } @@ -3492,6 +3494,7 @@ void ClientTaskState::PendSharedTask(Client *c, int TaskID, int NPCID, bool enfo if (!task_state->HasSlotForTask(task)) { task_failed = true; c->Message_StringID(13, TASK_REJECT_RAID_HAVE_ONE, c->GetName()); + break; } else { if (task->replay_group) { auto expires = client->GetTaskLockoutExpire(task->replay_group); @@ -3509,6 +3512,7 @@ void ClientTaskState::PendSharedTask(Client *c, int TaskID, int NPCID, bool enfo client->Message_StringID(13, TASK_REJECT_LOCKEDOUT_ME, days.c_str(), hours.c_str(), minutes.c_str()); + break; } } } @@ -3518,8 +3522,10 @@ void ClientTaskState::PendSharedTask(Client *c, int TaskID, int NPCID, bool enfo } } - if (task_failed) // we already yelled at them + if (task_failed) { // we already yelled at them + c->ResetPendingTask(); return; + } // so we've verified all the clients we can and didn't fail, time to pend and yell at world c->SetPendingTask(TaskID, NPCID); @@ -3542,6 +3548,75 @@ 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 b0a640353..ee3b61a87 100644 --- a/zone/tasks.h +++ b/zone/tasks.h @@ -267,6 +267,7 @@ 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); diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index ebd37ff78..34139990d 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -1970,7 +1970,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) pack->ReadString(name); auto client = entity_list.GetClientByName(name); if (client) { - // do check + client->HandleCanJoinSharedTask(task_id, id); } break; }