mirror of
https://github.com/ValveSoftware/Proton.git
synced 2024-12-27 23:25:50 +03:00
394 lines
16 KiB
C
394 lines
16 KiB
C
|
//====== Copyright Valve Corporation, All rights reserved. ====================
|
||
|
//
|
||
|
// Internal implementation details of the steamworks SDK.
|
||
|
//
|
||
|
// You should be able to figure out how to use the SDK by reading
|
||
|
// steam_api_common.h, and should not need to understand anything in here.
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
#ifdef STEAM_CALLBACK_BEGIN
|
||
|
#error "This file should only be included from steam_api_common.h"
|
||
|
#endif
|
||
|
|
||
|
#include <string.h>
|
||
|
|
||
|
// Internal functions used by the utility CCallback objects to receive callbacks
|
||
|
S_API void S_CALLTYPE SteamAPI_RegisterCallback( class CCallbackBase *pCallback, int iCallback );
|
||
|
S_API void S_CALLTYPE SteamAPI_UnregisterCallback( class CCallbackBase *pCallback );
|
||
|
// Internal functions used by the utility CCallResult objects to receive async call results
|
||
|
S_API void S_CALLTYPE SteamAPI_RegisterCallResult( class CCallbackBase *pCallback, SteamAPICall_t hAPICall );
|
||
|
S_API void S_CALLTYPE SteamAPI_UnregisterCallResult( class CCallbackBase *pCallback, SteamAPICall_t hAPICall );
|
||
|
|
||
|
S_API HSteamPipe S_CALLTYPE SteamAPI_GetHSteamPipe();
|
||
|
S_API HSteamUser S_CALLTYPE SteamAPI_GetHSteamUser();
|
||
|
S_API HSteamPipe S_CALLTYPE SteamGameServer_GetHSteamPipe();
|
||
|
S_API HSteamUser S_CALLTYPE SteamGameServer_GetHSteamUser();
|
||
|
S_API void *S_CALLTYPE SteamInternal_ContextInit( void *pContextInitData );
|
||
|
S_API void *S_CALLTYPE SteamInternal_CreateInterface( const char *ver );
|
||
|
S_API void *S_CALLTYPE SteamInternal_FindOrCreateUserInterface( HSteamUser hSteamUser, const char *pszVersion );
|
||
|
S_API void *S_CALLTYPE SteamInternal_FindOrCreateGameServerInterface( HSteamUser hSteamUser, const char *pszVersion );
|
||
|
|
||
|
// disable this warning; this pattern need for steam callback registration
|
||
|
#ifdef _MSVC_VER
|
||
|
#pragma warning( push )
|
||
|
#pragma warning( disable: 4355 ) // 'this' : used in base member initializer list
|
||
|
#endif
|
||
|
|
||
|
#define _STEAM_CALLBACK_AUTO_HOOK( thisclass, func, param )
|
||
|
#define _STEAM_CALLBACK_HELPER( _1, _2, SELECTED, ... ) _STEAM_CALLBACK_##SELECTED
|
||
|
#define _STEAM_CALLBACK_SELECT( X, Y ) _STEAM_CALLBACK_HELPER X Y
|
||
|
#define _STEAM_CALLBACK_3( extra_code, thisclass, func, param ) \
|
||
|
struct CCallbackInternal_ ## func : private CCallbackImpl< sizeof( param ) > { \
|
||
|
CCallbackInternal_ ## func () { extra_code SteamAPI_RegisterCallback( this, param::k_iCallback ); } \
|
||
|
CCallbackInternal_ ## func ( const CCallbackInternal_ ## func & ) { extra_code SteamAPI_RegisterCallback( this, param::k_iCallback ); } \
|
||
|
CCallbackInternal_ ## func & operator=( const CCallbackInternal_ ## func & ) { return *this; } \
|
||
|
private: virtual void Run( void *pvParam ) { _STEAM_CALLBACK_AUTO_HOOK( thisclass, func, param ) \
|
||
|
thisclass *pOuter = reinterpret_cast<thisclass*>( reinterpret_cast<char*>(this) - offsetof( thisclass, m_steamcallback_ ## func ) ); \
|
||
|
pOuter->func( reinterpret_cast<param*>( pvParam ) ); \
|
||
|
} \
|
||
|
} m_steamcallback_ ## func ; void func( param *pParam )
|
||
|
#define _STEAM_CALLBACK_4( _, thisclass, func, param, var ) \
|
||
|
CCallback< thisclass, param > var; void func( param *pParam )
|
||
|
#define _STEAM_CALLBACK_GS( _, thisclass, func, param, var ) \
|
||
|
CCallback< thisclass, param, true > var; void func( param *pParam )
|
||
|
|
||
|
template< class T, class P >
|
||
|
inline CCallResult<T, P>::CCallResult()
|
||
|
{
|
||
|
m_hAPICall = k_uAPICallInvalid;
|
||
|
m_pObj = nullptr;
|
||
|
m_Func = nullptr;
|
||
|
m_iCallback = P::k_iCallback;
|
||
|
}
|
||
|
|
||
|
template< class T, class P >
|
||
|
inline void CCallResult<T, P>::Set( SteamAPICall_t hAPICall, T *p, func_t func )
|
||
|
{
|
||
|
if ( m_hAPICall )
|
||
|
SteamAPI_UnregisterCallResult( this, m_hAPICall );
|
||
|
|
||
|
m_hAPICall = hAPICall;
|
||
|
m_pObj = p;
|
||
|
m_Func = func;
|
||
|
|
||
|
if ( hAPICall )
|
||
|
SteamAPI_RegisterCallResult( this, hAPICall );
|
||
|
}
|
||
|
|
||
|
template< class T, class P >
|
||
|
inline bool CCallResult<T, P>::IsActive() const
|
||
|
{
|
||
|
return (m_hAPICall != k_uAPICallInvalid);
|
||
|
}
|
||
|
|
||
|
template< class T, class P >
|
||
|
inline void CCallResult<T, P>::Cancel()
|
||
|
{
|
||
|
if ( m_hAPICall != k_uAPICallInvalid )
|
||
|
{
|
||
|
SteamAPI_UnregisterCallResult( this, m_hAPICall );
|
||
|
m_hAPICall = k_uAPICallInvalid;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template< class T, class P >
|
||
|
inline CCallResult<T, P>::~CCallResult()
|
||
|
{
|
||
|
Cancel();
|
||
|
}
|
||
|
|
||
|
template< class T, class P >
|
||
|
inline void CCallResult<T, P>::Run( void *pvParam )
|
||
|
{
|
||
|
m_hAPICall = k_uAPICallInvalid; // caller unregisters for us
|
||
|
(m_pObj->*m_Func)((P *)pvParam, false);
|
||
|
}
|
||
|
|
||
|
template< class T, class P >
|
||
|
inline void CCallResult<T, P>::Run( void *pvParam, bool bIOFailure, SteamAPICall_t hSteamAPICall )
|
||
|
{
|
||
|
if ( hSteamAPICall == m_hAPICall )
|
||
|
{
|
||
|
m_hAPICall = k_uAPICallInvalid; // caller unregisters for us
|
||
|
(m_pObj->*m_Func)((P *)pvParam, bIOFailure);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template< class T, class P, bool bGameserver >
|
||
|
inline CCallback< T, P, bGameserver >::CCallback( T *pObj, func_t func )
|
||
|
: m_pObj( nullptr ), m_Func( nullptr )
|
||
|
{
|
||
|
if ( bGameserver )
|
||
|
{
|
||
|
this->SetGameserverFlag();
|
||
|
}
|
||
|
Register( pObj, func );
|
||
|
}
|
||
|
|
||
|
template< class T, class P, bool bGameserver >
|
||
|
inline void CCallback< T, P, bGameserver >::Register( T *pObj, func_t func )
|
||
|
{
|
||
|
if ( !pObj || !func )
|
||
|
return;
|
||
|
|
||
|
if ( this->m_nCallbackFlags & CCallbackBase::k_ECallbackFlagsRegistered )
|
||
|
Unregister();
|
||
|
|
||
|
m_pObj = pObj;
|
||
|
m_Func = func;
|
||
|
// SteamAPI_RegisterCallback sets k_ECallbackFlagsRegistered
|
||
|
SteamAPI_RegisterCallback( this, P::k_iCallback );
|
||
|
}
|
||
|
|
||
|
template< class T, class P, bool bGameserver >
|
||
|
inline void CCallback< T, P, bGameserver >::Unregister()
|
||
|
{
|
||
|
// SteamAPI_UnregisterCallback removes k_ECallbackFlagsRegistered
|
||
|
SteamAPI_UnregisterCallback( this );
|
||
|
}
|
||
|
|
||
|
template< class T, class P, bool bGameserver >
|
||
|
inline void CCallback< T, P, bGameserver >::Run( void *pvParam )
|
||
|
{
|
||
|
(m_pObj->*m_Func)((P *)pvParam);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Macros to define steam callback structures. Used internally for debugging
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
#ifdef STEAM_CALLBACK_INSPECTION_ENABLED
|
||
|
#include "../../clientdll/steam_api_callback_inspection.h"
|
||
|
#else
|
||
|
#define STEAM_CALLBACK_BEGIN( callbackname, callbackid ) struct callbackname { enum { k_iCallback = callbackid };
|
||
|
#define STEAM_CALLBACK_MEMBER( varidx, vartype, varname ) vartype varname ;
|
||
|
#define STEAM_CALLBACK_MEMBER_ARRAY( varidx, vartype, varname, varcount ) vartype varname [ varcount ];
|
||
|
#define STEAM_CALLBACK_END(nArgs) };
|
||
|
#endif
|
||
|
|
||
|
// Forward declare all of the Steam interfaces. (Do we really need to do this?)
|
||
|
class ISteamClient;
|
||
|
class ISteamUser;
|
||
|
class ISteamGameServer;
|
||
|
class ISteamFriends;
|
||
|
class ISteamUtils;
|
||
|
class ISteamMatchmaking;
|
||
|
class ISteamContentServer;
|
||
|
class ISteamMatchmakingServers;
|
||
|
class ISteamUserStats;
|
||
|
class ISteamApps;
|
||
|
class ISteamNetworking;
|
||
|
class ISteamRemoteStorage;
|
||
|
class ISteamScreenshots;
|
||
|
class ISteamMusic;
|
||
|
class ISteamMusicRemote;
|
||
|
class ISteamGameServerStats;
|
||
|
class ISteamPS3OverlayRender;
|
||
|
class ISteamHTTP;
|
||
|
class ISteamController;
|
||
|
class ISteamUGC;
|
||
|
class ISteamAppList;
|
||
|
class ISteamHTMLSurface;
|
||
|
class ISteamInventory;
|
||
|
class ISteamVideo;
|
||
|
class ISteamParentalSettings;
|
||
|
class ISteamGameSearch;
|
||
|
class ISteamInput;
|
||
|
class ISteamParties;
|
||
|
class ISteamTV;
|
||
|
class ISteamRemotePlay;
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: Base values for callback identifiers, each callback must
|
||
|
// have a unique ID.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
enum { k_iSteamUserCallbacks = 100 };
|
||
|
enum { k_iSteamGameServerCallbacks = 200 };
|
||
|
enum { k_iSteamFriendsCallbacks = 300 };
|
||
|
enum { k_iSteamBillingCallbacks = 400 };
|
||
|
enum { k_iSteamMatchmakingCallbacks = 500 };
|
||
|
enum { k_iSteamContentServerCallbacks = 600 };
|
||
|
enum { k_iSteamUtilsCallbacks = 700 };
|
||
|
enum { k_iClientFriendsCallbacks = 800 };
|
||
|
enum { k_iClientUserCallbacks = 900 };
|
||
|
enum { k_iSteamAppsCallbacks = 1000 };
|
||
|
enum { k_iSteamUserStatsCallbacks = 1100 };
|
||
|
enum { k_iSteamNetworkingCallbacks = 1200 };
|
||
|
enum { k_iSteamNetworkingSocketsCallbacks = 1220 };
|
||
|
enum { k_iSteamNetworkingMessagesCallbacks = 1250 };
|
||
|
enum { k_iSteamNetworkingUtilsCallbacks = 1280 };
|
||
|
enum { k_iClientRemoteStorageCallbacks = 1300 };
|
||
|
enum { k_iClientDepotBuilderCallbacks = 1400 };
|
||
|
enum { k_iSteamGameServerItemsCallbacks = 1500 };
|
||
|
enum { k_iClientUtilsCallbacks = 1600 };
|
||
|
enum { k_iSteamGameCoordinatorCallbacks = 1700 };
|
||
|
enum { k_iSteamGameServerStatsCallbacks = 1800 };
|
||
|
enum { k_iSteam2AsyncCallbacks = 1900 };
|
||
|
enum { k_iSteamGameStatsCallbacks = 2000 };
|
||
|
enum { k_iClientHTTPCallbacks = 2100 };
|
||
|
enum { k_iClientScreenshotsCallbacks = 2200 };
|
||
|
enum { k_iSteamScreenshotsCallbacks = 2300 };
|
||
|
enum { k_iClientAudioCallbacks = 2400 };
|
||
|
enum { k_iClientUnifiedMessagesCallbacks = 2500 };
|
||
|
enum { k_iSteamStreamLauncherCallbacks = 2600 };
|
||
|
enum { k_iClientControllerCallbacks = 2700 };
|
||
|
enum { k_iSteamControllerCallbacks = 2800 };
|
||
|
enum { k_iClientParentalSettingsCallbacks = 2900 };
|
||
|
enum { k_iClientDeviceAuthCallbacks = 3000 };
|
||
|
enum { k_iClientNetworkDeviceManagerCallbacks = 3100 };
|
||
|
enum { k_iClientMusicCallbacks = 3200 };
|
||
|
enum { k_iClientRemoteClientManagerCallbacks = 3300 };
|
||
|
enum { k_iClientUGCCallbacks = 3400 };
|
||
|
enum { k_iSteamStreamClientCallbacks = 3500 };
|
||
|
enum { k_IClientProductBuilderCallbacks = 3600 };
|
||
|
enum { k_iClientShortcutsCallbacks = 3700 };
|
||
|
enum { k_iClientRemoteControlManagerCallbacks = 3800 };
|
||
|
enum { k_iSteamAppListCallbacks = 3900 };
|
||
|
enum { k_iSteamMusicCallbacks = 4000 };
|
||
|
enum { k_iSteamMusicRemoteCallbacks = 4100 };
|
||
|
enum { k_iClientVRCallbacks = 4200 };
|
||
|
enum { k_iClientGameNotificationCallbacks = 4300 };
|
||
|
enum { k_iSteamGameNotificationCallbacks = 4400 };
|
||
|
enum { k_iSteamHTMLSurfaceCallbacks = 4500 };
|
||
|
enum { k_iClientVideoCallbacks = 4600 };
|
||
|
enum { k_iClientInventoryCallbacks = 4700 };
|
||
|
enum { k_iClientBluetoothManagerCallbacks = 4800 };
|
||
|
enum { k_iClientSharedConnectionCallbacks = 4900 };
|
||
|
enum { k_ISteamParentalSettingsCallbacks = 5000 };
|
||
|
enum { k_iClientShaderCallbacks = 5100 };
|
||
|
enum { k_iSteamGameSearchCallbacks = 5200 };
|
||
|
enum { k_iSteamPartiesCallbacks = 5300 };
|
||
|
enum { k_iClientPartiesCallbacks = 5400 };
|
||
|
enum { k_iSteamSTARCallbacks = 5500 };
|
||
|
enum { k_iClientSTARCallbacks = 5600 };
|
||
|
enum { k_iSteamRemotePlayCallbacks = 5700 };
|
||
|
|
||
|
// Macro used to define a type-safe accessor that will always return the version
|
||
|
// of the interface of the *header file* you are compiling with! We also bounce
|
||
|
// through a safety function that checks for interfaces being created or destroyed.
|
||
|
#ifndef STEAM_API_EXPORTS
|
||
|
// SteamInternal_ContextInit takes a base pointer for the equivalent of
|
||
|
// struct { void (*pFn)(void* pCtx); uintp counter; CSteamAPIContext ctx; }
|
||
|
// Do not change layout of 2 + sizeof... or add non-pointer aligned data!
|
||
|
// NOTE: declaring "static CSteamAPIConext" creates a large function
|
||
|
// which queries the initialization status of the object. We know that
|
||
|
// it is pointer-aligned and fully memset with zeros, so just alias a
|
||
|
// static buffer of the appropriate size and call it a CSteamAPIContext.
|
||
|
#define STEAM_DEFINE_INTERFACE_ACCESSOR( type, name, expr ) \
|
||
|
inline void S_CALLTYPE SteamInternal_Init_ ## name( type *p ) { *p = (type)( expr ); } \
|
||
|
inline type name() { \
|
||
|
static void* s_CallbackCounterAndContext[ 3 ] = { (void*)&SteamInternal_Init_ ## name, 0, 0 }; \
|
||
|
return *(type*)SteamInternal_ContextInit( s_CallbackCounterAndContext ); \
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
// Stub when we're compiling steam_api.dll itself. These are inline
|
||
|
// functions defined when the header is included. not functions exported
|
||
|
// by the lib!
|
||
|
#define STEAM_DEFINE_INTERFACE_ACCESSOR( type, name, expr )
|
||
|
#endif
|
||
|
|
||
|
#define STEAM_DEFINE_USER_INTERFACE_ACCESSOR( type, name, version ) \
|
||
|
STEAM_DEFINE_INTERFACE_ACCESSOR( type, name, SteamInternal_FindOrCreateUserInterface( SteamAPI_GetHSteamUser(), version ) )
|
||
|
#define STEAM_DEFINE_GAMESERVER_INTERFACE_ACCESSOR( type, name, version ) \
|
||
|
STEAM_DEFINE_INTERFACE_ACCESSOR( type, name, SteamInternal_FindOrCreateGameServerInterface( SteamGameServer_GetHSteamUser(), version ) )
|
||
|
|
||
|
#ifdef _MSVC_VER
|
||
|
#pragma warning( pop )
|
||
|
#endif
|
||
|
|
||
|
// CSteamAPIContext encapsulates the Steamworks API global accessors into
|
||
|
// a single object.
|
||
|
//
|
||
|
// DEPRECATED: Used the global interface accessors instead!
|
||
|
//
|
||
|
// This will be removed in a future iteration of the SDK
|
||
|
class CSteamAPIContext
|
||
|
{
|
||
|
public:
|
||
|
CSteamAPIContext() { Clear(); }
|
||
|
inline void Clear() { memset( this, 0, sizeof(*this) ); }
|
||
|
inline bool Init(); // NOTE: This is defined in steam_api.h, to avoid this file having to include everything
|
||
|
ISteamClient* SteamClient() const { return m_pSteamClient; }
|
||
|
ISteamUser* SteamUser() const { return m_pSteamUser; }
|
||
|
ISteamFriends* SteamFriends() const { return m_pSteamFriends; }
|
||
|
ISteamUtils* SteamUtils() const { return m_pSteamUtils; }
|
||
|
ISteamMatchmaking* SteamMatchmaking() const { return m_pSteamMatchmaking; }
|
||
|
ISteamGameSearch* SteamGameSearch() const { return m_pSteamGameSearch; }
|
||
|
ISteamUserStats* SteamUserStats() const { return m_pSteamUserStats; }
|
||
|
ISteamApps* SteamApps() const { return m_pSteamApps; }
|
||
|
ISteamMatchmakingServers* SteamMatchmakingServers() const { return m_pSteamMatchmakingServers; }
|
||
|
ISteamNetworking* SteamNetworking() const { return m_pSteamNetworking; }
|
||
|
ISteamRemoteStorage* SteamRemoteStorage() const { return m_pSteamRemoteStorage; }
|
||
|
ISteamScreenshots* SteamScreenshots() const { return m_pSteamScreenshots; }
|
||
|
ISteamHTTP* SteamHTTP() const { return m_pSteamHTTP; }
|
||
|
ISteamController* SteamController() const { return m_pController; }
|
||
|
ISteamUGC* SteamUGC() const { return m_pSteamUGC; }
|
||
|
ISteamAppList* SteamAppList() const { return m_pSteamAppList; }
|
||
|
ISteamMusic* SteamMusic() const { return m_pSteamMusic; }
|
||
|
ISteamMusicRemote* SteamMusicRemote() const { return m_pSteamMusicRemote; }
|
||
|
ISteamHTMLSurface* SteamHTMLSurface() const { return m_pSteamHTMLSurface; }
|
||
|
ISteamInventory* SteamInventory() const { return m_pSteamInventory; }
|
||
|
ISteamVideo* SteamVideo() const { return m_pSteamVideo; }
|
||
|
ISteamTV* SteamTV() const { return m_pSteamTV; }
|
||
|
ISteamParentalSettings* SteamParentalSettings() const { return m_pSteamParentalSettings; }
|
||
|
ISteamInput* SteamInput() const { return m_pSteamInput; }
|
||
|
private:
|
||
|
ISteamClient *m_pSteamClient;
|
||
|
ISteamUser *m_pSteamUser;
|
||
|
ISteamFriends *m_pSteamFriends;
|
||
|
ISteamUtils *m_pSteamUtils;
|
||
|
ISteamMatchmaking *m_pSteamMatchmaking;
|
||
|
ISteamGameSearch *m_pSteamGameSearch;
|
||
|
ISteamUserStats *m_pSteamUserStats;
|
||
|
ISteamApps *m_pSteamApps;
|
||
|
ISteamMatchmakingServers *m_pSteamMatchmakingServers;
|
||
|
ISteamNetworking *m_pSteamNetworking;
|
||
|
ISteamRemoteStorage *m_pSteamRemoteStorage;
|
||
|
ISteamScreenshots *m_pSteamScreenshots;
|
||
|
ISteamHTTP *m_pSteamHTTP;
|
||
|
ISteamController *m_pController;
|
||
|
ISteamUGC *m_pSteamUGC;
|
||
|
ISteamAppList *m_pSteamAppList;
|
||
|
ISteamMusic *m_pSteamMusic;
|
||
|
ISteamMusicRemote *m_pSteamMusicRemote;
|
||
|
ISteamHTMLSurface *m_pSteamHTMLSurface;
|
||
|
ISteamInventory *m_pSteamInventory;
|
||
|
ISteamVideo *m_pSteamVideo;
|
||
|
ISteamTV *m_pSteamTV;
|
||
|
ISteamParentalSettings *m_pSteamParentalSettings;
|
||
|
ISteamInput *m_pSteamInput;
|
||
|
};
|
||
|
|
||
|
class CSteamGameServerAPIContext
|
||
|
{
|
||
|
public:
|
||
|
CSteamGameServerAPIContext() { Clear(); }
|
||
|
inline void Clear() { memset( this, 0, sizeof(*this) ); }
|
||
|
inline bool Init(); // NOTE: This is defined in steam_gameserver.h, to avoid this file having to include everything
|
||
|
|
||
|
ISteamClient *SteamClient() const { return m_pSteamClient; }
|
||
|
ISteamGameServer *SteamGameServer() const { return m_pSteamGameServer; }
|
||
|
ISteamUtils *SteamGameServerUtils() const { return m_pSteamGameServerUtils; }
|
||
|
ISteamNetworking *SteamGameServerNetworking() const { return m_pSteamGameServerNetworking; }
|
||
|
ISteamGameServerStats *SteamGameServerStats() const { return m_pSteamGameServerStats; }
|
||
|
ISteamHTTP *SteamHTTP() const { return m_pSteamHTTP; }
|
||
|
ISteamInventory *SteamInventory() const { return m_pSteamInventory; }
|
||
|
ISteamUGC *SteamUGC() const { return m_pSteamUGC; }
|
||
|
ISteamApps *SteamApps() const { return m_pSteamApps; }
|
||
|
|
||
|
private:
|
||
|
ISteamClient *m_pSteamClient;
|
||
|
ISteamGameServer *m_pSteamGameServer;
|
||
|
ISteamUtils *m_pSteamGameServerUtils;
|
||
|
ISteamNetworking *m_pSteamGameServerNetworking;
|
||
|
ISteamGameServerStats *m_pSteamGameServerStats;
|
||
|
ISteamHTTP *m_pSteamHTTP;
|
||
|
ISteamInventory *m_pSteamInventory;
|
||
|
ISteamUGC *m_pSteamUGC;
|
||
|
ISteamApps *m_pSteamApps;
|
||
|
};
|
||
|
|
||
|
|