/* Copyright (C) 2019 Mr Goldberg This file is part of the Goldberg Emulator The Goldberg Emulator is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. The Goldberg Emulator is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the Goldberg Emulator; if not, see . */ #ifndef __INCLUDED_STEAM_USER_STATS_H__ #define __INCLUDED_STEAM_USER_STATS_H__ #include "base.h" #include #include #include "../json/json.hpp" struct Steam_Leaderboard { std::string name; ELeaderboardSortMethod sort_method; ELeaderboardDisplayType display_type; }; class Steam_User_Stats : public ISteamUserStats003, public ISteamUserStats004, public ISteamUserStats005, public ISteamUserStats006, public ISteamUserStats007, public ISteamUserStats008, 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 leaderboards; nlohmann::json defined_achievements; nlohmann::json user_achievements; unsigned int find_leaderboard(std::string name); void load_achievements_db(); void load_achievements(); void save_achievements(); public: Steam_User_Stats(Settings* settings, Local_Storage* local_storage, class SteamCallResults* callback_results, class SteamCallBacks* callbacks); nlohmann::json const& GetAchievementsDb() const; // Ask the server to send down this user's data and achievements for this game STEAM_CALL_BACK(UserStatsReceived_t) bool RequestCurrentStats(); // Data accessors bool GetStat(const char* pchName, int32* pData); bool GetStat(const char* pchName, float* pData); // Set / update data bool SetStat(const char* pchName, int32 nData); bool SetStat(const char* pchName, float fData); bool UpdateAvgRateStat(const char* pchName, float flCountThisSession, double dSessionLength); // Achievement flag accessors bool GetAchievement(const char* pchName, bool* pbAchieved); bool SetAchievement(const char* pchName); bool ClearAchievement(const char* pchName); // Get the achievement status, and the time it was unlocked if unlocked. // If the return value is true, but the unlock time is zero, that means it was unlocked before Steam // began tracking achievement unlock times (December 2009). Time is seconds since January 1, 1970. bool GetAchievementAndUnlockTime(const char* pchName, bool* pbAchieved, uint32* punUnlockTime); // Store the current data on the server, will get a callback when set // And one callback for every new achievement // // If the callback has a result of k_EResultInvalidParam, one or more stats // uploaded has been rejected, either because they broke constraints // or were out of date. In this case the server sends back updated values. // The stats should be re-iterated to keep in sync. bool StoreStats(); // Achievement / GroupAchievement metadata // Gets the icon of the achievement, which is a handle to be used in ISteamUtils::GetImageRGBA(), or 0 if none set. // A return value of 0 may indicate we are still fetching data, and you can wait for the UserAchievementIconFetched_t callback // which will notify you when the bits are ready. If the callback still returns zero, then there is no image set for the // specified achievement. int GetAchievementIcon(const char* pchName); // Get general attributes for an achievement. Accepts the following keys: // - "name" and "desc" for retrieving the localized achievement name and description (returned in UTF8) // - "hidden" for retrieving if an achievement is hidden (returns "0" when not hidden, "1" when hidden) const char* GetAchievementDisplayAttribute(const char* pchName, const char* pchKey); // Achievement progress - triggers an AchievementProgress callback, that is all. // Calling this w/ N out of N progress will NOT set the achievement, the game must still do that. bool IndicateAchievementProgress(const char* pchName, uint32 nCurProgress, uint32 nMaxProgress); // Used for iterating achievements. In general games should not need these functions because they should have a // list of existing achievements compiled into them uint32 GetNumAchievements(); // Get achievement name iAchievement in [0,GetNumAchievements) const char* GetAchievementName(uint32 iAchievement); // Friends stats & achievements // downloads stats for the user // returns a UserStatsReceived_t received when completed // if the other user has no stats, UserStatsReceived_t.m_eResult will be set to k_EResultFail // these stats won't be auto-updated; you'll need to call RequestUserStats() again to refresh any data STEAM_CALL_RESULT(UserStatsReceived_t) SteamAPICall_t RequestUserStats(CSteamID steamIDUser); // requests stat information for a user, usable after a successful call to RequestUserStats() bool GetUserStat(CSteamID steamIDUser, const char* pchName, int32* pData); bool GetUserStat(CSteamID steamIDUser, const char* pchName, float* pData); bool GetUserAchievement(CSteamID steamIDUser, const char* pchName, bool* pbAchieved); // See notes for GetAchievementAndUnlockTime above bool GetUserAchievementAndUnlockTime(CSteamID steamIDUser, const char* pchName, bool* pbAchieved, uint32* punUnlockTime); // Reset stats bool ResetAllStats(bool bAchievementsToo); // Leaderboard functions // asks the Steam back-end for a leaderboard by name, and will create it if it's not yet // This call is asynchronous, with the result returned in LeaderboardFindResult_t STEAM_CALL_RESULT(LeaderboardFindResult_t) SteamAPICall_t FindOrCreateLeaderboard(const char* pchLeaderboardName, ELeaderboardSortMethod eLeaderboardSortMethod, ELeaderboardDisplayType eLeaderboardDisplayType); // as above, but won't create the leaderboard if it's not found // This call is asynchronous, with the result returned in LeaderboardFindResult_t STEAM_CALL_RESULT(LeaderboardFindResult_t) SteamAPICall_t FindLeaderboard(const char* pchLeaderboardName); // returns the name of a leaderboard const char* GetLeaderboardName(SteamLeaderboard_t hSteamLeaderboard); // returns the total number of entries in a leaderboard, as of the last request int GetLeaderboardEntryCount(SteamLeaderboard_t hSteamLeaderboard); // returns the sort method of the leaderboard ELeaderboardSortMethod GetLeaderboardSortMethod(SteamLeaderboard_t hSteamLeaderboard); // returns the display type of the leaderboard ELeaderboardDisplayType GetLeaderboardDisplayType(SteamLeaderboard_t hSteamLeaderboard); // Asks the Steam back-end for a set of rows in the leaderboard. // This call is asynchronous, with the result returned in LeaderboardScoresDownloaded_t // LeaderboardScoresDownloaded_t will contain a handle to pull the results from GetDownloadedLeaderboardEntries() (below) // You can ask for more entries than exist, and it will return as many as do exist. // k_ELeaderboardDataRequestGlobal requests rows in the leaderboard from the full table, with nRangeStart & nRangeEnd in the range [1, TotalEntries] // k_ELeaderboardDataRequestGlobalAroundUser requests rows around the current user, nRangeStart being negate // e.g. DownloadLeaderboardEntries( hLeaderboard, k_ELeaderboardDataRequestGlobalAroundUser, -3, 3 ) will return 7 rows, 3 before the user, 3 after // k_ELeaderboardDataRequestFriends requests all the rows for friends of the current user STEAM_CALL_RESULT(LeaderboardScoresDownloaded_t) SteamAPICall_t DownloadLeaderboardEntries(SteamLeaderboard_t hSteamLeaderboard, ELeaderboardDataRequest eLeaderboardDataRequest, int nRangeStart, int nRangeEnd); // as above, but downloads leaderboard entries for an arbitrary set of users - ELeaderboardDataRequest is k_ELeaderboardDataRequestUsers // if a user doesn't have a leaderboard entry, they won't be included in the result // a max of 100 users can be downloaded at a time, with only one outstanding call at a time STEAM_METHOD_DESC(Downloads leaderboard entries for an arbitrary set of users - ELeaderboardDataRequest is k_ELeaderboardDataRequestUsers) STEAM_CALL_RESULT(LeaderboardScoresDownloaded_t) SteamAPICall_t DownloadLeaderboardEntriesForUsers(SteamLeaderboard_t hSteamLeaderboard, STEAM_ARRAY_COUNT_D(cUsers, Array of users to retrieve) CSteamID* prgUsers, int cUsers); // Returns data about a single leaderboard entry // use a for loop from 0 to LeaderboardScoresDownloaded_t::m_cEntryCount to get all the downloaded entries // e.g. // void OnLeaderboardScoresDownloaded( LeaderboardScoresDownloaded_t *pLeaderboardScoresDownloaded ) // { // for ( int index = 0; index < pLeaderboardScoresDownloaded->m_cEntryCount; index++ ) // { // LeaderboardEntry_t leaderboardEntry; // int32 details[3]; // we know this is how many we've stored previously // GetDownloadedLeaderboardEntry( pLeaderboardScoresDownloaded->m_hSteamLeaderboardEntries, index, &leaderboardEntry, details, 3 ); // assert( leaderboardEntry.m_cDetails == 3 ); // ... // } // once you've accessed all the entries, the data will be free'd, and the SteamLeaderboardEntries_t handle will become invalid bool GetDownloadedLeaderboardEntry(SteamLeaderboardEntries_t hSteamLeaderboardEntries, int index, LeaderboardEntry_t* pLeaderboardEntry, int32* pDetails, int cDetailsMax); // Uploads a user score to the Steam back-end. // This call is asynchronous, with the result returned in LeaderboardScoreUploaded_t // Details are extra game-defined information regarding how the user got that score // pScoreDetails points to an array of int32's, cScoreDetailsCount is the number of int32's in the list STEAM_CALL_RESULT(LeaderboardScoreUploaded_t) SteamAPICall_t UploadLeaderboardScore(SteamLeaderboard_t hSteamLeaderboard, ELeaderboardUploadScoreMethod eLeaderboardUploadScoreMethod, int32 nScore, const int32* pScoreDetails, int cScoreDetailsCount); SteamAPICall_t UploadLeaderboardScore(SteamLeaderboard_t hSteamLeaderboard, int32 nScore, int32* pScoreDetails, int cScoreDetailsCount); // Attaches a piece of user generated content the user's entry on a leaderboard. // hContent is a handle to a piece of user generated content that was shared using ISteamUserRemoteStorage::FileShare(). // This call is asynchronous, with the result returned in LeaderboardUGCSet_t. STEAM_CALL_RESULT(LeaderboardUGCSet_t) SteamAPICall_t AttachLeaderboardUGC(SteamLeaderboard_t hSteamLeaderboard, UGCHandle_t hUGC); // Retrieves the number of players currently playing your game (online + offline) // This call is asynchronous, with the result returned in NumberOfCurrentPlayers_t STEAM_CALL_RESULT(NumberOfCurrentPlayers_t) SteamAPICall_t GetNumberOfCurrentPlayers(); // Requests that Steam fetch data on the percentage of players who have received each achievement // for the game globally. // This call is asynchronous, with the result returned in GlobalAchievementPercentagesReady_t. STEAM_CALL_RESULT(GlobalAchievementPercentagesReady_t) SteamAPICall_t RequestGlobalAchievementPercentages(); // Get the info on the most achieved achievement for the game, returns an iterator index you can use to fetch // the next most achieved afterwards. Will return -1 if there is no data on achievement // percentages (ie, you haven't called RequestGlobalAchievementPercentages and waited on the callback). int GetMostAchievedAchievementInfo(char* pchName, uint32 unNameBufLen, float* pflPercent, bool* pbAchieved); // Get the info on the next most achieved achievement for the game. Call this after GetMostAchievedAchievementInfo or another // GetNextMostAchievedAchievementInfo call passing the iterator from the previous call. Returns -1 after the last // achievement has been iterated. int GetNextMostAchievedAchievementInfo(int iIteratorPrevious, char* pchName, uint32 unNameBufLen, float* pflPercent, bool* pbAchieved); // Returns the percentage of users who have achieved the specified achievement. bool GetAchievementAchievedPercent(const char* pchName, float* pflPercent); // Requests global stats data, which is available for stats marked as "aggregated". // This call is asynchronous, with the results returned in GlobalStatsReceived_t. // nHistoryDays specifies how many days of day-by-day history to retrieve in addition // to the overall totals. The limit is 60. STEAM_CALL_RESULT(GlobalStatsReceived_t) SteamAPICall_t RequestGlobalStats(int nHistoryDays); // Gets the lifetime totals for an aggregated stat bool GetGlobalStat(const char* pchStatName, int64* pData); bool GetGlobalStat(const char* pchStatName, double* pData); // Gets history for an aggregated stat. pData will be filled with daily values, starting with today. // So when called, pData[0] will be today, pData[1] will be yesterday, and pData[2] will be two days ago, // etc. cubData is the size in bytes of the pubData buffer. Returns the number of // elements actually set. int32 GetGlobalStatHistory(const char* pchStatName, STEAM_ARRAY_COUNT(cubData) int64* pData, uint32 cubData); int32 GetGlobalStatHistory(const char* pchStatName, STEAM_ARRAY_COUNT(cubData) double* pData, uint32 cubData); }; #endif//__INCLUDED_STEAM_USER_STATS_H__