diff --git a/dll/dll/settings.h b/dll/dll/settings.h index fc3b7719..0ca2c664 100644 --- a/dll/dll/settings.h +++ b/dll/dll/settings.h @@ -232,6 +232,10 @@ public: // allow stats not defined by the user? bool allow_unknown_stats = false; + // when a stat that's tied to an achievement gets a new value, should the emu save that progress only if it's higher? + // the stat itself is always saved regardless of that flag, obly affects the achievement progress + bool save_only_higher_stat_achievement_progress = true; + // bypass to make SetAchievement() always return true, prevent some games from breaking bool achievement_bypass = false; diff --git a/dll/dll/steam_user_stats.h b/dll/dll/steam_user_stats.h index 5821fdd7..5ea6ad48 100644 --- a/dll/dll/steam_user_stats.h +++ b/dll/dll/steam_user_stats.h @@ -45,10 +45,10 @@ struct Steam_Leaderboard { }; struct achievement_trigger { - std::string name{}; + std::string name{}; // defined achievement name std::string value_operation{}; - std::string min_value{}; - std::string max_value{}; + std::string min_value{}; // min progress + std::string max_value{}; // max progress bool should_unlock_ach(float stat) const; bool should_unlock_ach(int32 stat) const; diff --git a/dll/settings_parser.cpp b/dll/settings_parser.cpp index 28c2dd89..99ca894f 100644 --- a/dll/settings_parser.cpp +++ b/dll/settings_parser.cpp @@ -1290,6 +1290,9 @@ static void parse_simple_features(class Settings *settings_client, class Setting settings_client->allow_unknown_stats = ini.GetBoolValue("main::general", "allow_unknown_stats", settings_client->allow_unknown_stats); settings_server->allow_unknown_stats = ini.GetBoolValue("main::general", "allow_unknown_stats", settings_server->allow_unknown_stats); + settings_client->save_only_higher_stat_achievement_progress = ini.GetBoolValue("main::general", "save_only_higher_stat_achievement_progress", settings_client->save_only_higher_stat_achievement_progress); + settings_server->save_only_higher_stat_achievement_progress = ini.GetBoolValue("main::general", "save_only_higher_stat_achievement_progress", settings_server->save_only_higher_stat_achievement_progress); + settings_client->immediate_gameserver_stats = ini.GetBoolValue("main::general", "immediate_gameserver_stats", settings_client->immediate_gameserver_stats); settings_server->immediate_gameserver_stats = ini.GetBoolValue("main::general", "immediate_gameserver_stats", settings_server->immediate_gameserver_stats); diff --git a/dll/steam_user_stats.cpp b/dll/steam_user_stats.cpp index 1d9b5bfb..0ca4a3aa 100644 --- a/dll/steam_user_stats.cpp +++ b/dll/steam_user_stats.cpp @@ -447,7 +447,7 @@ Steam_User_Stats::InternalSetResult Steam_User_Stats::set_stat_internal( result.current_val = nData; auto cached_stat = stats_cache_int.find(stat_name); - if (cached_stat != stats_cache_int.end()) { + if (stats_cache_int.end() != cached_stat) { if (cached_stat->second == nData) { result.success = true; return result; @@ -461,7 +461,26 @@ Steam_User_Stats::InternalSetResult Steam_User_Stats::set_stat_internal( set_achievement_internal(t.name.c_str()); } if (t.should_indicate_progress(nData)) { - IndicateAchievementProgress(t.name.c_str(), nData, std::stoi(t.max_value)); + bool indicate_progress = true; + // appid 1482380 needs that otherwise it will spam progress indications while driving + if (settings->save_only_higher_stat_achievement_progress) { + try { + auto user_ach_it = user_achievements.find(t.name); + if (user_achievements.end() != user_ach_it) { + auto user_progress_it = user_ach_it->find("progress"); + if (user_ach_it->end() != user_progress_it) { + int32 user_progress = *user_progress_it; + if (nData <= user_progress) { + indicate_progress = false; + } + } + } + } catch(...){} + } + + if (indicate_progress) { + IndicateAchievementProgress(t.name.c_str(), nData, std::stoi(t.max_value)); + } } } } @@ -502,7 +521,7 @@ Steam_User_Stats::InternalSetResultsecond == fData) { result.success = true; return result; @@ -516,7 +535,26 @@ Steam_User_Stats::InternalSetResultsave_only_higher_stat_achievement_progress) { + try { + auto user_ach_it = user_achievements.find(t.name); + if (user_achievements.end() != user_ach_it) { + auto user_progress_it = user_ach_it->find("progress"); + if (user_ach_it->end() != user_progress_it) { + float user_progress = *user_progress_it; + if (fData <= user_progress) { + indicate_progress = false; + } + } + } + } catch(...){} + } + + if (indicate_progress) { + IndicateAchievementProgress(t.name.c_str(), (uint32)fData, (uint32)std::stof(t.max_value)); + } } } } @@ -1353,10 +1391,10 @@ bool Steam_User_Stats::GetUserAchievementAndUnlockTime( CSteamID steamIDUser, co // Reset stats bool Steam_User_Stats::ResetAllStats( bool bAchievementsToo ) { - PRINT_DEBUG_ENTRY(); + PRINT_DEBUG("bAchievementsToo = %i", (int)bAchievementsToo); std::lock_guard lock(global_mutex); - clear_stats_internal(); + clear_stats_internal(); // this will save stats to disk if necessary if (!settings->disable_sharing_stats_with_gameserver) { for (const auto &stat : settings->getStats()) { std::string stat_name(common_helpers::ascii_to_lowercase(stat.first)); diff --git a/post_build/steam_settings.EXAMPLE/configs.main.EXAMPLE.ini b/post_build/steam_settings.EXAMPLE/configs.main.EXAMPLE.ini index f1f30b5b..ff021287 100644 --- a/post_build/steam_settings.EXAMPLE/configs.main.EXAMPLE.ini +++ b/post_build/steam_settings.EXAMPLE/configs.main.EXAMPLE.ini @@ -18,6 +18,13 @@ disable_leaderboards_create_unknown=0 # set this to 1 to allow unknown stats # default=0 allow_unknown_stats=0 +# whenever a game updates a stat which is tied to an achievement progress, the emu will save that progress immediately +# but some games will update the stat very frequently (with lower & higher values) resulting in a spam of disk writes or overlay notifications +# set this to 0 to save any stat achievement progress value (higher or lower) +# this has no impact on the stat itself, only the achievement progress of a stat which is tied to an achievement +# also has no impact on the functions which directly change stats, achievements, or achievements progress +# default=1 +save_only_higher_stat_achievement_progress=1 # synchronize user stats/achievements with game servers as soon as possible instead of caching them until the next call to `Steam_RunCallbacks()` # not recommended immediate_gameserver_stats=0