eq2go/old/WorldServer/achievements/achievements.hpp
2025-08-06 19:00:30 -05:00

575 lines
18 KiB
C++

// Copyright (C) 2007 EQ2EMulator Development Team - GPL v3 License
#pragma once
#include <map>
#include <vector>
#include <string>
#include <shared_mutex>
#include <cassert>
#include <cstring>
#include "../../common/types.hpp"
#include "../../common/log.hpp"
#include "../../common/config_reader.hpp"
#include "../Items/Items.h"
using namespace std;
// Forward declarations
extern ConfigReader configReader;
extern class MasterAchievementList master_achievement_list;
// Structure representing achievement reward data
struct AchievementRewards
{
int32 achievement_id; // ID of the associated achievement
string reward; // Description of the reward
};
// Structure representing achievement requirement data
struct AchievementRequirements
{
int32 achievement_id; // ID of the associated achievement
string name; // Name/description of the requirement
int32 qty_req; // Quantity required to fulfill this requirement
};
// Structure representing achievement update item data
struct AchievementUpdateItems
{
int32 achievement_id; // ID of the associated achievement
int32 item_update; // Update value for the item
};
// Main achievement class representing a single achievement with all its data
class Achievement
{
public:
// Default constructor - initializes all members to default values
Achievement();
// Copy constructor - creates deep copy of another achievement
Achievement(Achievement *in);
// Destructor - cleans up dynamically allocated requirement and reward structures
virtual ~Achievement();
// Setters for achievement properties
void SetID(int32 id) { this->id = id; }
void SetTitle(const char *title) { strncpy(this->title, title, sizeof(this->title)); }
void SetUncompletedText(const char *uncompleted_text) { strncpy(this->uncompleted_text, uncompleted_text, sizeof(this->uncompleted_text)); }
void SetCompletedText(const char *completed_text) { strncpy(this->completed_text, completed_text, sizeof(this->completed_text)); }
void SetCategory(const char *category) { strncpy(this->category, category, sizeof(this->category)); }
void SetExpansion(const char *expansion) { strncpy(this->expansion, expansion, sizeof(this->expansion)); }
void SetIcon(int16 icon) { this->icon = icon; }
void SetPointValue(int32 point_value) { this->point_value = point_value; }
void SetQtyReq(int32 qty_req) { this->qty_req = qty_req; }
void SetHide(bool hide) { this->hide = hide; }
void SetUnknown3a(int32 unknown3a) { this->unknown3a = unknown3a; }
void SetUnknown3b(int32 unknown3b) { this->unknown3b = unknown3b; }
// Adds a requirement structure to this achievement
void AddAchievementRequirement(struct AchievementRequirements *requirement);
// Adds a reward structure to this achievement
void AddAchievementReward(struct AchievementRewards *reward);
// Getters for achievement properties
int32 GetID() { return id; }
const char * GetTitle() { return title; }
const char * GetUncompletedText() { return uncompleted_text; }
const char * GetCompletedText() { return completed_text; }
const char * GetCategory() { return category; }
const char * GetExpansion() { return expansion; }
int16 GetIcon() { return icon; }
int32 GetPointValue() { return point_value; }
int32 GetQtyReq() { return qty_req; }
bool GetHide() { return hide; }
int32 GetUnknown3a() { return unknown3a; }
int32 GetUnknown3b() { return unknown3b; }
vector<struct AchievementRequirements *> * GetRequirements() { return &requirements; }
vector<struct AchievementRewards *> * GetRewards() { return &rewards; }
private:
int32 id; // Unique identifier for this achievement
char title[512]; // Display title of the achievement
char uncompleted_text[512]; // Text shown when achievement is not completed
char completed_text[512]; // Text shown when achievement is completed
char category[32]; // Category this achievement belongs to
char expansion[32]; // Expansion pack this achievement is from
int16 icon; // Icon ID for display
int32 point_value; // Point value awarded for completion
int32 qty_req; // Base quantity requirement
bool hide; // Whether this achievement should be hidden
int32 unknown3a; // Unknown field for future use
int32 unknown3b; // Unknown field for future use
vector<struct AchievementRequirements *> requirements; // List of requirements
vector<struct AchievementRewards *> rewards; // List of rewards
};
// Class representing an achievement update with completion data
class AchievementUpdate
{
public:
// Default constructor - initializes members to default values
AchievementUpdate();
// Copy constructor - creates deep copy of another achievement update
AchievementUpdate(AchievementUpdate *in);
// Destructor - cleans up dynamically allocated update item structures
virtual ~AchievementUpdate();
// Setters for update properties
void SetID(int32 id) { this->id = id; }
void SetCompletedDate(int32 completed_date) { this->completed_date = completed_date; }
// Adds an update item structure to this achievement update
void AddAchievementUpdateItems(struct AchievementUpdateItems *update_item);
// Getters for update properties
int32 GetID() { return id; }
int32 GetCompletedDate() { return completed_date; }
vector<struct AchievementUpdateItems *> * GetUpdateItems() { return &update_items; }
private:
int32 id; // Achievement ID this update refers to
int32 completed_date; // Timestamp when achievement was completed
vector<struct AchievementUpdateItems *> update_items; // List of update items
};
// Master list managing all achievements in the system with thread safety
class MasterAchievementList
{
public:
// Constructor - initializes member variables and mutex
MasterAchievementList();
// Destructor - cleans up all achievements and resources
virtual ~MasterAchievementList();
// Adds an achievement to the master list (thread-safe)
bool AddAchievement(Achievement *achievement);
// Retrieves an achievement by ID (thread-safe)
Achievement * GetAchievement(int32 achievement_id);
// Removes all achievements from the list (thread-safe)
void ClearAchievements();
// Returns the number of achievements in the list (thread-safe)
int32 Size();
// Creates the master achievement list packet for client communication
void CreateMasterAchievementListPacket();
// Returns the serialized achievement packet, null if not created
EQ2Packet * GetAchievementPacket() { return m_packetsCreated ? masterPacket : nullptr; }
EQ2Packet *masterPacket; // Serialized packet data for client
private:
std::shared_mutex mutex_achievements; // Thread safety for achievement operations
map<int32, Achievement *> achievements; // Map of achievement ID to achievement object
bool m_packetsCreated; // Flag indicating if packet has been created
};
// Player-specific achievement list without thread safety requirements
class PlayerAchievementList
{
public:
// Constructor - no special initialization needed
PlayerAchievementList();
// Destructor - cleans up all player achievements
virtual ~PlayerAchievementList();
// Adds an achievement to the player's list
bool AddAchievement(Achievement *achievement);
// Retrieves an achievement by ID from player's list
Achievement * GetAchievement(int32 achievement_id);
// Removes all achievements from player's list
void ClearAchievements();
// Returns the number of achievements in player's list
int32 Size();
// Returns direct access to the achievements map
map<int32, Achievement *> * GetAchievements() { return &achievements; }
private:
map<int32, Achievement *> achievements; // Map of player's achievements
};
// Player-specific achievement update list for tracking completion progress
class PlayerAchievementUpdateList
{
public:
// Constructor - no special initialization needed
PlayerAchievementUpdateList();
// Destructor - cleans up all achievement updates
virtual ~PlayerAchievementUpdateList();
// Adds an achievement update to the player's list
bool AddAchievementUpdate(AchievementUpdate *achievement_update);
// Removes all achievement updates from player's list
void ClearAchievementUpdates();
// Returns the number of achievement updates in player's list
int32 Size();
// Returns direct access to the achievement updates map
map<int32, AchievementUpdate *> * GetAchievementUpdates() { return &achievement_updates; }
private:
map<int32, AchievementUpdate *> achievement_updates; // Map of player's achievement updates
};
// Implementation of Achievement class methods
Achievement::Achievement()
{
id = 0;
memset(title, 0, sizeof(title));
memset(uncompleted_text, 0, sizeof(uncompleted_text));
memset(completed_text, 0, sizeof(completed_text));
memset(category, 0, sizeof(category));
memset(expansion, 0, sizeof(expansion));
icon = 0;
point_value = 0;
qty_req = 0;
hide = false;
unknown3a = 0;
unknown3b = 0;
}
Achievement::Achievement(Achievement *in)
{
vector<struct AchievementRequirements *> *requirements_in;
vector<struct AchievementRewards *> *rewards_in;
vector<struct AchievementRequirements *>::iterator itr;
vector<struct AchievementRewards *>::iterator itr2;
struct AchievementRequirements *achievement_requirement;
struct AchievementRewards *achievement_reward;
assert(in);
id = in->GetID();
strncpy(title, in->GetTitle(), sizeof(title));
strncpy(uncompleted_text, in->GetUncompletedText(), sizeof(uncompleted_text));
strncpy(completed_text, in->GetCompletedText(), sizeof(completed_text));
strncpy(category, in->GetCategory(), sizeof(category));
strncpy(expansion, in->GetExpansion(), sizeof(expansion));
icon = in->GetIcon();
point_value = in->GetPointValue();
qty_req = in->GetQtyReq();
hide = in->GetHide();
unknown3a = in->GetUnknown3a();
unknown3b = in->GetUnknown3b();
// Deep copy requirements
requirements_in = in->GetRequirements();
for (itr = requirements_in->begin(); itr != requirements_in->end(); itr++) {
achievement_requirement = new struct AchievementRequirements;
achievement_requirement->achievement_id = (*itr)->achievement_id;
achievement_requirement->name = (*itr)->name;
achievement_requirement->qty_req = (*itr)->qty_req;
requirements.push_back(achievement_requirement);
}
// Deep copy rewards
rewards_in = in->GetRewards();
for (itr2 = rewards_in->begin(); itr2 != rewards_in->end(); itr2++) {
achievement_reward = new struct AchievementRewards;
achievement_reward->achievement_id = (*itr2)->achievement_id;
achievement_reward->reward = (*itr2)->reward;
rewards.push_back(achievement_reward);
}
}
Achievement::~Achievement()
{
vector<struct AchievementRequirements *>::iterator itr;
vector<struct AchievementRewards *>::iterator itr2;
// Clean up all requirements
for (itr = requirements.begin(); itr != requirements.end(); itr++)
delete *itr;
// Clean up all rewards
for (itr2 = rewards.begin(); itr2 != rewards.end(); itr2++)
delete *itr2;
}
void Achievement::AddAchievementRequirement(struct AchievementRequirements *requirement)
{
assert(requirement);
requirements.push_back(requirement);
}
void Achievement::AddAchievementReward(struct AchievementRewards *reward)
{
assert(reward);
rewards.push_back(reward);
}
// Implementation of AchievementUpdate class methods
AchievementUpdate::AchievementUpdate()
{
id = 0;
completed_date = 0;
}
AchievementUpdate::AchievementUpdate(AchievementUpdate *in)
{
vector<struct AchievementUpdateItems *> *items_in;
vector<struct AchievementUpdateItems *>::iterator itr;
struct AchievementUpdateItems *items;
assert(in);
id = in->GetID();
completed_date = in->GetCompletedDate();
// Deep copy update items
items_in = in->GetUpdateItems();
for (itr = items_in->begin(); itr != items_in->end(); itr++) {
items = new struct AchievementUpdateItems;
items->achievement_id = (*itr)->achievement_id;
items->item_update = (*itr)->item_update;
update_items.push_back(items);
}
}
AchievementUpdate::~AchievementUpdate()
{
vector<struct AchievementUpdateItems *>::iterator itr;
// Clean up all update items
for (itr = update_items.begin(); itr != update_items.end(); itr++)
delete *itr;
}
void AchievementUpdate::AddAchievementUpdateItems(struct AchievementUpdateItems *update_item)
{
assert(update_item);
update_items.push_back(update_item);
}
// Implementation of MasterAchievementList class methods
MasterAchievementList::MasterAchievementList()
{
m_packetsCreated = false;
masterPacket = nullptr;
}
MasterAchievementList::~MasterAchievementList()
{
ClearAchievements();
}
bool MasterAchievementList::AddAchievement(Achievement *achievement)
{
bool ret = false;
assert(achievement);
// Use unique_lock for write operations
std::unique_lock<std::shared_mutex> lock(mutex_achievements);
if (achievements.count(achievement->GetID()) == 0) {
achievements[achievement->GetID()] = achievement;
ret = true;
}
return ret;
}
Achievement * MasterAchievementList::GetAchievement(int32 achievement_id)
{
Achievement *achievement = nullptr;
// Use shared_lock for read operations
std::shared_lock<std::shared_mutex> lock(mutex_achievements);
if (achievements.count(achievement_id) > 0)
achievement = achievements[achievement_id];
return achievement;
}
void MasterAchievementList::ClearAchievements()
{
map<int32, Achievement *>::iterator itr;
// Use unique_lock for write operations
std::unique_lock<std::shared_mutex> lock(mutex_achievements);
for (itr = achievements.begin(); itr != achievements.end(); itr++)
delete itr->second;
achievements.clear();
}
int32 MasterAchievementList::Size()
{
// Use shared_lock for read operations
std::shared_lock<std::shared_mutex> lock(mutex_achievements);
return achievements.size();
}
void MasterAchievementList::CreateMasterAchievementListPacket()
{
map<int32, Achievement *>::iterator itr;
Achievement *achievement;
vector<AchievementRequirements *> *requirements = nullptr;
vector<AchievementRequirements *>::iterator itr2;
AchievementRequirements *requirement;
vector<AchievementRewards *> *rewards = nullptr;
vector<AchievementRewards *>::iterator itr3;
AchievementRewards *reward;
PacketStruct *packet;
int16 i = 0;
int16 j = 0;
int16 k = 0;
int16 version = 1096;
// Get packet structure for achievement data
if (!(packet = configReader.getStruct("WS_CharacterAchievements", version))) {
return;
}
// Set up packet array for all achievements
packet->setArrayLengthByName("num_achievements", achievements.size());
for (itr = achievements.begin(); itr != achievements.end(); itr++) {
achievement = itr->second;
// Set basic achievement data
packet->setArrayDataByName("achievement_id", achievement->GetID(), i);
packet->setArrayDataByName("title", achievement->GetTitle(), i);
packet->setArrayDataByName("uncompleted_text", achievement->GetUncompletedText(), i);
packet->setArrayDataByName("completed_text", achievement->GetCompletedText(), i);
packet->setArrayDataByName("category", achievement->GetCategory(), i);
packet->setArrayDataByName("expansion", achievement->GetExpansion(), i);
packet->setArrayDataByName("icon", achievement->GetIcon(), i);
packet->setArrayDataByName("point_value", achievement->GetPointValue(), i);
packet->setArrayDataByName("qty_req", achievement->GetQtyReq(), i);
packet->setArrayDataByName("hide_achievement", achievement->GetHide(), i);
packet->setArrayDataByName("unknown3", achievement->GetUnknown3a(), i);
packet->setArrayDataByName("unknown3", achievement->GetUnknown3b(), i);
requirements = achievement->GetRequirements();
rewards = achievement->GetRewards();
j = 0;
k = 0;
// Set achievement requirements
packet->setSubArrayLengthByName("num_items", requirements->size(), i, j);
for (itr2 = requirements->begin(); itr2 != requirements->end(); itr2++) {
requirement = *itr2;
packet->setSubArrayDataByName("item_name", requirement->name.c_str(), i, j);
packet->setSubArrayDataByName("item_qty_req", requirement->qty_req, i, j);
j++;
}
// Set achievement rewards
packet->setSubArrayLengthByName("num_rewards", achievement->GetRewards()->size(), i, k);
for (itr3 = rewards->begin(); itr3 != rewards->end(); itr3++) {
reward = *itr3;
packet->setSubArrayDataByName("reward_item", reward->reward.c_str(), i, k);
k++;
}
i++;
}
// Serialize and create final packet
EQ2Packet* data = packet->serialize();
masterPacket = new EQ2Packet(OP_ClientCmdMsg, data->pBuffer, data->size);
delete packet;
delete data;
m_packetsCreated = true;
}
// Implementation of PlayerAchievementList class methods
PlayerAchievementList::PlayerAchievementList()
{
}
PlayerAchievementList::~PlayerAchievementList()
{
ClearAchievements();
}
bool PlayerAchievementList::AddAchievement(Achievement *achievement)
{
assert(achievement);
if (achievements.count(achievement->GetID()) == 0) {
achievements[achievement->GetID()] = achievement;
return true;
}
return false;
}
Achievement * PlayerAchievementList::GetAchievement(int32 achievement_id)
{
if (achievements.count(achievement_id) > 0)
return achievements[achievement_id];
return nullptr;
}
void PlayerAchievementList::ClearAchievements()
{
map<int32, Achievement *>::iterator itr;
for (itr = achievements.begin(); itr != achievements.end(); itr++)
delete itr->second;
achievements.clear();
}
int32 PlayerAchievementList::Size()
{
return achievements.size();
}
// Implementation of PlayerAchievementUpdateList class methods
PlayerAchievementUpdateList::PlayerAchievementUpdateList()
{
}
PlayerAchievementUpdateList::~PlayerAchievementUpdateList()
{
ClearAchievementUpdates();
}
bool PlayerAchievementUpdateList::AddAchievementUpdate(AchievementUpdate *update)
{
assert(update);
if (achievement_updates.count(update->GetID()) == 0) {
achievement_updates[update->GetID()] = update;
return true;
}
return false;
}
void PlayerAchievementUpdateList::ClearAchievementUpdates()
{
map<int32, AchievementUpdate *>::iterator itr;
for (itr = achievement_updates.begin(); itr != achievement_updates.end(); itr++)
delete itr->second;
achievement_updates.clear();
}
int32 PlayerAchievementUpdateList::Size()
{
return achievement_updates.size();
}