diff --git a/dll/steam_user.cpp b/dll/steam_user.cpp
index 0d942e4c..ada7f481 100644
--- a/dll/steam_user.cpp
+++ b/dll/steam_user.cpp
@@ -15,849 +15,462 @@
License along with the Goldberg Emulator; if not, see
. */
-#include "dll/steam_user.h"
-#include "dll/auth.h"
-#include "dll/appticket.h"
+#include "dll/steam_user_stats.h"
+#include
-Steam_User::Steam_User(Settings *settings, Local_Storage *local_storage, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks)
+
+void Steam_User_Stats::steam_user_stats_network_low_level(void *object, Common_Message *msg)
{
- this->settings = settings;
- this->local_storage = local_storage;
- this->network = network;
- this->callbacks = callbacks;
- this->callback_results = callback_results;
+ // PRINT_DEBUG_ENTRY();
+
+ auto inst = (Steam_User_Stats *)object;
+ inst->network_callback_low_level(msg);
+}
+
+void Steam_User_Stats::steam_user_stats_run_every_runcb(void *object)
+{
+ // PRINT_DEBUG_ENTRY();
+
+ auto inst = (Steam_User_Stats *)object;
+ inst->steam_run_callback();
+}
+
+
+Steam_User_Stats::Steam_User_Stats(Settings *settings, class Networking *network, Local_Storage *local_storage, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb, Steam_Overlay* overlay):
+ settings(settings),
+ network(network),
+ local_storage(local_storage),
+ callback_results(callback_results),
+ callbacks(callbacks),
+ defined_achievements(nlohmann::json::object()),
+ user_achievements(nlohmann::json::object()),
+ run_every_runcb(run_every_runcb),
+ overlay(overlay)
+{
+ load_achievements_db(); // steam_settings/achievements.json
+ load_achievements(); // %appdata%///achievements.json
+
+ // discard achievements without a "name"
+ auto x = defined_achievements.begin();
+ while (x != defined_achievements.end()) {
+ if (!x->contains("name")) {
+ x = defined_achievements.erase(x);
+ } else {
+ ++x;
+ }
+ }
+
+ for (auto & it : defined_achievements) {
+ try {
+ std::string name = static_cast(it["name"]);
+ sorted_achievement_names.push_back(name);
+
+ achievement_trigger trig{};
+ try {
+ trig.name = name;
+ trig.value_operation = static_cast(it["progress"]["value"]["operation"]);
+ std::string stat_name = common_helpers::to_lower(static_cast(it["progress"]["value"]["operand1"]));
+ trig.min_value = static_cast(it["progress"]["min_val"]);
+ trig.max_value = static_cast(it["progress"]["max_val"]);
+ achievement_stat_trigger[stat_name].push_back(trig);
+ } catch(...) {}
+
+ // default initial values, will only be added if they don't exist already
+ auto &user_ach = user_achievements[name]; // this will create a new json entry if the key didn't exist already
+ user_ach.emplace("earned", false);
+ user_ach.emplace("earned_time", static_cast(0));
+ // they will throw an exception for achievements with no progress
+ try {
+ uint32 progress_min = std::stoul(trig.min_value);
+ uint32 progress_max = std::stoul(trig.max_value);
+ // if the above lines didn't throw exception then add the values
+ user_ach.emplace("progress", progress_min);
+ user_ach.emplace("max_progress", progress_max);
+ } catch(...) {}
+ } catch(...) {}
+
+ try {
+ it["hidden"] = std::to_string(it["hidden"].get());
+ } catch(...) {}
+
+ it["displayName"] = get_value_for_language(it, "displayName", settings->get_language());
+ it["description"] = get_value_for_language(it, "description", settings->get_language());
+
+ it["icon_handle"] = Settings::UNLOADED_IMAGE_HANDLE;
+ it["icon_gray_handle"] = Settings::UNLOADED_IMAGE_HANDLE;
+ }
+
+ //TODO: not sure if the sort is actually case insensitive, ach names seem to be treated by steam as case insensitive so I assume they are.
+ //need to find a game with achievements of different case names to confirm
+ std::sort(sorted_achievement_names.begin(), sorted_achievement_names.end(), [](const std::string lhs, const std::string rhs){
+ const auto result = std::mismatch(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend(), [](const unsigned char lhs, const unsigned char rhs){return std::tolower(lhs) == std::tolower(rhs);});
+ return result.second != rhs.cend() && (result.first == lhs.cend() || std::tolower(*result.first) < std::tolower(*result.second));}
+ );
- recording = false;
- auth_manager = new Auth_Manager(settings, network, callbacks);
+ if (!settings->disable_sharing_stats_with_gameserver) {
+ this->network->setCallback(CALLBACK_ID_GAMESERVER_STATS, settings->get_local_steam_id(), &Steam_User_Stats::steam_user_stats_network_stats, this);
+ }
+ if (settings->share_leaderboards_over_network) {
+ this->network->setCallback(CALLBACK_ID_LEADERBOARDS_STATS, settings->get_local_steam_id(), &Steam_User_Stats::steam_user_stats_network_leaderboards, this);
+ }
+ this->network->setCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_User_Stats::steam_user_stats_network_low_level, this);
+ this->run_every_runcb->add(&Steam_User_Stats::steam_user_stats_run_every_runcb, this);
}
-Steam_User::~Steam_User()
+Steam_User_Stats::~Steam_User_Stats()
{
- delete auth_manager;
+ if (!settings->disable_sharing_stats_with_gameserver) {
+ this->network->rmCallback(CALLBACK_ID_GAMESERVER_STATS, settings->get_local_steam_id(), &Steam_User_Stats::steam_user_stats_network_stats, this);
+ }
+ if (settings->share_leaderboards_over_network) {
+ this->network->rmCallback(CALLBACK_ID_LEADERBOARDS_STATS, settings->get_local_steam_id(), &Steam_User_Stats::steam_user_stats_network_leaderboards, this);
+ }
+ this->network->rmCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_User_Stats::steam_user_stats_network_low_level, this);
+ this->run_every_runcb->remove(&Steam_User_Stats::steam_user_stats_run_every_runcb, this);
}
-// returns the HSteamUser this interface represents
-// this is only used internally by the API, and by a few select interfaces that support multi-user
-HSteamUser Steam_User::GetHSteamUser()
+
+// 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 Steam_User_Stats::GetNumberOfCurrentPlayers()
{
PRINT_DEBUG_ENTRY();
- return CLIENT_HSTEAMUSER;
-}
-
-void Steam_User::LogOn( CSteamID steamID )
-{
- PRINT_DEBUG_ENTRY();
- settings->set_offline(false);
-}
-
-void Steam_User::LogOff()
-{
- PRINT_DEBUG_ENTRY();
- settings->set_offline(true);
-}
-
-// returns true if the Steam client current has a live connection to the Steam servers.
-// If false, it means there is no active connection due to either a networking issue on the local machine, or the Steam server is down/busy.
-// The Steam client will automatically be trying to recreate the connection as often as possible.
-bool Steam_User::BLoggedOn()
-{
- PRINT_DEBUG_ENTRY();
- return !settings->is_offline();
-}
-
-ELogonState Steam_User::GetLogonState()
-{
- PRINT_DEBUG_ENTRY();
- if(settings->is_offline())
- return (ELogonState)0;
- else
- return (ELogonState)4; // tested on real steam, undocumented return value
-}
-
-bool Steam_User::BConnected()
-{
- PRINT_DEBUG_ENTRY();
- return !settings->is_offline();
-}
-
-// returns the CSteamID of the account currently logged into the Steam client
-// a CSteamID is a unique identifier for an account, and used to differentiate users in all parts of the Steamworks API
-CSteamID Steam_User::GetSteamID()
-{
- PRINT_DEBUG_ENTRY();
- CSteamID id = settings->get_local_steam_id();
+ std::lock_guard lock(global_mutex);
- return id;
-}
-
-bool Steam_User::IsVACBanned( int nGameID )
-{
- PRINT_DEBUG_ENTRY();
- return false;
-}
-
-bool Steam_User::RequireShowVACBannedMessage( int nGameID )
-{
- PRINT_DEBUG_ENTRY();
- return false;
-}
-
-void Steam_User::AcknowledgeVACBanning( int nGameID )
-{
- PRINT_DEBUG_ENTRY();
-}
-
-// according to comments in sdk, "these are dead."
-int Steam_User::NClientGameIDAdd( int nGameID )
-{
- PRINT_DEBUG_ENTRY();
- return 0;
-}
-// according to comments in sdk, "these are dead."
-void Steam_User::RemoveClientGame( int nClientGameID )
-{
- PRINT_DEBUG_ENTRY();
-}
-// according to comments in sdk, "these are dead."
-void Steam_User::SetClientGameServer( int nClientGameID, uint32 unIPServer, uint16 usPortServer )
-{
- PRINT_DEBUG_ENTRY();
-}
-
-void Steam_User::SetSteam2Ticket( uint8 *pubTicket, int cubTicket )
-{
- PRINT_DEBUG_ENTRY();
-}
-
-void Steam_User::AddServerNetAddress( uint32 unIP, uint16 unPort )
-{
- PRINT_DEBUG_ENTRY();
-}
-
-bool Steam_User::SetEmail( const char *pchEmail )
-{
- PRINT_DEBUG_ENTRY();
- return false;
-}
-
-// according to comments in sdk, "logon cookie - this is obsolete and never used"
-int Steam_User::GetSteamGameConnectToken( void *pBlob, int cbMaxBlob )
-{
- PRINT_DEBUG_ENTRY();
- return 0;
-}
-
-bool Steam_User::SetRegistryString( EConfigSubTree eRegistrySubTree, const char *pchKey, const char *pchValue )
-{
- PRINT_DEBUG_TODO();
- if (!pchValue)
- return false; // real steam crashes, so return value is assumed
-
- if (!pchKey) // tested on real steam
- {
- registry.clear();
- registry_nullptr = std::string(pchValue);
- }
- else
- {
- registry[std::string(pchKey)] = std::string(pchValue);
- // TODO: save it to disk, because real steam can get the string when app restarts
- }
-
- return true;
-}
-
-bool Steam_User::GetRegistryString( EConfigSubTree eRegistrySubTree, const char *pchKey, char *pchValue, int cbValue )
-{
- PRINT_DEBUG_TODO();
- // TODO: read data on disk, because real steam can get the string when app restarts
- if (pchValue && cbValue > 0)
- memset(pchValue, 0, cbValue);
-
- std::string value{};
- if(!pchKey)
- {
- value = registry_nullptr;
- }
- else
- {
- auto it = registry.find(std::string(pchKey));
- if (it == registry.end())
- return false;
-
- value = it->second;
- }
-
- if (pchValue && cbValue > 0)
- value.copy(pchValue, cbValue - 1);
- return true;
-}
-
-bool Steam_User::SetRegistryInt( EConfigSubTree eRegistrySubTree, const char *pchKey, int iValue )
-{
- PRINT_DEBUG_TODO();
- if (!pchKey) // tested on real steam
- {
- registry.clear();
- registry_nullptr = std::to_string(iValue);
- }
- else
- {
- registry[std::string(pchKey)] = std::to_string(iValue);
- // TODO: save it to disk, because real steam can get the string when app restarts
- }
-
- return true;
-}
-
-bool Steam_User::GetRegistryInt( EConfigSubTree eRegistrySubTree, const char *pchKey, int *piValue )
-{
- PRINT_DEBUG_TODO();
- // TODO: read data on disk, because real steam can get the string when app restarts
- if (piValue)
- *piValue = 0;
-
- std::string value{};
- if(!pchKey)
- {
- value = registry_nullptr;
- }
- else
- {
- auto it = registry.find(std::string(pchKey));
- if (it == registry.end())
- return false;
-
- value = it->second;
- }
-
- try
- {
- if (piValue)
- *piValue = std::stoi(value);
- }
- catch(...)
- {
- PRINT_DEBUG("not a number"); // TODO: real steam returns a value other than 0 under this condition
- }
-
- return true;
-}
-
-// Multiplayer Authentication functions
-
-// InitiateGameConnection() starts the state machine for authenticating the game client with the game server
-// It is the client portion of a three-way handshake between the client, the game server, and the steam servers
-//
-// Parameters:
-// void *pAuthBlob - a pointer to empty memory that will be filled in with the authentication token.
-// int cbMaxAuthBlob - the number of bytes of allocated memory in pBlob. Should be at least 2048 bytes.
-// CSteamID steamIDGameServer - the steamID of the game server, received from the game server by the client
-// CGameID gameID - the ID of the current game. For games without mods, this is just CGameID( )
-// uint32 unIPServer, uint16 usPortServer - the IP address of the game server
-// bool bSecure - whether or not the client thinks that the game server is reporting itself as secure (i.e. VAC is running)
-//
-// return value - returns the number of bytes written to pBlob. If the return is 0, then the buffer passed in was too small, and the call has failed
-// The contents of pBlob should then be sent to the game server, for it to use to complete the authentication process.
-
-//steam returns 206 bytes
-#define INITIATE_GAME_CONNECTION_TICKET_SIZE 206
-
-int Steam_User::InitiateGameConnection( void *pAuthBlob, int cbMaxAuthBlob, CSteamID steamIDGameServer, uint32 unIPServer, uint16 usPortServer, bool bSecure )
-{
- PRINT_DEBUG("%i %llu %u %u %u %p", cbMaxAuthBlob, steamIDGameServer.ConvertToUint64(), unIPServer, usPortServer, bSecure, pAuthBlob);
- std::lock_guard lock(global_mutex);
- if (cbMaxAuthBlob < INITIATE_GAME_CONNECTION_TICKET_SIZE) return 0;
- if (!pAuthBlob) return 0;
- uint32 out_size = INITIATE_GAME_CONNECTION_TICKET_SIZE;
- auth_manager->getTicketData(pAuthBlob, INITIATE_GAME_CONNECTION_TICKET_SIZE, &out_size);
- if (out_size > INITIATE_GAME_CONNECTION_TICKET_SIZE)
- return 0;
- return out_size;
-}
-
-int Steam_User::InitiateGameConnection( void *pAuthBlob, int cbMaxAuthBlob, CSteamID steamIDGameServer, CGameID gameID, uint32 unIPServer, uint16 usPortServer, bool bSecure )
-{
- PRINT_DEBUG_ENTRY();
- return InitiateGameConnection(pAuthBlob, cbMaxAuthBlob, steamIDGameServer, unIPServer, usPortServer, bSecure);
-}
-
-int Steam_User::InitiateGameConnection( void *pBlob, int cbMaxBlob, CSteamID steamID, CGameID gameID, uint32 unIPServer, uint16 usPortServer, bool bSecure, void *pvSteam2GetEncryptionKey, int cbSteam2GetEncryptionKey )
-{
- PRINT_DEBUG("sdk 0.99x, 0.99y");
- return InitiateGameConnection(pBlob, cbMaxBlob, steamID, unIPServer, usPortServer, bSecure);
-}
-
-int Steam_User::InitiateGameConnection( void *pBlob, int cbMaxBlob, CSteamID steamID, int nGameAppID, uint32 unIPServer, uint16 usPortServer, bool bSecure )
-{
- PRINT_DEBUG("sdk 0.99u");
- return InitiateGameConnection(pBlob, cbMaxBlob, steamID, unIPServer, usPortServer, bSecure);
-}
-
-// notify of disconnect
-// needs to occur when the game client leaves the specified game server, needs to match with the InitiateGameConnection() call
-void Steam_User::TerminateGameConnection( uint32 unIPServer, uint16 usPortServer )
-{
- PRINT_DEBUG_TODO();
-}
-
-// Legacy functions
-
-void Steam_User::SetSelfAsPrimaryChatDestination()
-{
- PRINT_DEBUG_TODO();
-}
-
-bool Steam_User::IsPrimaryChatDestination()
-{
- PRINT_DEBUG_ENTRY();
- return false;
-}
-
-void Steam_User::RequestLegacyCDKey( uint32 iAppID )
-{
- PRINT_DEBUG_TODO();
-}
-
-bool Steam_User::SendGuestPassByEmail( const char *pchEmailAccount, GID_t gidGuestPassID, bool bResending )
-{
- PRINT_DEBUG_TODO();
- return false;
-}
-
-bool Steam_User::SendGuestPassByAccountID( uint32 uAccountID, GID_t gidGuestPassID, bool bResending )
-{
- PRINT_DEBUG_TODO();
- return false;
-}
-
-bool Steam_User::AckGuestPass(const char *pchGuestPassCode)
-{
- PRINT_DEBUG_TODO();
- return false;
-}
-
-bool Steam_User::RedeemGuestPass(const char *pchGuestPassCode)
-{
- PRINT_DEBUG_TODO();
- return false;
-}
-
-uint32 Steam_User::GetGuestPassToGiveCount()
-{
- PRINT_DEBUG_TODO();
- return 0;
-}
-
-uint32 Steam_User::GetGuestPassToRedeemCount()
-{
- PRINT_DEBUG_TODO();
- return 0;
-}
-
-RTime32 Steam_User::GetGuestPassLastUpdateTime()
-{
- PRINT_DEBUG_TODO();
- return 0;
-}
-
-bool Steam_User::GetGuestPassToGiveInfo( uint32 nPassIndex, GID_t *pgidGuestPassID, PackageId_t *pnPackageID, RTime32 *pRTime32Created, RTime32 *pRTime32Expiration, RTime32 *pRTime32Sent, RTime32 *pRTime32Redeemed, char *pchRecipientAddress, int cRecipientAddressSize )
-{
- PRINT_DEBUG_TODO();
- // TODO: pgidGuestPassID
- if (pnPackageID)
- *pnPackageID = 0;
- if (pRTime32Created)
- *pRTime32Created = 0;
- if (pRTime32Expiration)
- *pRTime32Expiration = 0;
- if (pRTime32Sent)
- *pRTime32Sent = 0;
- if (pRTime32Redeemed)
- *pRTime32Redeemed = 0;
- if (pchRecipientAddress && cRecipientAddressSize > 0)
- memset(pchRecipientAddress, 0, cRecipientAddressSize);
- return false;
-}
-
-bool Steam_User::GetGuestPassToRedeemInfo( uint32 nPassIndex, GID_t *pgidGuestPassID, PackageId_t *pnPackageID, RTime32 *pRTime32Created, RTime32 *pRTime32Expiration, RTime32 *pRTime32Sent, RTime32 *pRTime32Redeemed)
-{
- PRINT_DEBUG_TODO();
- // TODO: pgidGuestPassID
- if (pnPackageID)
- *pnPackageID = 0;
- if (pRTime32Created)
- *pRTime32Created = 0;
- if (pRTime32Expiration)
- *pRTime32Expiration = 0;
- if (pRTime32Sent)
- *pRTime32Sent = 0;
- if (pRTime32Redeemed)
- *pRTime32Redeemed = 0;
- return false;
-}
-
-bool Steam_User::GetGuestPassToRedeemSenderAddress( uint32 nPassIndex, char* pchSenderAddress, int cSenderAddressSize )
-{
- PRINT_DEBUG_TODO();
- return false;
-}
-
-bool Steam_User::GetGuestPassToRedeemSenderName( uint32 nPassIndex, char* pchSenderName, int cSenderNameSize )
-{
- PRINT_DEBUG_TODO();
- if (pchSenderName && cSenderNameSize > 0)
- memset(pchSenderName, 0, cSenderNameSize);
- return false;
-}
-
-void Steam_User::AcknowledgeMessageByGID( const char *pchMessageGID )
-{
- PRINT_DEBUG_TODO();
-}
-
-bool Steam_User::SetLanguage( const char *pchLanguage )
-{
- PRINT_DEBUG_TODO();
- // TODO: don't know what this api actually does other than returning true
- return true;
-}
-
-// used by only a few games to track usage events
-void Steam_User::TrackAppUsageEvent( CGameID gameID, int eAppUsageEvent, const char *pchExtraInfo)
-{
- PRINT_DEBUG_TODO();
-}
-
-void Steam_User::SetAccountName( const char *pchAccountName )
-{
- PRINT_DEBUG_TODO();
-}
-
-void Steam_User::SetPassword( const char *pchPassword )
-{
- PRINT_DEBUG_TODO();
-}
-
-void Steam_User::SetAccountCreationTime( RTime32 rt )
-{
- PRINT_DEBUG_TODO();
-}
-
-void Steam_User::RefreshSteam2Login()
-{
- PRINT_DEBUG_TODO();
-}
-
-// get the local storage folder for current Steam account to write application data, e.g. save games, configs etc.
-// this will usually be something like "C:\Progam Files\Steam\userdata\\\local"
-bool Steam_User::GetUserDataFolder( char *pchBuffer, int cubBuffer )
-{
- PRINT_DEBUG_ENTRY();
- if (!cubBuffer || cubBuffer <= 0) return false;
-
- std::string user_data = local_storage->get_path(Local_Storage::user_data_storage);
- if (static_cast(cubBuffer) <= user_data.size()) return false;
-
- strncpy(pchBuffer, user_data.c_str(), cubBuffer - 1);
- pchBuffer[cubBuffer - 1] = 0;
- return true;
-}
-
-// Starts voice recording. Once started, use GetVoice() to get the data
-void Steam_User::StartVoiceRecording( )
-{
- PRINT_DEBUG_ENTRY();
- last_get_voice = std::chrono::high_resolution_clock::now();
- recording = true;
- //TODO:fix
- recording = false;
-}
-
-// Stops voice recording. Because people often release push-to-talk keys early, the system will keep recording for
-// a little bit after this function is called. GetVoice() should continue to be called until it returns
-// k_eVoiceResultNotRecording
-void Steam_User::StopVoiceRecording( )
-{
- PRINT_DEBUG_ENTRY();
- recording = false;
-}
-
-// Determine the size of captured audio data that is available from GetVoice.
-// Most applications will only use compressed data and should ignore the other
-// parameters, which exist primarily for backwards compatibility. See comments
-// below for further explanation of "uncompressed" data.
-EVoiceResult Steam_User::GetAvailableVoice( uint32 *pcbCompressed, uint32 *pcbUncompressed_Deprecated, uint32 nUncompressedVoiceDesiredSampleRate_Deprecated )
-{
- PRINT_DEBUG_ENTRY();
- if (pcbCompressed) *pcbCompressed = 0;
- if (pcbUncompressed_Deprecated) *pcbUncompressed_Deprecated = 0;
- if (!recording) return k_EVoiceResultNotRecording;
- double seconds = std::chrono::duration_cast>(std::chrono::high_resolution_clock::now() - last_get_voice).count();
- if (pcbCompressed) *pcbCompressed = static_cast(seconds * 1024.0 * 64.0 / 8.0);
- if (pcbUncompressed_Deprecated) *pcbUncompressed_Deprecated = static_cast(seconds * (double)nUncompressedVoiceDesiredSampleRate_Deprecated * 2.0);
-
- return k_EVoiceResultOK;
-}
-
-EVoiceResult Steam_User::GetAvailableVoice(uint32 *pcbCompressed, uint32 *pcbUncompressed)
-{
- PRINT_DEBUG("old");
- return GetAvailableVoice(pcbCompressed, pcbUncompressed, 11025);
-}
-
-// ---------------------------------------------------------------------------
-// NOTE: "uncompressed" audio is a deprecated feature and should not be used
-// by most applications. It is raw single-channel 16-bit PCM wave data which
-// may have been run through preprocessing filters and/or had silence removed,
-// so the uncompressed audio could have a shorter duration than you expect.
-// There may be no data at all during long periods of silence. Also, fetching
-// uncompressed audio will cause GetVoice to discard any leftover compressed
-// audio, so you must fetch both types at once. Finally, GetAvailableVoice is
-// not precisely accurate when the uncompressed size is requested. So if you
-// really need to use uncompressed audio, you should call GetVoice frequently
-// with two very large (20kb+) output buffers instead of trying to allocate
-// perfectly-sized buffers. But most applications should ignore all of these
-// details and simply leave the "uncompressed" parameters as NULL/zero.
-// ---------------------------------------------------------------------------
-
-// Read captured audio data from the microphone buffer. This should be called
-// at least once per frame, and preferably every few milliseconds, to keep the
-// microphone input delay as low as possible. Most applications will only use
-// compressed data and should pass NULL/zero for the "uncompressed" parameters.
-// Compressed data can be transmitted by your application and decoded into raw
-// using the DecompressVoice function below.
-EVoiceResult Steam_User::GetVoice( bool bWantCompressed, void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten, bool bWantUncompressed_Deprecated, void *pUncompressedDestBuffer_Deprecated , uint32 cbUncompressedDestBufferSize_Deprecated , uint32 *nUncompressBytesWritten_Deprecated , uint32 nUncompressedVoiceDesiredSampleRate_Deprecated )
-{
- PRINT_DEBUG_ENTRY();
- if (!recording) return k_EVoiceResultNotRecording;
-
- double seconds = std::chrono::duration_cast>(std::chrono::high_resolution_clock::now() - last_get_voice).count();
- if (bWantCompressed) {
- uint32 towrite = static_cast(seconds * 1024.0 * 64.0 / 8.0);
- if (cbDestBufferSize < towrite) towrite = cbDestBufferSize;
- if (pDestBuffer) memset(pDestBuffer, 0, towrite);
- if (nBytesWritten) *nBytesWritten = towrite;
- }
-
- if (bWantUncompressed_Deprecated) {
- PRINT_DEBUG("Wanted Uncompressed");
- }
-
- last_get_voice = std::chrono::high_resolution_clock::now();
- return k_EVoiceResultOK;
-}
-
-EVoiceResult Steam_User::GetVoice( bool bWantCompressed, void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten, bool bWantUncompressed, void *pUncompressedDestBuffer, uint32 cbUncompressedDestBufferSize, uint32 *nUncompressBytesWritten )
-{
- PRINT_DEBUG("old");
- return GetVoice(bWantCompressed, pDestBuffer, cbDestBufferSize, nBytesWritten, bWantUncompressed, pUncompressedDestBuffer, cbUncompressedDestBufferSize, nUncompressBytesWritten, 11025);
-}
-
-EVoiceResult Steam_User::GetCompressedVoice( void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten )
-{
- PRINT_DEBUG_ENTRY();
- return GetVoice(true, pDestBuffer, cbDestBufferSize, nBytesWritten, false, NULL, 0, NULL);
-}
-
-// Decodes the compressed voice data returned by GetVoice. The output data is
-// raw single-channel 16-bit PCM audio. The decoder supports any sample rate
-// from 11025 to 48000; see GetVoiceOptimalSampleRate() below for details.
-// If the output buffer is not large enough, then *nBytesWritten will be set
-// to the required buffer size, and k_EVoiceResultBufferTooSmall is returned.
-// It is suggested to start with a 20kb buffer and reallocate as necessary.
-EVoiceResult Steam_User::DecompressVoice( const void *pCompressed, uint32 cbCompressed, void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten, uint32 nDesiredSampleRate )
-{
- PRINT_DEBUG_ENTRY();
- if (!recording) return k_EVoiceResultNotRecording;
-
- uint32 uncompressed = static_cast((double)cbCompressed * ((double)nDesiredSampleRate / 8192.0));
- if(nBytesWritten) *nBytesWritten = uncompressed;
- if (uncompressed > cbDestBufferSize) uncompressed = cbDestBufferSize;
- if (pDestBuffer) memset(pDestBuffer, 0, uncompressed);
-
- return k_EVoiceResultOK;
-}
-
-EVoiceResult Steam_User::DecompressVoice( const void *pCompressed, uint32 cbCompressed, void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten )
-{
- PRINT_DEBUG("old");
- return DecompressVoice(pCompressed, cbCompressed, pDestBuffer, cbDestBufferSize, nBytesWritten, 11025);
-}
-
-EVoiceResult Steam_User::DecompressVoice( void *pCompressed, uint32 cbCompressed, void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten )
-{
- PRINT_DEBUG("older");
- return DecompressVoice(pCompressed, cbCompressed, pDestBuffer, cbDestBufferSize, nBytesWritten, 11025);
-}
-
-// This returns the native sample rate of the Steam voice decompressor
-// this sample rate for DecompressVoice will perform the least CPU processing.
-// However, the final audio quality will depend on how well the audio device
-// (and/or your application's audio output SDK) deals with lower sample rates.
-// You may find that you get the best audio output quality when you ignore
-// this function and use the native sample rate of your audio output device,
-// which is usually 48000 or 44100.
-uint32 Steam_User::GetVoiceOptimalSampleRate()
-{
- PRINT_DEBUG_ENTRY();
- return 48000;
-}
-
-// Retrieve ticket to be sent to the entity who wishes to authenticate you.
-// pcbTicket retrieves the length of the actual ticket.
-HAuthTicket Steam_User::GetAuthSessionTicket( void *pTicket, int cbMaxTicket, uint32 *pcbTicket )
-{
- return GetAuthSessionTicket(pTicket, cbMaxTicket, pcbTicket, NULL);
-}
-// SteamNetworkingIdentity is an optional input parameter to hold the public IP address or SteamID of the entity you are connecting to
-// if an IP address is passed Steam will only allow the ticket to be used by an entity with that IP address
-// if a Steam ID is passed Steam will only allow the ticket to be used by that Steam ID
-HAuthTicket Steam_User::GetAuthSessionTicket( void *pTicket, int cbMaxTicket, uint32 *pcbTicket, const SteamNetworkingIdentity *pSteamNetworkingIdentity )
-{
- PRINT_DEBUG("%p [%i] %p", pTicket, cbMaxTicket, pcbTicket);
- std::lock_guard lock(global_mutex);
-
- if (!pTicket) return k_HAuthTicketInvalid;
-
- return auth_manager->getTicket(pTicket, cbMaxTicket, pcbTicket);
-}
-
-// Request a ticket which will be used for webapi "ISteamUserAuth\AuthenticateUserTicket"
-// pchIdentity is an optional input parameter to identify the service the ticket will be sent to
-// the ticket will be returned in callback GetTicketForWebApiResponse_t
-HAuthTicket Steam_User::GetAuthTicketForWebApi( const char *pchIdentity )
-{
- PRINT_DEBUG("'%s'", pchIdentity);
- std::lock_guard lock(global_mutex);
-
- return auth_manager->getWebApiTicket(pchIdentity);
-}
-
-// Authenticate ticket from entity steamID to be sure it is valid and isnt reused
-// Registers for callbacks if the entity goes offline or cancels the ticket ( see ValidateAuthTicketResponse_t callback and EAuthSessionResponse )
-EBeginAuthSessionResult Steam_User::BeginAuthSession( const void *pAuthTicket, int cbAuthTicket, CSteamID steamID )
-{
- PRINT_DEBUG("%i %llu", cbAuthTicket, steamID.ConvertToUint64());
- std::lock_guard lock(global_mutex);
-
- return auth_manager->beginAuth(pAuthTicket, cbAuthTicket, steamID);
-}
-
-// Stop tracking started by BeginAuthSession - called when no longer playing game with this entity
-void Steam_User::EndAuthSession( CSteamID steamID )
-{
- PRINT_DEBUG_ENTRY();
- std::lock_guard lock(global_mutex);
-
- auth_manager->endAuth(steamID);
-}
-
-// Cancel auth ticket from GetAuthSessionTicket, called when no longer playing game with the entity you gave the ticket to
-void Steam_User::CancelAuthTicket( HAuthTicket hAuthTicket )
-{
- PRINT_DEBUG_ENTRY();
- std::lock_guard lock(global_mutex);
-
- auth_manager->cancelTicket(hAuthTicket);
-}
-
-// After receiving a user's authentication data, and passing it to BeginAuthSession, use this function
-// to determine if the user owns downloadable content specified by the provided AppID.
-EUserHasLicenseForAppResult Steam_User::UserHasLicenseForApp( CSteamID steamID, AppId_t appID )
-{
- PRINT_DEBUG_ENTRY();
- return k_EUserHasLicenseResultHasLicense;
-}
-
-// returns true if this users looks like they are behind a NAT device. Only valid once the user has connected to steam
-// (i.e a SteamServersConnected_t has been issued) and may not catch all forms of NAT.
-bool Steam_User::BIsBehindNAT()
-{
- PRINT_DEBUG_ENTRY();
- return false;
-}
-
-// set data to be replicated to friends so that they can join your game
-// CSteamID steamIDGameServer - the steamID of the game server, received from the game server by the client
-// uint32 unIPServer, uint16 usPortServer - the IP address of the game server
-void Steam_User::AdvertiseGame( CSteamID steamIDGameServer, uint32 unIPServer, uint16 usPortServer )
-{
- PRINT_DEBUG_ENTRY();
- std::lock_guard lock(global_mutex);
- Gameserver *server = new Gameserver();
- server->set_id(steamIDGameServer.ConvertToUint64());
- server->set_ip(unIPServer);
- server->set_port(usPortServer);
- server->set_query_port(usPortServer);
- server->set_appid(settings->get_local_game_id().AppID());
-
- if (settings->matchmaking_server_list_always_lan_type)
- server->set_type(eLANServer);
- else
- server->set_type(eFriendsServer);
-
- Common_Message msg;
- msg.set_allocated_gameserver(server);
- msg.set_source_id(settings->get_local_steam_id().ConvertToUint64());
- network->sendToAllIndividuals(&msg, true);
-}
-
-// Requests a ticket encrypted with an app specific shared key
-// pDataToInclude, cbDataToInclude will be encrypted into the ticket
-// ( This is asynchronous, you must wait for the ticket to be completed by the server )
-STEAM_CALL_RESULT( EncryptedAppTicketResponse_t )
-SteamAPICall_t Steam_User::RequestEncryptedAppTicket( void *pDataToInclude, int cbDataToInclude )
-{
- PRINT_DEBUG("%i %p", cbDataToInclude, pDataToInclude);
- std::lock_guard lock(global_mutex);
- EncryptedAppTicketResponse_t data;
- data.m_eResult = k_EResultOK;
-
- DecryptedAppTicket ticket;
- ticket.TicketV1.Reset();
- ticket.TicketV2.Reset();
- ticket.TicketV4.Reset();
-
- ticket.TicketV1.TicketVersion = 1;
- if (pDataToInclude) {
- ticket.TicketV1.UserData.assign((uint8_t*)pDataToInclude, (uint8_t*)pDataToInclude + cbDataToInclude);
- }
-
- ticket.TicketV2.TicketVersion = 4;
- ticket.TicketV2.SteamID = settings->get_local_steam_id().ConvertToUint64();
- ticket.TicketV2.TicketIssueTime = static_cast(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count());
- ticket.TicketV2.TicketValidityEnd = ticket.TicketV2.TicketIssueTime + (21 * 24 * 60 * 60);
-
- for (int i = 0; i < 140; ++i)
- {
- AppId_t appid{};
- bool available{};
- std::string name{};
- if (!settings->getDLC(appid, appid, available, name)) break;
- ticket.TicketV4.AppIDs.emplace_back(appid);
- }
-
- ticket.TicketV4.HasVACStatus = true;
- ticket.TicketV4.VACStatus = 0;
-
- auto serialized = ticket.SerializeTicket();
-
- SteamAppTicket_pb pb;
- pb.set_ticket_version_no(1);
- pb.set_crc_encryptedticket(0); // TODO: Find out how to compute the CRC
- pb.set_cb_encrypteduserdata(cbDataToInclude);
- pb.set_cb_encrypted_appownershipticket(static_cast(serialized.size()) - 16);
- pb.mutable_encrypted_ticket()->assign(serialized.begin(), serialized.end()); // TODO: Find how to encrypt datas
-
- encrypted_app_ticket = pb.SerializeAsString();
-
+ std::random_device rd{};
+ std::mt19937 gen(rd());
+ std::uniform_int_distribution distrib(117, 1017);
+
+ NumberOfCurrentPlayers_t data{};
+ data.m_bSuccess = 1;
+ data.m_cPlayers = distrib(gen);
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
return ret;
}
-// retrieve a finished ticket
-bool Steam_User::GetEncryptedAppTicket( void *pTicket, int cbMaxTicket, uint32 *pcbTicket )
-{
- PRINT_DEBUG("%i %p %p", cbMaxTicket, pTicket, pcbTicket);
- uint32 ticket_size = static_cast(encrypted_app_ticket.size());
- if (pcbTicket) *pcbTicket = ticket_size;
- if (cbMaxTicket <= 0) {
- if (!pcbTicket) return false;
- return true;
+
+// --- old interface version
+
+uint32 Steam_User_Stats::GetNumStats( CGameID nGameID )
+{
+ PRINT_DEBUG("old %llu", nGameID.ToUint64());
+ std::lock_guard lock(global_mutex);
+ if (settings->get_local_game_id() != nGameID) {
+ return 0;
+ }
+ return (uint32)settings->getStats().size();
+}
+
+const char *Steam_User_Stats::GetStatName( CGameID nGameID, uint32 iStat )
+{
+ PRINT_DEBUG("old %llu [%u]", nGameID.ToUint64(), iStat);
+ std::lock_guard lock(global_mutex);
+
+ auto &stats = settings->getStats();
+ if (settings->get_local_game_id() != nGameID || iStat >= stats.size()) {
+ return "";
+ }
+
+ return std::next(stats.begin(), iStat)->first.c_str();
+}
+
+ESteamUserStatType Steam_User_Stats::GetStatType( CGameID nGameID, const char *pchName )
+{
+ PRINT_DEBUG("old %llu '%s'", nGameID.ToUint64(), pchName);
+ std::lock_guard lock(global_mutex);
+
+ if (settings->get_local_game_id() != nGameID || !pchName) {
+ return ESteamUserStatType::k_ESteamUserStatTypeINVALID;
+ }
+
+ std::string stat_name(common_helpers::to_lower(pchName));
+ const auto &stats = settings->getStats();
+ auto stat_info = stats.find(stat_name);
+ if (stats.end() == stat_info) {
+ return ESteamUserStatType::k_ESteamUserStatTypeINVALID;
}
- if (!pTicket) return false;
- if (ticket_size > static_cast(cbMaxTicket)) return false;
- encrypted_app_ticket.copy((char *)pTicket, cbMaxTicket);
-
- PRINT_DEBUG("copied successfully");
- return true;
+ switch (stat_info->second.type)
+ {
+ case GameServerStats_Messages::StatInfo::STAT_TYPE_INT: return ESteamUserStatType::k_ESteamUserStatTypeINT;
+ case GameServerStats_Messages::StatInfo::STAT_TYPE_FLOAT: return ESteamUserStatType::k_ESteamUserStatTypeFLOAT;
+ case GameServerStats_Messages::StatInfo::STAT_TYPE_AVGRATE: return ESteamUserStatType::k_ESteamUserStatTypeAVGRATE;
+
+ default: PRINT_DEBUG("[X] unhandled type %i", (int)stat_info->second.type); break;
+ }
+
+ return ESteamUserStatType::k_ESteamUserStatTypeINVALID;
}
-// Trading Card badges data access
-// if you only have one set of cards, the series will be 1
-// the user has can have two different badges for a series; the regular (max level 5) and the foil (max level 1)
-int Steam_User::GetGameBadgeLevel( int nSeries, bool bFoil )
+uint32 Steam_User_Stats::GetNumAchievements( CGameID nGameID )
{
- PRINT_DEBUG_ENTRY();
+ PRINT_DEBUG("old %llu", nGameID.ToUint64());
+ std::lock_guard lock(global_mutex);
+ if (settings->get_local_game_id() != nGameID) {
+ return 0;
+ }
+
+ return GetNumAchievements();
+}
+
+const char *Steam_User_Stats::GetAchievementName( CGameID nGameID, uint32 iAchievement )
+{
+ PRINT_DEBUG("old %llu [%u]", nGameID.ToUint64(), iAchievement);
+ std::lock_guard lock(global_mutex);
+ if (settings->get_local_game_id() != nGameID) {
+ return "";
+ }
+
+ return GetAchievementName(iAchievement);
+}
+
+uint32 Steam_User_Stats::GetNumGroupAchievements( CGameID nGameID )
+{
+ PRINT_DEBUG("old %llu // TODO", nGameID.ToUint64());
+ std::lock_guard lock(global_mutex);
+ if (settings->get_local_game_id() != nGameID) {
+ return 0;
+ }
+
return 0;
}
-// gets the Steam Level of the user, as shown on their profile
-int Steam_User::GetPlayerSteamLevel()
+const char *Steam_User_Stats::GetGroupAchievementName( CGameID nGameID, uint32 iAchievement )
{
- PRINT_DEBUG_ENTRY();
- return 100;
+ PRINT_DEBUG("old %llu [%u] // TODO", nGameID.ToUint64(), iAchievement);
+ std::lock_guard lock(global_mutex);
+ if (settings->get_local_game_id() != nGameID) {
+ return "";
+ }
+
+ return "";
}
-// Requests a URL which authenticates an in-game browser for store check-out,
-// and then redirects to the specified URL. As long as the in-game browser
-// accepts and handles session cookies, Steam microtransaction checkout pages
-// will automatically recognize the user instead of presenting a login page.
-// The result of this API call will be a StoreAuthURLResponse_t callback.
-// NOTE: The URL has a very short lifetime to prevent history-snooping attacks,
-// so you should only call this API when you are about to launch the browser,
-// or else immediately navigate to the result URL using a hidden browser window.
-// NOTE 2: The resulting authorization cookie has an expiration time of one day,
-// so it would be a good idea to request and visit a new auth URL every 12 hours.
-STEAM_CALL_RESULT( StoreAuthURLResponse_t )
-SteamAPICall_t Steam_User::RequestStoreAuthURL( const char *pchRedirectURL )
+bool Steam_User_Stats::RequestCurrentStats( CGameID nGameID )
{
- PRINT_DEBUG_TODO();
- return 0;
+ PRINT_DEBUG("old %llu", nGameID.ToUint64());
+ std::lock_guard lock(global_mutex);
+ if (settings->get_local_game_id() != nGameID) {
+ return false;
+ }
+
+ return RequestCurrentStats();
}
-// gets whether the users phone number is verified
-bool Steam_User::BIsPhoneVerified()
+bool Steam_User_Stats::GetStat( CGameID nGameID, const char *pchName, int32 *pData )
{
- PRINT_DEBUG_ENTRY();
- return true;
+ PRINT_DEBUG("old %llu '%s' %p", nGameID.ToUint64(), pchName, pData);
+ std::lock_guard lock(global_mutex);
+
+ if (pData) *pData = 0;
+ if (settings->get_local_game_id() != nGameID) {
+ return false;
+ }
+
+ return GetStat(pchName, pData);
}
-// gets whether the user has two factor enabled on their account
-bool Steam_User::BIsTwoFactorEnabled()
+bool Steam_User_Stats::GetStat( CGameID nGameID, const char *pchName, float *pData )
{
- PRINT_DEBUG_ENTRY();
- return true;
+ PRINT_DEBUG("old %llu '%s' %p", nGameID.ToUint64(), pchName, pData);
+ std::lock_guard lock(global_mutex);
+
+ if (pData) *pData = 0;
+ if (settings->get_local_game_id() != nGameID) {
+ return false;
+ }
+
+ return GetStat(pchName, pData);
}
-// gets whether the users phone number is identifying
-bool Steam_User::BIsPhoneIdentifying()
+bool Steam_User_Stats::SetStat( CGameID nGameID, const char *pchName, int32 nData )
{
- PRINT_DEBUG_ENTRY();
+ PRINT_DEBUG("old %llu '%s' %i", nGameID.ToUint64(), pchName, nData);
+ std::lock_guard lock(global_mutex);
+ if (settings->get_local_game_id() != nGameID) {
+ return false;
+ }
+
+ return SetStat(pchName, nData);
+}
+
+bool Steam_User_Stats::SetStat( CGameID nGameID, const char *pchName, float fData )
+{
+ PRINT_DEBUG("old %llu '%s' %f", nGameID.ToUint64(), pchName, fData);
+ std::lock_guard lock(global_mutex);
+ if (settings->get_local_game_id() != nGameID) {
+ return false;
+ }
+
+ return SetStat(pchName, fData);
+}
+
+bool Steam_User_Stats::UpdateAvgRateStat( CGameID nGameID, const char *pchName, float flCountThisSession, double dSessionLength )
+{
+ PRINT_DEBUG("old %llu '%s' %f %f", nGameID.ToUint64(), pchName, flCountThisSession, dSessionLength);
+ std::lock_guard lock(global_mutex);
+ if (settings->get_local_game_id() != nGameID) {
+ return false;
+ }
+
+ return UpdateAvgRateStat(pchName, flCountThisSession, dSessionLength);
+}
+
+bool Steam_User_Stats::GetAchievement( CGameID nGameID, const char *pchName, bool *pbAchieved )
+{
+ PRINT_DEBUG("old %llu '%s' %p", nGameID.ToUint64(), pchName, pbAchieved);
+ std::lock_guard lock(global_mutex);
+
+ if (pbAchieved) *pbAchieved = false;
+ if (settings->get_local_game_id() != nGameID) {
+ return false;
+ }
+
+ return GetAchievement(pchName, pbAchieved);
+}
+
+bool Steam_User_Stats::GetGroupAchievement( CGameID nGameID, const char *pchName, bool *pbAchieved )
+{
+ PRINT_DEBUG("old %llu '%s' %p // TODO", nGameID.ToUint64(), pchName, pbAchieved);
+ std::lock_guard lock(global_mutex);
+
+ if (pbAchieved) *pbAchieved = false;
+ if (settings->get_local_game_id() != nGameID) {
+ return false;
+ }
+
return false;
}
-// gets whether the users phone number is awaiting (re)verification
-bool Steam_User::BIsPhoneRequiringVerification()
+bool Steam_User_Stats::SetAchievement( CGameID nGameID, const char *pchName )
{
- PRINT_DEBUG_ENTRY();
+ PRINT_DEBUG("old %llu '%s'", nGameID.ToUint64(), pchName);
+ std::lock_guard lock(global_mutex);
+ if (settings->get_local_game_id() != nGameID && settings->achievement_bypass) {
+ return false;
+ }
+
+ return SetAchievement(pchName);
+}
+
+bool Steam_User_Stats::SetGroupAchievement( CGameID nGameID, const char *pchName )
+{
+ PRINT_DEBUG("old %llu '%s' // TODO", nGameID.ToUint64(), pchName);
+ std::lock_guard lock(global_mutex);
+ if (settings->get_local_game_id() != nGameID) {
+ return false;
+ }
+
return false;
}
-STEAM_CALL_RESULT( MarketEligibilityResponse_t )
-SteamAPICall_t Steam_User::GetMarketEligibility()
+bool Steam_User_Stats::StoreStats( CGameID nGameID )
{
- PRINT_DEBUG_TODO();
- return 0;
+ PRINT_DEBUG("old %llu", nGameID.ToUint64());
+ std::lock_guard lock(global_mutex);
+ if (settings->get_local_game_id() != nGameID) {
+ return false;
+ }
+
+ return StoreStats();
}
-// Retrieves anti indulgence / duration control for current user
-STEAM_CALL_RESULT( DurationControl_t )
-SteamAPICall_t Steam_User::GetDurationControl()
+bool Steam_User_Stats::ClearAchievement( CGameID nGameID, const char *pchName )
{
- PRINT_DEBUG_TODO();
- return 0;
+ PRINT_DEBUG("old %llu '%s'", nGameID.ToUint64(), pchName);
+ std::lock_guard lock(global_mutex);
+ if (settings->get_local_game_id() != nGameID) {
+ return false;
+ }
+
+ return ClearAchievement(pchName);
}
-// Advise steam china duration control system about the online state of the game.
-// This will prevent offline gameplay time from counting against a user's
-// playtime limits.
-bool Steam_User::BSetDurationControlOnlineState( EDurationControlOnlineState eNewState )
+bool Steam_User_Stats::ClearGroupAchievement( CGameID nGameID, const char *pchName )
{
- PRINT_DEBUG_ENTRY();
+ PRINT_DEBUG("old %llu '%s' // TODO", nGameID.ToUint64(), pchName);
+ std::lock_guard lock(global_mutex);
+ if (settings->get_local_game_id() != nGameID) {
+ return 0;
+ }
+
return false;
}
+
+int Steam_User_Stats::GetAchievementIcon( CGameID nGameID, const char *pchName )
+{
+ PRINT_DEBUG("old %llu '%s'", nGameID.ToUint64(), pchName);
+ std::lock_guard lock(global_mutex);
+ if (settings->get_local_game_id() != nGameID) {
+ return Settings::INVALID_IMAGE_HANDLE;
+ }
+
+ return GetAchievementIcon(pchName);
+}
+
+const char *Steam_User_Stats::GetAchievementDisplayAttribute( CGameID nGameID, const char *pchName, const char *pchKey )
+{
+ PRINT_DEBUG("old %llu '%s' ['%s']", nGameID.ToUint64(), pchName, pchKey);
+ std::lock_guard lock(global_mutex);
+ if (settings->get_local_game_id() != nGameID) {
+ return "";
+ }
+
+ return GetAchievementDisplayAttribute(pchName, pchKey);
+}
+
+bool Steam_User_Stats::IndicateAchievementProgress( CGameID nGameID, const char *pchName, uint32 nCurProgress, uint32 nMaxProgress )
+{
+ PRINT_DEBUG("old %llu '%s' %u %u", nGameID.ToUint64(), pchName, nCurProgress, nMaxProgress);
+ std::lock_guard lock(global_mutex);
+ if (settings->get_local_game_id() != nGameID) {
+ return false;
+ }
+
+ return IndicateAchievementProgress(pchName, nCurProgress, nMaxProgress);
+}
+
+
+// --- steam callbacks
+
+void Steam_User_Stats::steam_run_callback()
+{
+ send_updated_stats();
+ load_achievements_icons();
+}
+
+
+
+// --- networking callbacks
+// only triggered when we have a message
+
+// user connect/disconnect
+void Steam_User_Stats::network_callback_low_level(Common_Message *msg)
+{
+ CSteamID steamid((uint64)msg->source_id());
+ // this should never happen, but just in case
+ if (steamid == settings->get_local_steam_id()) return;
+
+ switch (msg->low_level().type())
+ {
+ case Low_Level::CONNECT:
+ // nothing
+ break;
+
+ case Low_Level::DISCONNECT: {
+ for (auto &board : cached_leaderboards) {
+ board.remove_entries(steamid);
+ }
+
+ // PRINT_DEBUG("removed user %llu", (uint64)steamid.ConvertToUint64());
+ }
+ break;
+
+ default:
+ PRINT_DEBUG("unknown type %i", (int)msg->low_level().type());
+ break;
+ }
+}