More work on shared tasks

This commit is contained in:
Michael Cook (mackal) 2018-09-02 23:14:15 -04:00
parent 39544b4723
commit ea0a54ed60
11 changed files with 230 additions and 5 deletions

View File

@ -20,3 +20,30 @@ CREATE TABLE `task_replay_groups` (
`name` VARCHAR(128) NOT NULL DEFAULT '',
PRIMARY KEY(`id`)
);
CREATE TABLE `character_task_lockouts` (
`charid` INT NOT NULL,
`replay_group` INT NOT NULL,
`timestamp` INT NOT NULL,
PRIMARY KEY(`charid`, `replay_group`)
);
CREATE TABLE `shared_task_state` (
`id` INT NOT NULL,
`taskid` INT NOT NULL,
`acceptedtime` INT NOT NULL,
`locked` TINYINT NOT NULL DEFAULT '0',
PRIMARY KEY(`id`)
);
CREATE TABLE `shared_task_activities` (
`shared_id` INT NOT NULL,
`activity_id` INT NOT NULL,
`done_count` INT NOT NULL,
`completed` TINYINT,
PRIMARY KEY(`shared_id`, `activity_id`)
);
CREATE TABLE `shared_task_members` (
`shared_id` INT NOT NULL,
`charid` INT NOT NULL,
`name` VARCHAR(64) NOT NULL,
`leader` TINYINT,
PRIMARY KEY(`charid`)
);

View File

@ -15,6 +15,7 @@ SET(world_sources
login_server_list.cpp
net.cpp
queryserv.cpp
shared_tasks.cpp
ucs.cpp
web_interface.cpp
web_interface_eqw.cpp
@ -42,6 +43,7 @@ SET(world_headers
login_server_list.h
net.h
queryserv.h
shared_tasks.h
sof_char_create_data.h
ucs.h
web_interface.h

View File

@ -83,6 +83,7 @@ union semun {
#include "queryserv.h"
#include "web_interface.h"
#include "console.h"
#include "shared_tasks.h"
#include "../common/net/servertalk_server.h"
#include "../zone/data_bucket.h"
@ -103,6 +104,7 @@ bool holdzones = false;
const WorldConfig *Config;
EQEmuLogSys LogSys;
WebInterfaceList web_interface;
SharedTaskManager shared_tasks;
void CatchSignal(int sig_num);
void CheckForServerScript(bool force_download = false);
@ -622,4 +624,4 @@ void CheckForServerScript(bool force_download) {
system("wget -N --no-check-certificate --quiet -O eqemu_server.pl https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/eqemu_server.pl");
#endif
}
}
}

85
world/shared_tasks.cpp Normal file
View File

@ -0,0 +1,85 @@
#include "shared_tasks.h"
#include "clientlist.h"
#include "cliententry.h"
#include "zonelist.h"
extern ClientList client_list;
extern ZSList zoneserver_list;
void SharedTaskManager::HandleTaskRequest(ServerPacket *pack)
{
if (!pack)
return;
char tmp_str[64] = { 0 };
int task_id = pack->ReadUInt32();
pack->ReadString(tmp_str);
std::string leader_name = tmp_str;
int missing_count = pack->ReadUInt32();
std::vector<std::string> missing_players;
for (int i = 0; i < missing_count; ++i) {
pack->ReadString(tmp_str);
missing_players.push_back(tmp_str);
}
int id = GetNextID();
auto ret = tasks.insert({id, {id, task_id}});
if (!ret.second) {
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
}
auto &task = ret.first->second;
task.AddMember(leader_name, true);
if (missing_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
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);
}
return;
}
task.SetMissingCount(missing_count);
for (auto &&name : missing_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);
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;
}
}
}

46
world/shared_tasks.h Normal file
View File

@ -0,0 +1,46 @@
#ifndef SHARED_TASKS_H
#define SHARED_TASKS_H
#include <unordered_map>
#include <vector>
#include <string>
#include "../common/servertalk.h"
struct SharedTaskMember {
std::string name;
bool leader;
SharedTaskMember() : leader(false) {}
SharedTaskMember(std::string name, bool leader) : name(name), 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() {}
void AddMember(std::string name, bool leader = false) { members.push_back({name, leader}); }
inline void SetMissingCount(int in) { missing_count = in; }
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::vector<SharedTaskMember> members;
};
class SharedTaskManager {
public:
SharedTaskManager() {}
~SharedTaskManager() {}
// IPC packet processing
void HandleTaskRequest(ServerPacket *pack);
private:
inline int GetNextID() { return ++next_id; }
int next_id;
std::unordered_map<int, SharedTask> tasks;
};
#endif /* !SHARED_TASKS_H */

