Inventory/achivements bug fixes/improvements/cleanups.
parent
3982ad31e6
commit
828e5d456c
|
@ -75,6 +75,7 @@ An example can be found in steam_settings.EXAMPLE that works with Killing Floor
|
||||||
The items.json syntax is simple, you SHOULD validate your .json file before trying to run your game or you won't have any item in your inventory. Just look for "online json validator" on your web brower to valide your file.
|
The items.json syntax is simple, you SHOULD validate your .json file before trying to run your game or you won't have any item in your inventory. Just look for "online json validator" on your web brower to valide your file.
|
||||||
You can use https://steamdb.info/ to list items and attributes they have and put them into your .json.
|
You can use https://steamdb.info/ to list items and attributes they have and put them into your .json.
|
||||||
Keep in mind that some item are not valid to have in your inventory. For example, in PayDay2 all items below item_id 50000 will make your game crash.
|
Keep in mind that some item are not valid to have in your inventory. For example, in PayDay2 all items below item_id 50000 will make your game crash.
|
||||||
|
items.json should contain all the item definitions for the game, default_items.json is the quantity of each item that you want a user to have initially in their inventory. By default the user will have no items.
|
||||||
|
|
||||||
Leaderboards:
|
Leaderboards:
|
||||||
By default the emulator assumes all leaderboards queried by the game (FindLeaderboard()) exist and creates them with the most common options (sort method descending, display type numeric)
|
By default the emulator assumes all leaderboards queried by the game (FindLeaderboard()) exist and creates them with the most common options (sort method descending, display type numeric)
|
||||||
|
|
|
@ -128,14 +128,19 @@ bool Local_Storage::update_save_filenames(std::string folder)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Local_Storage::load_json(std::string full_path, nlohmann::json& json)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool Local_Storage::load_json_file(std::string folder, std::string const&file, nlohmann::json& json)
|
bool Local_Storage::load_json_file(std::string folder, std::string const&file, nlohmann::json& json)
|
||||||
{
|
{
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Local_Storage::write_json_file(std::string folder, std::string const&file, nlohmann::json const& json)
|
bool Local_Storage::write_json_file(std::string folder, std::string const&file, nlohmann::json const& json)
|
||||||
{
|
{
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> Local_Storage::get_filenames_path(std::string path)
|
std::vector<std::string> Local_Storage::get_filenames_path(std::string path)
|
||||||
|
@ -691,16 +696,8 @@ bool Local_Storage::update_save_filenames(std::string folder)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Local_Storage::load_json_file(std::string folder, std::string const&file, nlohmann::json& json)
|
bool Local_Storage::load_json(std::string full_path, nlohmann::json& json)
|
||||||
{
|
{
|
||||||
if (!folder.empty() && folder.back() != *PATH_SEPARATOR) {
|
|
||||||
folder.append(PATH_SEPARATOR);
|
|
||||||
}
|
|
||||||
std::string inv_path = std::move(save_directory + appid + folder);
|
|
||||||
std::string full_path = inv_path + file;
|
|
||||||
|
|
||||||
create_directory(inv_path);
|
|
||||||
|
|
||||||
std::ifstream inventory_file(full_path);
|
std::ifstream inventory_file(full_path);
|
||||||
// If there is a file and we opened it
|
// If there is a file and we opened it
|
||||||
if (inventory_file)
|
if (inventory_file)
|
||||||
|
@ -730,6 +727,17 @@ bool Local_Storage::load_json_file(std::string folder, std::string const&file, n
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Local_Storage::load_json_file(std::string folder, std::string const&file, nlohmann::json& json)
|
||||||
|
{
|
||||||
|
if (!folder.empty() && folder.back() != *PATH_SEPARATOR) {
|
||||||
|
folder.append(PATH_SEPARATOR);
|
||||||
|
}
|
||||||
|
std::string inv_path = std::move(save_directory + appid + folder);
|
||||||
|
std::string full_path = inv_path + file;
|
||||||
|
|
||||||
|
return load_json(full_path, json);
|
||||||
|
}
|
||||||
|
|
||||||
bool Local_Storage::write_json_file(std::string folder, std::string const&file, nlohmann::json const& json)
|
bool Local_Storage::write_json_file(std::string folder, std::string const&file, nlohmann::json const& json)
|
||||||
{
|
{
|
||||||
if (!folder.empty() && folder.back() != *PATH_SEPARATOR) {
|
if (!folder.empty() && folder.back() != *PATH_SEPARATOR) {
|
||||||
|
|
|
@ -63,6 +63,7 @@ public:
|
||||||
|
|
||||||
bool update_save_filenames(std::string folder);
|
bool update_save_filenames(std::string folder);
|
||||||
|
|
||||||
|
bool load_json(std::string full_path, nlohmann::json& json);
|
||||||
bool load_json_file(std::string folder, std::string const& file, nlohmann::json& json);
|
bool load_json_file(std::string folder, std::string const& file, nlohmann::json& json);
|
||||||
bool write_json_file(std::string folder, std::string const& file, nlohmann::json const& json);
|
bool write_json_file(std::string folder, std::string const& file, nlohmann::json const& json);
|
||||||
};
|
};
|
||||||
|
|
|
@ -60,9 +60,7 @@ private:
|
||||||
|
|
||||||
bool inventory_loaded;
|
bool inventory_loaded;
|
||||||
bool call_definition_update;
|
bool call_definition_update;
|
||||||
bool call_inventory_update;
|
bool item_definitions_loaded;
|
||||||
bool definition_update_called;
|
|
||||||
bool full_update_called;
|
|
||||||
|
|
||||||
struct Steam_Inventory_Requests* new_inventory_result(bool full_query=true, const SteamItemInstanceID_t* pInstanceIDs = NULL, uint32 unCountInstanceIDs = 0)
|
struct Steam_Inventory_Requests* new_inventory_result(bool full_query=true, const SteamItemInstanceID_t* pInstanceIDs = NULL, uint32 unCountInstanceIDs = 0)
|
||||||
{
|
{
|
||||||
|
@ -96,29 +94,7 @@ void read_items_db()
|
||||||
{
|
{
|
||||||
std::string items_db_path = Local_Storage::get_game_settings_path() + items_user_file;
|
std::string items_db_path = Local_Storage::get_game_settings_path() + items_user_file;
|
||||||
PRINT_DEBUG("Items file path: %s\n", items_db_path.c_str());
|
PRINT_DEBUG("Items file path: %s\n", items_db_path.c_str());
|
||||||
std::ifstream inventory_file(items_db_path);
|
local_storage->load_json(items_db_path, defined_items);
|
||||||
// If there is a file and we opened it
|
|
||||||
if (inventory_file)
|
|
||||||
{
|
|
||||||
inventory_file.seekg(0, std::ios::end);
|
|
||||||
size_t size = inventory_file.tellg();
|
|
||||||
std::string buffer(size, '\0');
|
|
||||||
inventory_file.seekg(0);
|
|
||||||
// Read it entirely, if the .json file gets too big,
|
|
||||||
// I should look into this and split reads into smaller parts.
|
|
||||||
inventory_file.read(&buffer[0], size);
|
|
||||||
inventory_file.close();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
defined_items = std::move(nlohmann::json::parse(buffer));
|
|
||||||
PRINT_DEBUG("Loaded inventory. Loaded %u items.\n", defined_items.size());
|
|
||||||
}
|
|
||||||
catch (std::exception& e)
|
|
||||||
{
|
|
||||||
PRINT_DEBUG("Error while parsing inventory json: %s\n", e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void read_inventory_db()
|
void read_inventory_db()
|
||||||
|
@ -129,29 +105,7 @@ void read_inventory_db()
|
||||||
// Try to load a default one
|
// Try to load a default one
|
||||||
std::string items_db_path = Local_Storage::get_game_settings_path() + items_default_file;
|
std::string items_db_path = Local_Storage::get_game_settings_path() + items_default_file;
|
||||||
PRINT_DEBUG("Default items file path: %s\n", items_db_path.c_str());
|
PRINT_DEBUG("Default items file path: %s\n", items_db_path.c_str());
|
||||||
std::ifstream inventory_file(items_db_path);
|
local_storage->load_json(items_db_path, user_items);
|
||||||
// If there is a file and we opened it
|
|
||||||
if (inventory_file)
|
|
||||||
{
|
|
||||||
inventory_file.seekg(0, std::ios::end);
|
|
||||||
size_t size = inventory_file.tellg();
|
|
||||||
std::string buffer(size, '\0');
|
|
||||||
inventory_file.seekg(0);
|
|
||||||
// Read it entirely, if the .json file gets too big,
|
|
||||||
// I should look into this and split reads into smaller parts.
|
|
||||||
inventory_file.read(&buffer[0], size);
|
|
||||||
inventory_file.close();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
user_items = std::move(nlohmann::json::parse(buffer));
|
|
||||||
PRINT_DEBUG("Loaded default inventory. Loaded %u items.\n", user_items.size());
|
|
||||||
}
|
|
||||||
catch (std::exception& e)
|
|
||||||
{
|
|
||||||
PRINT_DEBUG("Error while parsing inventory json: %s\n", e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,9 +129,7 @@ Steam_Inventory(class Settings *settings, class SteamCallResults *callback_resul
|
||||||
user_items(nlohmann::json::object()),
|
user_items(nlohmann::json::object()),
|
||||||
inventory_loaded(false),
|
inventory_loaded(false),
|
||||||
call_definition_update(false),
|
call_definition_update(false),
|
||||||
call_inventory_update(false),
|
item_definitions_loaded(false)
|
||||||
definition_update_called(false),
|
|
||||||
full_update_called(false)
|
|
||||||
{
|
{
|
||||||
this->run_every_runcb->add(&Steam_Inventory::run_every_runcb_cb, this);
|
this->run_every_runcb->add(&Steam_Inventory::run_every_runcb_cb, this);
|
||||||
}
|
}
|
||||||
|
@ -230,6 +182,7 @@ bool GetResultItems( SteamInventoryResult_t resultHandle,
|
||||||
|
|
||||||
if (pOutItemsArray != nullptr)
|
if (pOutItemsArray != nullptr)
|
||||||
{
|
{
|
||||||
|
SteamItemDetails_t *items_array_base = pOutItemsArray;
|
||||||
uint32 max_items = *punOutItemsArraySize;
|
uint32 max_items = *punOutItemsArraySize;
|
||||||
|
|
||||||
if (request->full_query) {
|
if (request->full_query) {
|
||||||
|
@ -249,15 +202,17 @@ bool GetResultItems( SteamInventoryResult_t resultHandle,
|
||||||
pOutItemsArray->m_unFlags = k_ESteamItemNoTrade;
|
pOutItemsArray->m_unFlags = k_ESteamItemNoTrade;
|
||||||
++pOutItemsArray;
|
++pOutItemsArray;
|
||||||
}
|
}
|
||||||
*punOutItemsArraySize = std::min(*punOutItemsArraySize, static_cast<uint32>(user_items.size()));
|
|
||||||
} else {
|
} else {
|
||||||
for (auto &itemid : request->instance_ids) {
|
for (auto &itemid : request->instance_ids) {
|
||||||
if (!max_items) break;
|
if (!max_items) break;
|
||||||
|
auto it = user_items.find(std::to_string(itemid));
|
||||||
|
if (it != user_items.end()) {
|
||||||
pOutItemsArray->m_iDefinition = itemid;
|
pOutItemsArray->m_iDefinition = itemid;
|
||||||
pOutItemsArray->m_itemId = itemid;
|
pOutItemsArray->m_itemId = itemid;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
pOutItemsArray->m_unQuantity = user_items[itemid].get<int>();
|
pOutItemsArray->m_unQuantity = it->get<int>();
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
|
@ -269,9 +224,16 @@ bool GetResultItems( SteamInventoryResult_t resultHandle,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*punOutItemsArraySize = pOutItemsArray - items_array_base;
|
||||||
|
}
|
||||||
else if (punOutItemsArraySize != nullptr)
|
else if (punOutItemsArraySize != nullptr)
|
||||||
{
|
{
|
||||||
|
if (request->full_query) {
|
||||||
*punOutItemsArraySize = user_items.size();
|
*punOutItemsArraySize = user_items.size();
|
||||||
|
} else {
|
||||||
|
*punOutItemsArraySize = std::count_if(request->instance_ids.begin(), request->instance_ids.end(), [this](auto item_id){ return user_items.find(std::to_string(item_id)) != user_items.end();});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PRINT_DEBUG("GetResultItems good\n");
|
PRINT_DEBUG("GetResultItems good\n");
|
||||||
|
@ -359,8 +321,6 @@ bool GetAllItems( SteamInventoryResult_t *pResultHandle )
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
struct Steam_Inventory_Requests* request = new_inventory_result();
|
struct Steam_Inventory_Requests* request = new_inventory_result();
|
||||||
|
|
||||||
call_inventory_update = true;
|
|
||||||
|
|
||||||
if (pResultHandle != nullptr)
|
if (pResultHandle != nullptr)
|
||||||
*pResultHandle = request->inventory_result;
|
*pResultHandle = request->inventory_result;
|
||||||
|
|
||||||
|
@ -383,7 +343,6 @@ bool GetItemsByID( SteamInventoryResult_t *pResultHandle, STEAM_ARRAY_COUNT( unC
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
if (pResultHandle) {
|
if (pResultHandle) {
|
||||||
struct Steam_Inventory_Requests *request = new_inventory_result(false, pInstanceIDs, unCountInstanceIDs);
|
struct Steam_Inventory_Requests *request = new_inventory_result(false, pInstanceIDs, unCountInstanceIDs);
|
||||||
//call_inventory_update = true;
|
|
||||||
*pResultHandle = request->inventory_result;
|
*pResultHandle = request->inventory_result;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -613,7 +572,7 @@ bool LoadItemDefinitions()
|
||||||
PRINT_DEBUG("LoadItemDefinitions\n");
|
PRINT_DEBUG("LoadItemDefinitions\n");
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
|
||||||
if (!definition_update_called) {
|
if (!item_definitions_loaded) {
|
||||||
call_definition_update = true;
|
call_definition_update = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -715,6 +674,7 @@ bool GetItemDefinitionProperty( SteamItemDef_t iDefinition, const char *pchPrope
|
||||||
{
|
{
|
||||||
*punValueBufferSizeOut = 0;
|
*punValueBufferSizeOut = 0;
|
||||||
PRINT_DEBUG("Attr %s not found for item %d\n", pchPropertyName, iDefinition);
|
PRINT_DEBUG("Attr %s not found for item %d\n", pchPropertyName, iDefinition);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // Pass a NULL pointer for pchPropertyName to get a comma - separated list of available property names.
|
else // Pass a NULL pointer for pchPropertyName to get a comma - separated list of available property names.
|
||||||
|
@ -750,10 +710,13 @@ bool GetItemDefinitionProperty( SteamItemDef_t iDefinition, const char *pchPrope
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Request the list of "eligible" promo items that can be manually granted to the given
|
// Request the list of "eligible" promo items that can be manually granted to the given
|
||||||
// user. These are promo items of type "manual" that won't be granted automatically.
|
// user. These are promo items of type "manual" that won't be granted automatically.
|
||||||
|
@ -877,39 +840,37 @@ bool SubmitUpdateProperties( SteamInventoryUpdateHandle_t handle, SteamInventory
|
||||||
|
|
||||||
void RunCallbacks()
|
void RunCallbacks()
|
||||||
{
|
{
|
||||||
if (call_definition_update && !definition_update_called) {
|
if (call_definition_update || inventory_requests.size()) {
|
||||||
definition_update_called = true;
|
if (!item_definitions_loaded) {
|
||||||
read_items_db();
|
read_items_db();
|
||||||
|
item_definitions_loaded = true;
|
||||||
|
|
||||||
|
//only gets called once
|
||||||
|
//also gets called when getting items
|
||||||
SteamInventoryDefinitionUpdate_t data = {};
|
SteamInventoryDefinitionUpdate_t data = {};
|
||||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||||
|
}
|
||||||
|
|
||||||
call_definition_update = false;
|
call_definition_update = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (call_inventory_update) {
|
if (inventory_requests.size() && !inventory_loaded) {
|
||||||
read_inventory_db();
|
read_inventory_db();
|
||||||
inventory_loaded = true;
|
inventory_loaded = true;
|
||||||
|
|
||||||
call_definition_update = true;
|
|
||||||
call_inventory_update = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (definition_update_called && inventory_loaded)
|
if (inventory_loaded)
|
||||||
{
|
{
|
||||||
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
|
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
|
||||||
for (auto& r : inventory_requests) {
|
for (auto& r : inventory_requests) {
|
||||||
if (!r.done && std::chrono::duration_cast<std::chrono::duration<double>>(now - r.time_created).count() > r.timeout) {
|
if (!r.done && std::chrono::duration_cast<std::chrono::duration<double>>(now - r.time_created).count() > r.timeout) {
|
||||||
if (r.full_query) {
|
if (r.full_query) {
|
||||||
if (!full_update_called) {
|
|
||||||
// SteamInventoryFullUpdate_t callbacks are triggered when GetAllItems
|
// SteamInventoryFullUpdate_t callbacks are triggered when GetAllItems
|
||||||
// successfully returns a result which is newer / fresher than the last
|
// successfully returns a result which is newer / fresher than the last
|
||||||
// known result.
|
// known result.
|
||||||
//TODO: should this always be returned for each get all item calls?
|
|
||||||
struct SteamInventoryFullUpdate_t data;
|
struct SteamInventoryFullUpdate_t data;
|
||||||
data.m_handle = r.inventory_result;
|
data.m_handle = r.inventory_result;
|
||||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||||
full_update_called = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -66,29 +66,7 @@ unsigned int find_leaderboard(std::string name)
|
||||||
void load_achievements_db()
|
void load_achievements_db()
|
||||||
{
|
{
|
||||||
std::string file_path = Local_Storage::get_game_settings_path() + achievements_user_file;
|
std::string file_path = Local_Storage::get_game_settings_path() + achievements_user_file;
|
||||||
std::ifstream achs_file(file_path);
|
local_storage->load_json(file_path, defined_achievements);
|
||||||
|
|
||||||
if (achs_file)
|
|
||||||
{
|
|
||||||
achs_file.seekg(0, std::ios::end);
|
|
||||||
size_t size = achs_file.tellg();
|
|
||||||
std::string buffer(size, '\0');
|
|
||||||
achs_file.seekg(0);
|
|
||||||
// Read it entirely, if the .json file gets too big,
|
|
||||||
// I should look into this and split reads into smaller parts.
|
|
||||||
achs_file.read(&buffer[0], size);
|
|
||||||
achs_file.close();
|
|
||||||
|
|
||||||
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()
|
void load_achievements()
|
||||||
|
@ -96,6 +74,11 @@ void load_achievements()
|
||||||
local_storage->load_json_file("", achievements_user_file, user_achievements);
|
local_storage->load_json_file("", achievements_user_file, user_achievements);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void save_achievements()
|
||||||
|
{
|
||||||
|
local_storage->write_json_file("", achievements_user_file, user_achievements);
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Steam_User_Stats(Settings *settings, Local_Storage *local_storage, class SteamCallResults *callback_results, class SteamCallBacks *callbacks):
|
Steam_User_Stats(Settings *settings, Local_Storage *local_storage, class SteamCallResults *callback_results, class SteamCallBacks *callbacks):
|
||||||
settings(settings),
|
settings(settings),
|
||||||
|
@ -223,6 +206,7 @@ bool GetAchievement( const char *pchName, bool *pbAchieved )
|
||||||
{
|
{
|
||||||
PRINT_DEBUG("GetAchievement %s\n", pchName);
|
PRINT_DEBUG("GetAchievement %s\n", pchName);
|
||||||
if (pchName == nullptr) return false;
|
if (pchName == nullptr) return false;
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto it = std::find_if(defined_achievements.begin(), defined_achievements.end(), [pchName]( nlohmann::json &item ) {
|
auto it = std::find_if(defined_achievements.begin(), defined_achievements.end(), [pchName]( nlohmann::json &item ) {
|
||||||
|
@ -244,16 +228,19 @@ bool SetAchievement( const char *pchName )
|
||||||
{
|
{
|
||||||
PRINT_DEBUG("SetAchievement %s\n", pchName);
|
PRINT_DEBUG("SetAchievement %s\n", pchName);
|
||||||
if (pchName == nullptr) return false;
|
if (pchName == nullptr) return false;
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto it = std::find_if(defined_achievements.begin(), defined_achievements.end(), [pchName](nlohmann::json& item) {
|
auto it = std::find_if(defined_achievements.begin(), defined_achievements.end(), [pchName](nlohmann::json& item) {
|
||||||
return item["name"].get<std::string>() == pchName;
|
return item["name"].get<std::string>() == pchName;
|
||||||
});
|
});
|
||||||
if (it != defined_achievements.end()) {
|
if (it != defined_achievements.end()) {
|
||||||
if (user_achievements[pchName]["earned"] == false) {
|
if (user_achievements.find(pchName) == user_achievements.end() || user_achievements[pchName].value("earned", false) == false) {
|
||||||
user_achievements[pchName]["earned"] = true;
|
user_achievements[pchName]["earned"] = true;
|
||||||
user_achievements[pchName]["earned_time"] = static_cast<uint32>(std::time(nullptr));
|
user_achievements[pchName]["earned_time"] = std::chrono::duration_cast<std::chrono::duration<uint32>>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||||
|
save_achievements();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} catch (...) {}
|
} catch (...) {}
|
||||||
|
@ -265,6 +252,7 @@ bool ClearAchievement( const char *pchName )
|
||||||
{
|
{
|
||||||
PRINT_DEBUG("ClearAchievement %s\n", pchName);
|
PRINT_DEBUG("ClearAchievement %s\n", pchName);
|
||||||
if (pchName == nullptr) return false;
|
if (pchName == nullptr) return false;
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto it = std::find_if(defined_achievements.begin(), defined_achievements.end(), [pchName](nlohmann::json& item) {
|
auto it = std::find_if(defined_achievements.begin(), defined_achievements.end(), [pchName](nlohmann::json& item) {
|
||||||
|
@ -273,6 +261,7 @@ bool ClearAchievement( const char *pchName )
|
||||||
if (it != defined_achievements.end()) {
|
if (it != defined_achievements.end()) {
|
||||||
user_achievements[pchName]["earned"] = false;
|
user_achievements[pchName]["earned"] = false;
|
||||||
user_achievements[pchName]["earned_time"] = static_cast<uint32>(0);
|
user_achievements[pchName]["earned_time"] = static_cast<uint32>(0);
|
||||||
|
save_achievements();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} catch (...) {}
|
} catch (...) {}
|
||||||
|
@ -288,6 +277,7 @@ bool GetAchievementAndUnlockTime( const char *pchName, bool *pbAchieved, uint32
|
||||||
{
|
{
|
||||||
PRINT_DEBUG("GetAchievementAndUnlockTime\n");
|
PRINT_DEBUG("GetAchievementAndUnlockTime\n");
|
||||||
if (pchName == nullptr) return false;
|
if (pchName == nullptr) return false;
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto it = std::find_if(defined_achievements.begin(), defined_achievements.end(), [pchName](nlohmann::json& item) {
|
auto it = std::find_if(defined_achievements.begin(), defined_achievements.end(), [pchName](nlohmann::json& item) {
|
||||||
|
@ -319,8 +309,6 @@ bool StoreStats()
|
||||||
PRINT_DEBUG("StoreStats\n");
|
PRINT_DEBUG("StoreStats\n");
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
|
||||||
local_storage->write_json_file("", achievements_user_file, user_achievements);
|
|
||||||
|
|
||||||
UserStatsStored_t data;
|
UserStatsStored_t data;
|
||||||
data.m_nGameID = settings->get_local_game_id().ToUint64();
|
data.m_nGameID = settings->get_local_game_id().ToUint64();
|
||||||
data.m_eResult = k_EResultOK;
|
data.m_eResult = k_EResultOK;
|
||||||
|
@ -339,6 +327,7 @@ int GetAchievementIcon( const char *pchName )
|
||||||
{
|
{
|
||||||
PRINT_DEBUG("GetAchievementIcon\n");
|
PRINT_DEBUG("GetAchievementIcon\n");
|
||||||
if (pchName == nullptr) return 0;
|
if (pchName == nullptr) return 0;
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -353,13 +342,17 @@ const char * GetAchievementDisplayAttribute( const char *pchName, const char *pc
|
||||||
if (pchName == nullptr) return "";
|
if (pchName == nullptr) return "";
|
||||||
if (pchKey == nullptr) return "";
|
if (pchKey == nullptr) return "";
|
||||||
|
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
|
||||||
if (strcmp (pchKey, "name") == 0) {
|
if (strcmp (pchKey, "name") == 0) {
|
||||||
try {
|
try {
|
||||||
auto it = std::find_if(defined_achievements.begin(), defined_achievements.end(), [pchName](nlohmann::json& item) {
|
auto it = std::find_if(defined_achievements.begin(), defined_achievements.end(), [pchName](nlohmann::json& item) {
|
||||||
return static_cast<std::string const&>(item["name"]) == pchName;
|
return static_cast<std::string const&>(item["name"]) == pchName;
|
||||||
});
|
});
|
||||||
if (it != defined_achievements.end()) {
|
if (it != defined_achievements.end()) {
|
||||||
return it.value()["displayName"].get<std::string>().c_str();
|
static std::string display_name;
|
||||||
|
display_name = it.value()["displayName"].get<std::string>();
|
||||||
|
return display_name.c_str();
|
||||||
}
|
}
|
||||||
} catch (...) {}
|
} catch (...) {}
|
||||||
}
|
}
|
||||||
|
@ -370,7 +363,9 @@ const char * GetAchievementDisplayAttribute( const char *pchName, const char *pc
|
||||||
return static_cast<std::string const&>(item["name"]) == pchName;
|
return static_cast<std::string const&>(item["name"]) == pchName;
|
||||||
});
|
});
|
||||||
if (it != defined_achievements.end()) {
|
if (it != defined_achievements.end()) {
|
||||||
return it.value()["description"].get<std::string>().c_str();
|
static std::string description;
|
||||||
|
description = it.value()["description"].get<std::string>();
|
||||||
|
return description.c_str();
|
||||||
}
|
}
|
||||||
} catch (...) {}
|
} catch (...) {}
|
||||||
}
|
}
|
||||||
|
@ -381,7 +376,9 @@ const char * GetAchievementDisplayAttribute( const char *pchName, const char *pc
|
||||||
return static_cast<std::string const&>(item["name"]) == pchName;
|
return static_cast<std::string const&>(item["name"]) == pchName;
|
||||||
});
|
});
|
||||||
if (it != defined_achievements.end()) {
|
if (it != defined_achievements.end()) {
|
||||||
return it.value()["description"].get<std::string>().c_str();
|
static std::string hidden;
|
||||||
|
hidden = it.value()["hidden"].get<std::string>();
|
||||||
|
return hidden.c_str();
|
||||||
}
|
}
|
||||||
} catch (...) {}
|
} catch (...) {}
|
||||||
}
|
}
|
||||||
|
@ -396,7 +393,41 @@ bool IndicateAchievementProgress( const char *pchName, uint32 nCurProgress, uint
|
||||||
{
|
{
|
||||||
PRINT_DEBUG("IndicateAchievementProgress\n");
|
PRINT_DEBUG("IndicateAchievementProgress\n");
|
||||||
if (pchName == nullptr) return false;
|
if (pchName == nullptr) return false;
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
|
||||||
|
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;
|
||||||
|
});
|
||||||
|
auto ach = user_achievements.find(pchName);
|
||||||
|
if (it != defined_achievements.end()) {
|
||||||
|
bool achieved = false;
|
||||||
|
if ( ach != user_achievements.end()) {
|
||||||
|
bool achieved = ach->value("earned", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
UserAchievementStored_t data = {};
|
||||||
|
data.m_nGameID = settings->get_local_game_id().ToUint64();
|
||||||
|
data.m_bGroupAchievement = false;
|
||||||
|
strncpy(data.m_rgchAchievementName, pchName, k_cchStatNameMax);
|
||||||
|
|
||||||
|
if (achieved) {
|
||||||
|
data.m_nCurProgress = 0;
|
||||||
|
data.m_nMaxProgress = 0;
|
||||||
|
} else {
|
||||||
|
user_achievements[pchName]["progress"] = nCurProgress;
|
||||||
|
user_achievements[pchName]["max_progress"] = nMaxProgress;
|
||||||
|
data.m_nCurProgress = nCurProgress;
|
||||||
|
data.m_nMaxProgress = nMaxProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
save_achievements();
|
||||||
|
callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (...) {}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -405,6 +436,7 @@ bool IndicateAchievementProgress( const char *pchName, uint32 nCurProgress, uint
|
||||||
uint32 GetNumAchievements()
|
uint32 GetNumAchievements()
|
||||||
{
|
{
|
||||||
PRINT_DEBUG("GetNumAchievements\n");
|
PRINT_DEBUG("GetNumAchievements\n");
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
return defined_achievements.size();
|
return defined_achievements.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,7 +445,9 @@ const char * GetAchievementName( uint32 iAchievement )
|
||||||
{
|
{
|
||||||
PRINT_DEBUG("GetAchievementName\n");
|
PRINT_DEBUG("GetAchievementName\n");
|
||||||
try {
|
try {
|
||||||
return defined_achievements[iAchievement]["name"].get<std::string>().c_str();
|
static std::string achievement_name;
|
||||||
|
achievement_name = defined_achievements[iAchievement]["name"].get<std::string>();
|
||||||
|
return achievement_name.c_str();
|
||||||
} catch (...) {}
|
} catch (...) {}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
@ -482,6 +516,7 @@ bool GetUserAchievement( CSteamID steamIDUser, const char *pchName, bool *pbAchi
|
||||||
{
|
{
|
||||||
PRINT_DEBUG("GetUserAchievement %s\n", pchName);
|
PRINT_DEBUG("GetUserAchievement %s\n", pchName);
|
||||||
if (pchName == nullptr) return false;
|
if (pchName == nullptr) return false;
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
|
||||||
if (steamIDUser == settings->get_local_steam_id()) {
|
if (steamIDUser == settings->get_local_steam_id()) {
|
||||||
return GetAchievement(pchName, pbAchieved);
|
return GetAchievement(pchName, pbAchieved);
|
||||||
|
@ -495,6 +530,7 @@ bool GetUserAchievementAndUnlockTime( CSteamID steamIDUser, const char *pchName,
|
||||||
{
|
{
|
||||||
PRINT_DEBUG("GetUserAchievementAndUnlockTime %s\n", pchName);
|
PRINT_DEBUG("GetUserAchievementAndUnlockTime %s\n", pchName);
|
||||||
if (pchName == nullptr) return false;
|
if (pchName == nullptr) return false;
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
|
||||||
if (steamIDUser == settings->get_local_steam_id()) {
|
if (steamIDUser == settings->get_local_steam_id()) {
|
||||||
return GetAchievementAndUnlockTime(pchName, pbAchieved, punUnlockTime);
|
return GetAchievementAndUnlockTime(pchName, pbAchieved, punUnlockTime);
|
||||||
|
@ -507,6 +543,7 @@ bool GetUserAchievementAndUnlockTime( CSteamID steamIDUser, const char *pchName,
|
||||||
bool ResetAllStats( bool bAchievementsToo )
|
bool ResetAllStats( bool bAchievementsToo )
|
||||||
{
|
{
|
||||||
PRINT_DEBUG("ResetAllStats\n");
|
PRINT_DEBUG("ResetAllStats\n");
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
//TODO
|
//TODO
|
||||||
if (bAchievementsToo) {
|
if (bAchievementsToo) {
|
||||||
std::for_each(user_achievements.begin(), user_achievements.end(), [](nlohmann::json& v) {
|
std::for_each(user_achievements.begin(), user_achievements.end(), [](nlohmann::json& v) {
|
||||||
|
|
Loading…
Reference in New Issue