ACHIEVEMENTS: Load achivements descriptions from achievements.dat

This commit is contained in:
lb_ii 2021-06-04 04:34:59 +03:00 committed by lolbot-iichan
parent a81d534509
commit 629e5c2783
2 changed files with 83 additions and 16 deletions

View file

@ -23,8 +23,10 @@
#include "common/achievements.h"
#include "common/debug.h"
#include "common/stream.h"
#include "common/system.h"
#include "common/translation.h"
#include "common/unzip.h"
namespace Common {
@ -67,11 +69,11 @@ bool AchievementsManager::setActiveDomain(const AchievementsInfo &info) {
_iniFile = new Common::INIFile();
_iniFile->loadFromSaveFile(_iniFileName); // missing file is OK
_descriptions = info.descriptions;
loadAchievementsData(platform, info.appId.c_str());
for (uint32 i = 0; i < info.stats.size(); i++) {
if (!(_iniFile->hasKey(info.stats[i].id, "statistics"))) {
_iniFile->setKey(info.stats[i].id, "statistics", info.stats[i].start);
for (uint32 i = 0; i < _stats.size(); i++) {
if (!(_iniFile->hasKey(_stats[i].id, "statistics"))) {
_iniFile->setKey(_stats[i].id, "statistics", _stats[i].start);
}
}
@ -82,6 +84,68 @@ bool AchievementsManager::setActiveDomain(const AchievementsInfo &info) {
}
bool AchievementsManager::loadAchievementsData(const char *platform, const char *appId) {
Archive *cfgZip = Common::makeZipArchive("achievements.dat");
if (!cfgZip) {
warning("achievements.dat is not found. Achievements messages are unavailable");
return false;
}
String cfgFileName = String::format("%s-%s.ini", platform, appId);
SeekableReadStream *stream = cfgZip->createReadStreamForMember(cfgFileName);
if (!stream) {
delete cfgZip;
warning("%s is not found in achievements.dat. Achievements messages are unavailable", cfgFileName.c_str());
return false;
}
INIFile cfgFile;
if (!cfgFile.loadFromStream(*stream)) {
delete stream;
delete cfgZip;
warning("%s is corrupted in achievements.dat. Achievements messages are unavailable", cfgFileName.c_str());
return false;
}
_descriptions.clear();
for (int i = 0; i < 256; i++) {
String prefix = String::format("item_%d", i);
String id, title, comment, hidden;
cfgFile.getKey(prefix + "_id", "achievements:en", id);
cfgFile.getKey(prefix + "_title", "achievements:en", title);
cfgFile.getKey(prefix + "_comment", "achievements:en", comment);
cfgFile.getKey(prefix + "_hidden", "achievements:en", hidden);
if (id.empty()) {
break;
} else {
_descriptions.push_back({id, title, comment, !hidden.empty()});
}
}
_stats.clear();
for (int i = 0; i < 256; i++) {
String prefix = String::format("item_%d", i);
String id, comment, start;
cfgFile.getKey(prefix + "_id", "stats:en", id);
cfgFile.getKey(prefix + "_comment", "stats:en", comment);
cfgFile.getKey(prefix + "_start", "stats:en", start);
if (id.empty()) {
break;
} else {
_stats.push_back({id, comment, start});
}
}
delete stream;
delete cfgZip;
return true;
}
bool AchievementsManager::unsetActiveDomain() {
debug("AchievementsManager::unsetActiveDomain()");
@ -91,6 +155,7 @@ bool AchievementsManager::unsetActiveDomain() {
_iniFile = nullptr;
_descriptions.clear();
_stats.clear();
return true;
}
@ -107,7 +172,7 @@ bool AchievementsManager::setAchievement(const String &id) {
String displayedMessage = id;
for (uint32 i = 0; i < _descriptions.size(); i++) {
if (strcmp(_descriptions[i].id, id.c_str()) == 0) {
if (_descriptions[i].id == id) {
displayedMessage = _descriptions[i].title;
break;
}

View file

@ -53,19 +53,19 @@ enum AchievementsPlatform {
* Information structure for game-specific statistics.
*/
struct StatDescription {
const char *id; //!< Stat internal ID, such as "ITEMS_THROWN".
const char *comment; //!< Optional stat comment, such as "Items Thrown".
const char *start; //!< Stat default value, such as "0".
String id; //!< Stat internal ID, such as "ITEMS_THROWN".
String comment; //!< Optional stat comment, such as "Items Thrown".
String start; //!< Stat default value, such as "0".
};
/**
* Information structure for game-specific achievements.
*/
struct AchievementDescription {
const char *id; //!< Achievement internal ID, such as "ACHIEVEMENT_TIMING".
String id; //!< Achievement internal ID, such as "ACHIEVEMENT_TIMING".
String title; //!< Achievement displayed text, such as "Marathon Runner".
String comment; //!< Optional achievement hint or comment, such as "Finish the game in less than 4 hours".
bool isHidden; //!< Whether the achievement is hidden.
const char *title; //!< Achievement displayed text, such as "Marathon Runner".
const char *comment; //!< Optional achievement hint or comment, such as "Finish the game in less than 4 hours".
};
/**
@ -74,8 +74,6 @@ struct AchievementDescription {
struct AchievementsInfo {
Common::AchievementsPlatform platform; //!< Achievements platform, such as "STEAM_ACHIEVEMENTS".
Common::String appId; //!< Achievements application ID of the given platform.
Common::Array<StatDescription> stats; //!< Descriptions of all game stats.
Common::Array<AchievementDescription> descriptions; //!< Descriptions of all game achievements.
AchievementsInfo() { platform = Common::UNK_ACHIEVEMENTS; }
};
@ -91,9 +89,10 @@ public:
~AchievementsManager();
/**
* Set a platform and application ID as active domain, store messages texts.
* Set a game targeted by platform type and application ID as active domain.
* Automaticly loads messages texts from achievements.dat.
*
* @param[in] info Achievements platform, application ID and messages information.
* @param[in] info Achievements platform type and application ID.
*/
bool setActiveDomain(const AchievementsInfo &info);
bool unsetActiveDomain(); //!< Unset the current active domain.
@ -213,11 +212,14 @@ public:
/** @} */
private:
bool loadAchievementsData(const char *platform, const char *appId);
float getStatFloatEx(const String &id, const String &section) const;
bool setStatFloatEx(const String &id, float value, const String &section) const;
INIFile *_iniFile;
String _iniFileName;
Common::Array<StatDescription> _stats;
Common::Array<AchievementDescription> _descriptions;
};