mirror of
https://gitlab.com/Mr_Goldberg/goldberg_emulator.git
synced 2025-12-06 04:04:53 +01:00
Achievements support & inventory customization.
Added achievements support. Achievements are saved like real steam, see your inventory directory.(like items, uses a .json, tool can be used to dump achievements from steam public api). You will need a public apikey. (See https://steamcommunity.com/dev) Reworked item support to split inventory items to defined items.
This commit is contained in:
parent
46f2199cd2
commit
21e08ed220
9 changed files with 365 additions and 302 deletions
|
|
@ -38,14 +38,19 @@ public ISteamUserStats009,
|
|||
public ISteamUserStats010,
|
||||
public ISteamUserStats
|
||||
{
|
||||
public:
|
||||
static constexpr auto achievements_user_file = "achievements.json";
|
||||
|
||||
private:
|
||||
|
||||
Local_Storage *local_storage;
|
||||
Settings *settings;
|
||||
SteamCallResults *callback_results;
|
||||
class SteamCallBacks *callbacks;
|
||||
std::vector<struct Steam_Leaderboard> leaderboards;
|
||||
|
||||
std::string db_file_path;
|
||||
nlohmann::json achievements;
|
||||
nlohmann::json defined_achievements;
|
||||
nlohmann::json user_achievements;
|
||||
|
||||
unsigned int find_leaderboard(std::string name)
|
||||
{
|
||||
|
|
@ -58,9 +63,10 @@ unsigned int find_leaderboard(std::string name)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void load_achievements()
|
||||
void load_achievements_db()
|
||||
{
|
||||
std::ifstream achs_file(db_file_path);
|
||||
std::string file_path = Local_Storage::get_game_settings_path() + achievements_user_file;
|
||||
std::ifstream achs_file(file_path);
|
||||
|
||||
if (achs_file)
|
||||
{
|
||||
|
|
@ -73,26 +79,34 @@ void load_achievements()
|
|||
achs_file.read(&buffer[0], size);
|
||||
achs_file.close();
|
||||
|
||||
try
|
||||
{
|
||||
achievements = nlohmann::json::parse(buffer);
|
||||
}
|
||||
catch (std::exception &e)
|
||||
{
|
||||
PRINT_DEBUG("(Achievements): Error while parsing json: %s\n", e.what());
|
||||
try {
|
||||
defined_achievements = std::move(nlohmann::json::parse(buffer));
|
||||
} catch (std::exception &e) {
|
||||
PRINT_DEBUG("Error while parsing json: \"%s\" : %s\n", file_path.c_str(), e.what());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PRINT_DEBUG("Couldn't open file \"%s\" to read achievements definition\n", file_path.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void load_achievements()
|
||||
{
|
||||
local_storage->load_inventory_file(user_achievements, achievements_user_file);
|
||||
}
|
||||
|
||||
public:
|
||||
Steam_User_Stats(Settings *settings, Local_Storage *local_storage, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, std::string const&achievements_db_file_path):
|
||||
Steam_User_Stats(Settings *settings, Local_Storage *local_storage, class SteamCallResults *callback_results, class SteamCallBacks *callbacks):
|
||||
settings(settings),
|
||||
local_storage(local_storage),
|
||||
callback_results(callback_results),
|
||||
callbacks(callbacks),
|
||||
db_file_path(achievements_db_file_path)
|
||||
defined_achievements(nlohmann::json::object()),
|
||||
user_achievements(nlohmann::json::object())
|
||||
{
|
||||
load_achievements();
|
||||
load_achievements_db(); // achievements db
|
||||
load_achievements(); // achievements per user
|
||||
}
|
||||
|
||||
// Ask the server to send down this user's data and achievements for this game
|
||||
|
|
@ -118,7 +132,7 @@ bool GetStat( const char *pchName, int32 *pData )
|
|||
if (!pchName || !pData) return false;
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
|
||||
int read_data = local_storage->get_data(STATS_STORAGE_FOLDER, pchName, (char* )pData, sizeof(*pData));
|
||||
int read_data = local_storage->get_data(Local_Storage::stats_storage_folder, pchName, (char* )pData, sizeof(*pData));
|
||||
if (read_data == sizeof(int32))
|
||||
return true;
|
||||
|
||||
|
|
@ -131,7 +145,7 @@ bool GetStat( const char *pchName, float *pData )
|
|||
if (!pchName || !pData) return false;
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
|
||||
int read_data = local_storage->get_data(STATS_STORAGE_FOLDER, pchName, (char* )pData, sizeof(*pData));
|
||||
int read_data = local_storage->get_data(Local_Storage::stats_storage_folder, pchName, (char* )pData, sizeof(*pData));
|
||||
if (read_data == sizeof(int32))
|
||||
return true;
|
||||
|
||||
|
|
@ -146,7 +160,7 @@ bool SetStat( const char *pchName, int32 nData )
|
|||
if (!pchName) return false;
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
|
||||
return local_storage->store_data(STATS_STORAGE_FOLDER, pchName, (char* )&nData, sizeof(nData)) == sizeof(nData);
|
||||
return local_storage->store_data(Local_Storage::stats_storage_folder, pchName, (char* )&nData, sizeof(nData)) == sizeof(nData);
|
||||
}
|
||||
|
||||
bool SetStat( const char *pchName, float fData )
|
||||
|
|
@ -155,7 +169,7 @@ bool SetStat( const char *pchName, float fData )
|
|||
if (!pchName) return false;
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
|
||||
return local_storage->store_data(STATS_STORAGE_FOLDER, pchName, (char* )&fData, sizeof(fData)) == sizeof(fData);
|
||||
return local_storage->store_data(Local_Storage::stats_storage_folder, pchName, (char* )&fData, sizeof(fData)) == sizeof(fData);
|
||||
}
|
||||
|
||||
bool UpdateAvgRateStat( const char *pchName, float flCountThisSession, double dSessionLength )
|
||||
|
|
@ -164,7 +178,7 @@ bool UpdateAvgRateStat( const char *pchName, float flCountThisSession, double dS
|
|||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
|
||||
char data[sizeof(float) + sizeof(float) + sizeof(double)];
|
||||
int read_data = local_storage->get_data(STATS_STORAGE_FOLDER, pchName, (char* )data, sizeof(*data));
|
||||
int read_data = local_storage->get_data(Local_Storage::stats_storage_folder, pchName, (char* )data, sizeof(*data));
|
||||
float oldcount = 0;
|
||||
double oldsessionlength = 0;
|
||||
if (read_data == sizeof(data)) {
|
||||
|
|
@ -180,30 +194,28 @@ bool UpdateAvgRateStat( const char *pchName, float flCountThisSession, double dS
|
|||
memcpy(data + sizeof(float), &oldcount, sizeof(oldcount));
|
||||
memcpy(data + sizeof(float) * 2, &oldsessionlength, sizeof(oldsessionlength));
|
||||
|
||||
return local_storage->store_data(STATS_STORAGE_FOLDER, pchName, data, sizeof(data)) == sizeof(data);
|
||||
return local_storage->store_data(Local_Storage::stats_storage_folder, pchName, data, sizeof(data)) == sizeof(data);
|
||||
}
|
||||
|
||||
|
||||
// Achievement flag accessors
|
||||
bool GetAchievement( const char *pchName, bool *pbAchieved )
|
||||
{
|
||||
//TODO: these achievement functions need to load a list of achievements from somewhere, return false so that kf2 doesn't loop endlessly
|
||||
PRINT_DEBUG("GetAchievement %s\n", pchName);
|
||||
try
|
||||
{
|
||||
auto it = std::find_if(achievements.begin(), achievements.end(), [pchName]( nlohmann::json &item ) {
|
||||
return static_cast<std::string const&>(item["name"]) == pchName;
|
||||
if (pchName == nullptr) return false;
|
||||
|
||||
try {
|
||||
auto it = std::find_if(defined_achievements.begin(), defined_achievements.end(), [pchName]( nlohmann::json &item ) {
|
||||
return item["name"].get<std::string>() == pchName;
|
||||
});
|
||||
if (it != achievements.end())
|
||||
{
|
||||
*pbAchieved = it.value()["earned"];
|
||||
auto ach = user_achievements.find(pchName);
|
||||
if (it != defined_achievements.end() && ach != user_achievements.end()) {
|
||||
if(pbAchieved != nullptr) *pbAchieved = (*ach)["earned"];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
} catch (...) {}
|
||||
|
||||
}
|
||||
if (pbAchieved != nullptr)* pbAchieved = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -211,21 +223,18 @@ bool GetAchievement( const char *pchName, bool *pbAchieved )
|
|||
bool SetAchievement( const char *pchName )
|
||||
{
|
||||
PRINT_DEBUG("SetAchievement %s\n", pchName);
|
||||
try
|
||||
{
|
||||
auto it = std::find_if(achievements.begin(), achievements.end(), [pchName](nlohmann::json& item) {
|
||||
return static_cast<std::string const&>(item["name"]) == pchName;
|
||||
if (pchName == nullptr) return false;
|
||||
|
||||
try {
|
||||
auto it = std::find_if(defined_achievements.begin(), defined_achievements.end(), [pchName](nlohmann::json& item) {
|
||||
return item["name"].get<std::string>() == pchName;
|
||||
});
|
||||
if (it != achievements.end())
|
||||
{
|
||||
it.value()["earned"] = 1;
|
||||
if (it != defined_achievements.end()) {
|
||||
user_achievements[pchName]["earned"] = true;
|
||||
user_achievements[pchName]["earned_time"] = static_cast<uint32>(std::time(nullptr));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
||||
}
|
||||
} catch (...) {}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -233,20 +242,18 @@ bool SetAchievement( const char *pchName )
|
|||
bool ClearAchievement( const char *pchName )
|
||||
{
|
||||
PRINT_DEBUG("ClearAchievement %s\n", pchName);
|
||||
try
|
||||
{
|
||||
auto it = std::find_if(achievements.begin(), achievements.end(), [pchName](nlohmann::json& item) {
|
||||
if (pchName == nullptr) return false;
|
||||
|
||||
try {
|
||||
auto it = std::find_if(defined_achievements.begin(), defined_achievements.end(), [pchName](nlohmann::json& item) {
|
||||
return static_cast<std::string const&>(item["name"]) == pchName;
|
||||
});
|
||||
if (it != achievements.end())
|
||||
{
|
||||
it.value()["earned"] = 0;
|
||||
});
|
||||
if (it != defined_achievements.end()) {
|
||||
user_achievements[pchName]["earned"] = false;
|
||||
user_achievements[pchName]["earned_time"] = static_cast<uint32>(0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
} catch (...) {}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -258,26 +265,22 @@ bool ClearAchievement( const char *pchName )
|
|||
bool GetAchievementAndUnlockTime( const char *pchName, bool *pbAchieved, uint32 *punUnlockTime )
|
||||
{
|
||||
PRINT_DEBUG("GetAchievementAndUnlockTime\n");
|
||||
try
|
||||
{
|
||||
auto it = std::find_if(achievements.begin(), achievements.end(), [pchName](nlohmann::json& item) {
|
||||
if (pchName == nullptr) return false;
|
||||
|
||||
try {
|
||||
auto it = std::find_if(defined_achievements.begin(), defined_achievements.end(), [pchName](nlohmann::json& item) {
|
||||
return static_cast<std::string const&>(item["name"]) == pchName;
|
||||
});
|
||||
if (it != achievements.end())
|
||||
{
|
||||
*pbAchieved = it.value()["earned"].get<int>();
|
||||
*punUnlockTime = std::time(NULL);
|
||||
//*punUnlockTime = it.value()["time_earned"].get<uint32>();
|
||||
});
|
||||
auto ach = user_achievements.find(pchName);
|
||||
if (it != defined_achievements.end() && ach != user_achievements.end()) {
|
||||
if(pbAchieved != nullptr) *pbAchieved = (*ach)["earned"];
|
||||
if(punUnlockTime != nullptr) *punUnlockTime = (*ach)["earned_time"];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
} catch (...) {}
|
||||
|
||||
}
|
||||
|
||||
*pbAchieved = false;
|
||||
*punUnlockTime = 0;
|
||||
if(pbAchieved != nullptr) *pbAchieved = false;
|
||||
if(punUnlockTime != nullptr) *punUnlockTime = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -294,11 +297,7 @@ bool StoreStats()
|
|||
PRINT_DEBUG("StoreStats\n");
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
|
||||
std::ofstream achiev_file(db_file_path, std::ios::trunc | std::ios::out);
|
||||
if (achiev_file)
|
||||
{
|
||||
achiev_file << std::setw(2) << achievements;
|
||||
}
|
||||
local_storage->write_inventory_file(user_achievements, achievements_user_file);
|
||||
|
||||
UserStatsStored_t data;
|
||||
data.m_nGameID = settings->get_local_game_id().ToUint64();
|
||||
|
|
@ -317,6 +316,8 @@ bool StoreStats()
|
|||
int GetAchievementIcon( const char *pchName )
|
||||
{
|
||||
PRINT_DEBUG("GetAchievementIcon\n");
|
||||
if (pchName == nullptr) return 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -327,56 +328,40 @@ int GetAchievementIcon( const char *pchName )
|
|||
const char * GetAchievementDisplayAttribute( const char *pchName, const char *pchKey )
|
||||
{
|
||||
PRINT_DEBUG("GetAchievementDisplayAttribute %s %s\n", pchName, pchKey);
|
||||
if (pchName == nullptr) return "";
|
||||
if (pchKey == nullptr) return "";
|
||||
|
||||
if (strcmp (pchKey, "name") == 0) {
|
||||
try
|
||||
{
|
||||
auto it = std::find_if(achievements.begin(), achievements.end(), [pchName](nlohmann::json& item) {
|
||||
try {
|
||||
auto it = std::find_if(defined_achievements.begin(), defined_achievements.end(), [pchName](nlohmann::json& item) {
|
||||
return static_cast<std::string const&>(item["name"]) == pchName;
|
||||
});
|
||||
if (it != achievements.end())
|
||||
{
|
||||
});
|
||||
if (it != defined_achievements.end()) {
|
||||
return it.value()["displayName"].get<std::string>().c_str();
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
||||
}
|
||||
} catch (...) {}
|
||||
}
|
||||
|
||||
if (strcmp (pchKey, "desc") == 0) {
|
||||
try
|
||||
{
|
||||
auto it = std::find_if(achievements.begin(), achievements.end(), [pchName](nlohmann::json& item) {
|
||||
try {
|
||||
auto it = std::find_if(defined_achievements.begin(), defined_achievements.end(), [pchName](nlohmann::json& item) {
|
||||
return static_cast<std::string const&>(item["name"]) == pchName;
|
||||
});
|
||||
if (it != achievements.end())
|
||||
{
|
||||
});
|
||||
if (it != defined_achievements.end()) {
|
||||
return it.value()["description"].get<std::string>().c_str();
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
||||
}
|
||||
} catch (...) {}
|
||||
}
|
||||
|
||||
if (strcmp (pchKey, "hidden") == 0) {
|
||||
try
|
||||
{
|
||||
auto it = std::find_if(achievements.begin(), achievements.end(), [pchName](nlohmann::json& item) {
|
||||
try {
|
||||
auto it = std::find_if(defined_achievements.begin(), defined_achievements.end(), [pchName](nlohmann::json& item) {
|
||||
return static_cast<std::string const&>(item["name"]) == pchName;
|
||||
});
|
||||
if (it != achievements.end())
|
||||
{
|
||||
return (it.value()["hidden"].get<int>() ? "1" : "0");
|
||||
});
|
||||
if (it != defined_achievements.end()) {
|
||||
return it.value()["description"].get<std::string>().c_str();
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
||||
}
|
||||
} catch (...) {}
|
||||
}
|
||||
|
||||
return "";
|
||||
|
|
@ -388,6 +373,8 @@ const char * GetAchievementDisplayAttribute( const char *pchName, const char *pc
|
|||
bool IndicateAchievementProgress( const char *pchName, uint32 nCurProgress, uint32 nMaxProgress )
|
||||
{
|
||||
PRINT_DEBUG("IndicateAchievementProgress\n");
|
||||
if (pchName == nullptr) return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -396,21 +383,16 @@ bool IndicateAchievementProgress( const char *pchName, uint32 nCurProgress, uint
|
|||
uint32 GetNumAchievements()
|
||||
{
|
||||
PRINT_DEBUG("GetNumAchievements\n");
|
||||
return achievements.size();
|
||||
return defined_achievements.size();
|
||||
}
|
||||
|
||||
// Get achievement name iAchievement in [0,GetNumAchievements)
|
||||
const char * GetAchievementName( uint32 iAchievement )
|
||||
{
|
||||
PRINT_DEBUG("GetAchievementName\n");
|
||||
try
|
||||
{
|
||||
return static_cast<std::string const&>(achievements[iAchievement]["name"]).c_str();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
||||
}
|
||||
try {
|
||||
return defined_achievements[iAchievement]["name"].get<std::string>().c_str();
|
||||
} catch (...) {}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
|
@ -428,7 +410,10 @@ SteamAPICall_t RequestUserStats( CSteamID steamIDUser )
|
|||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
|
||||
// Enable this to allow hot reload achievements status
|
||||
//load_achievements();
|
||||
//if (steamIDUser == settings->get_local_steam_id()) {
|
||||
// load_achievements();
|
||||
//}
|
||||
|
||||
|
||||
UserStatsReceived_t data;
|
||||
data.m_nGameID = settings->get_local_game_id().ToUint64();
|
||||
|
|
@ -442,6 +427,8 @@ SteamAPICall_t RequestUserStats( CSteamID steamIDUser )
|
|||
bool GetUserStat( CSteamID steamIDUser, const char *pchName, int32 *pData )
|
||||
{
|
||||
PRINT_DEBUG("GetUserStat %s %llu\n", pchName, steamIDUser.ConvertToUint64());
|
||||
if (pchName == nullptr) return false;
|
||||
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
|
||||
if (steamIDUser == settings->get_local_steam_id()) {
|
||||
|
|
@ -456,6 +443,8 @@ bool GetUserStat( CSteamID steamIDUser, const char *pchName, int32 *pData )
|
|||
bool GetUserStat( CSteamID steamIDUser, const char *pchName, float *pData )
|
||||
{
|
||||
PRINT_DEBUG("GetUserStat %s %llu\n", pchName, steamIDUser.ConvertToUint64());
|
||||
if (pchName == nullptr) return false;
|
||||
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
|
||||
if (steamIDUser == settings->get_local_steam_id()) {
|
||||
|
|
@ -470,6 +459,12 @@ bool GetUserStat( CSteamID steamIDUser, const char *pchName, float *pData )
|
|||
bool GetUserAchievement( CSteamID steamIDUser, const char *pchName, bool *pbAchieved )
|
||||
{
|
||||
PRINT_DEBUG("GetUserAchievement %s\n", pchName);
|
||||
if (pchName == nullptr) return false;
|
||||
|
||||
if (steamIDUser == settings->get_local_steam_id()) {
|
||||
return GetAchievement(pchName, pbAchieved);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -477,6 +472,11 @@ bool GetUserAchievement( CSteamID steamIDUser, const char *pchName, bool *pbAchi
|
|||
bool GetUserAchievementAndUnlockTime( CSteamID steamIDUser, const char *pchName, bool *pbAchieved, uint32 *punUnlockTime )
|
||||
{
|
||||
PRINT_DEBUG("GetUserAchievementAndUnlockTime %s\n", pchName);
|
||||
if (pchName == nullptr) return false;
|
||||
|
||||
if (steamIDUser == settings->get_local_steam_id()) {
|
||||
return GetAchievementAndUnlockTime(pchName, pbAchieved, punUnlockTime);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -486,6 +486,13 @@ bool ResetAllStats( bool bAchievementsToo )
|
|||
{
|
||||
PRINT_DEBUG("ResetAllStats\n");
|
||||
//TODO
|
||||
if (bAchievementsToo) {
|
||||
std::for_each(user_achievements.begin(), user_achievements.end(), [](nlohmann::json& v) {
|
||||
v["earned"] = false;
|
||||
v["earned_time"] = 0;
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue