1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-05-06 02:37:47 +00:00
sapphire/src/world/Manager/AchievementMgr.h
2023-01-19 13:38:00 -03:00

122 lines
4 KiB
C++

#pragma once
#include <unordered_map>
#include <vector>
#include <algorithm>
#include <type_traits>
#include <Service.h>
#include <Common.h>
#include "Actor/Player.h"
namespace Sapphire::World::Manager
{
class AchievementMgr
{
public:
AchievementMgr() = default;
~AchievementMgr() = default;
bool cacheAchievements();
template < auto AchievementType >
void progressAchievementByType( Entity::Player& player, int32_t argument, uint32_t progressCount = 1 )
{
progressAchievement< decltype( AchievementType ), AchievementType >( player, argument, progressCount );
}
bool hasAchievementUnlocked( Entity::Player& player, uint32_t achievementId );
void unlockAchievement( Entity::Player& player, uint32_t achievementId );
/// <summary>
/// get a pair of current progress and maximum count for a given achievement ID
/// </summary>
/// <param name="player"></param>
/// <param name="achievementId"></param>
/// <returns>pair of current and maximum progress</returns>
std::pair< uint32_t, uint32_t > getAchievementDataById( Entity::Player& player, uint32_t achievementId );
private:
// map achievement IDs to achv data
using AchievementDetailCache = std::unordered_map< uint32_t, std::shared_ptr< Excel::ExcelStruct< Excel::Achievement > > >;
// map achievement keys (either type or union key:subtype) to achievement IDs
using AchievementKeyCache = std::unordered_map< uint32_t, std::vector< uint32_t > >;
AchievementDetailCache m_achievementDetailCacheMap;
AchievementKeyCache m_achievementKeyCacheMap;
std::shared_ptr< Excel::ExcelStruct< Excel::Achievement > > getAchievementDetail( uint32_t achvId ) const;
const std::vector< uint32_t >& getAchievementIdByType( Common::Achievement::Type type ) const;
const std::vector< uint32_t >& getAchievementIdByType( uint32_t type ) const;
Common::AchievementDataKey getKeyFromType( Common::Achievement::Type achvType, int32_t argument );
void handleLinkedAchievementsForId( Entity::Player& player, uint32_t achievementId );
template< typename AchievementTypeT, AchievementTypeT achievementType >
inline void progressAchievement( Entity::Player& player, int32_t argument, uint32_t progressCount );
};
template<>
inline void AchievementMgr::progressAchievement< Common::Achievement::Type, Common::Achievement::Type::General >( Entity::Player& player, int32_t subtype, uint32_t progressCount )
{
auto& achvDataList = player.getAchievementDataList();
auto dataKey = getKeyFromType( Common::Achievement::Type::General, subtype );
if( !achvDataList.count( dataKey.u32 ) )
achvDataList[ dataKey.u32 ] = 0;
achvDataList[ dataKey.u32 ] += progressCount;
const auto achvIdList = getAchievementIdByType( dataKey.u32 );
for( auto achvId : achvIdList )
{
if( hasAchievementUnlocked( player, achvId ) )
continue;
auto pAchv = getAchievementDetail( achvId );
if( !pAchv )
continue;
auto achvExdData = pAchv->data();
if( achvExdData.ConditionArg[ 1 ] <= achvDataList[ dataKey.u32 ] )
unlockAchievement( player, achvId );
}
}
template<>
inline void AchievementMgr::progressAchievement< Common::Achievement::Type, Common::Achievement::Type::Classjob >( Entity::Player& player, int32_t classJob, uint32_t level )
{
auto& achvDataList = player.getAchievementDataList();
auto dataKey = getKeyFromType( Common::Achievement::Type::Classjob, classJob );
if( !achvDataList.count( dataKey.u32 ) )
achvDataList[ dataKey.u32 ] = 0;
achvDataList[ dataKey.u32 ] = level;
const auto achvIdList = getAchievementIdByType( dataKey.u32 );
for( auto achvId : achvIdList )
{
if( hasAchievementUnlocked( player, achvId ) )
continue;
auto pAchv = getAchievementDetail( achvId );
if( !pAchv )
continue;
auto achvExdData = pAchv->data();
if( achvExdData.ConditionArg[ 1 ] <= achvDataList[ dataKey.u32 ] )
unlockAchievement( player, achvId );
}
}
}