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/achievements.h"
#include "common/debug.h" #include "common/debug.h"
#include "common/stream.h"
#include "common/system.h" #include "common/system.h"
#include "common/translation.h" #include "common/translation.h"
#include "common/unzip.h"
namespace Common { namespace Common {
@ -67,11 +69,11 @@ bool AchievementsManager::setActiveDomain(const AchievementsInfo &info) {
_iniFile = new Common::INIFile(); _iniFile = new Common::INIFile();
_iniFile->loadFromSaveFile(_iniFileName); // missing file is OK _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++) { for (uint32 i = 0; i < _stats.size(); i++) {
if (!(_iniFile->hasKey(info.stats[i].id, "statistics"))) { if (!(_iniFile->hasKey(_stats[i].id, "statistics"))) {
_iniFile->setKey(info.stats[i].id, "statistics", info.stats[i].start); _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() { bool AchievementsManager::unsetActiveDomain() {
debug("AchievementsManager::unsetActiveDomain()"); debug("AchievementsManager::unsetActiveDomain()");
@ -91,6 +155,7 @@ bool AchievementsManager::unsetActiveDomain() {
_iniFile = nullptr; _iniFile = nullptr;
_descriptions.clear(); _descriptions.clear();
_stats.clear();
return true; return true;
} }
@ -107,7 +172,7 @@ bool AchievementsManager::setAchievement(const String &id) {
String displayedMessage = id; String displayedMessage = id;
for (uint32 i = 0; i < _descriptions.size(); i++) { 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; displayedMessage = _descriptions[i].title;
break; break;
} }

View file

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