View File

@ -35,6 +35,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "adventure_manager.h"
#include "ucs.h"
#include "queryserv.h"
#include "shared_tasks.h"
extern ClientList client_list;
extern GroupLFPList LFPGroupList;
@ -45,6 +46,7 @@ extern volatile bool UCSServerAvailable_;
extern AdventureManager adventure_manager;
extern UCSConnection UCSLink;
extern QueryServConnection QSLink;
extern SharedTaskManager shared_tasks;
void CatchSignal(int sig_num);
ZoneServer::ZoneServer(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection, EQ::Net::ConsoleServer *console)
@ -1344,6 +1346,11 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
cle->ProcessTellQueue();
break;
}
case ServerOP_TaskRequest:
{
shared_tasks.HandleTaskRequest(pack);
break;
}
default:
{
Log(Logs::Detail, Logs::World_Server, "Unknown ServerOPcode from zone 0x%04x, size %d", pack->opcode, pack->size);

View File

@ -234,6 +234,7 @@ 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<std::string> members; // members ahh I guess if verification takes a long time raid could change?
PendingSharedTask() : id(0), task_master_id(0) {}
};
@ -1035,6 +1036,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 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,10 +1056,12 @@ public:
inline int GetTaskLockoutExpire(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 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; }

View File

@ -161,8 +161,7 @@ bool Client::Process() {
if (pending_task.timeout.Check(false)) {
Message(13, "Shared task timed out.");
pending_task.id = 0;
pending_task.task_master_id = 0;
ResetPendingTask();
}
if (linkdead_timer.Check()) {

View File

@ -3444,6 +3444,11 @@ void ClientTaskState::PendSharedTask(Client *c, int TaskID, int NPCID, bool enfo
bool task_failed = false;
if (group) {
for (int i = 0; i < MAX_GROUP_MEMBERS; ++i) {
if (group->members[i] == c)
continue;
c->PendingTaskAddMember(group->membername[i]);
if (group->members[i] && group->members[i]->IsClient()) {
auto *client = group->members[i]->CastToClient();
auto *task_state = client->GetTaskState();
@ -3476,6 +3481,11 @@ void ClientTaskState::PendSharedTask(Client *c, int TaskID, int NPCID, bool enfo
}
} else if (raid) {
for (int i = 0; i < MAX_RAID_MEMBERS; ++i) {
if (raid->members[i].member == c)
continue;
c->PendingTaskAddMember(raid->members[i].membername);
if (raid->members[i].member) {
auto *client = raid->members[i].member;
auto *task_state = client->GetTaskState();
@ -3527,6 +3537,11 @@ void ClientTaskState::PendSharedTask(Client *c, int TaskID, int NPCID, bool enfo
delete pack;
}
void ClientTaskState::AcceptNewSharedTask(Client *c, int TaskID, int NPCID, int id)
{
}
void ClientTaskState::ProcessTaskProximities(Client *c, float X, float Y, float Z) {
float LastX = c->ProximityX();

View File

@ -265,7 +265,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, 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 FailTask(Client *c, int TaskID);
int TaskTimeLeft(int TaskID);

View File

@ -1936,6 +1936,44 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
}
break;
}
case ServerOP_TaskGrant:
{
int 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);
break;
}
case ServerOP_TaskReject:
{
int message = pack->ReadUInt32();
char name[64] = { 0 };
pack->ReadString(name);
auto client = entity_list.GetClientByName(name);
if (client && client->HasPendingTask()) {
client->ResetPendingTask();
if (message == 0)
client->Message(13, "Shared task assignment has failed.");
else if (message > 0)
client->Message_StringID(13, message);
// negative nothing I guess
}
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) {
// do check
}
break;
}
default: {
std::cout << " Unknown ZSopcode:" << (int)pack->opcode;
std::cout << " size:" << pack->size << std::endl;