From a6f15329d0d54103a9190cc409471e1cc0f48d96 Mon Sep 17 00:00:00 2001 From: kelteseth Date: Wed, 17 Oct 2018 20:39:39 +0200 Subject: [PATCH] Add workshop subproject --- ScreenPlay.pro | 4 +- .../ThirdParty/steam/isteamapplist.h | 63 + .../ThirdParty/steam/isteamapps.h | 176 + .../ThirdParty/steam/isteamappticket.h | 28 + .../ThirdParty/steam/isteamclient.h | 526 + .../ThirdParty/steam/isteamcontroller.h | 461 + .../ThirdParty/steam/isteamfriends.h | 639 + .../ThirdParty/steam/isteamgamecoordinator.h | 75 + .../ThirdParty/steam/isteamgameserver.h | 387 + .../ThirdParty/steam/isteamgameserverstats.h | 101 + .../ThirdParty/steam/isteamhtmlsurface.h | 466 + .../ThirdParty/steam/isteamhttp.h | 210 + .../ThirdParty/steam/isteaminventory.h | 429 + .../steam/isteammasterserverupdater.h | 1 + .../ThirdParty/steam/isteammatchmaking.h | 751 + .../ThirdParty/steam/isteammusic.h | 67 + .../ThirdParty/steam/isteammusicremote.h | 129 + .../ThirdParty/steam/isteamnetworking.h | 306 + .../ThirdParty/steam/isteamparentalsettings.h | 57 + .../steam/isteamps3overlayrenderer.h | 91 + .../ThirdParty/steam/isteamremotestorage.h | 681 + .../ThirdParty/steam/isteamscreenshots.h | 116 + .../ThirdParty/steam/isteamugc.h | 545 + .../ThirdParty/steam/isteamunifiedmessages.h | 63 + .../ThirdParty/steam/isteamuser.h | 369 + .../ThirdParty/steam/isteamuserstats.h | 476 + .../ThirdParty/steam/isteamutils.h | 264 + .../ThirdParty/steam/isteamvideo.h | 71 + .../lib/osx32/libsdkencryptedappticket.dylib | Bin 0 -> 2127952 bytes .../steam/lib/win32/sdkencryptedappticket.dll | 3 + .../steam/lib/win32/sdkencryptedappticket.lib | Bin 0 -> 4542 bytes .../lib/win64/sdkencryptedappticket64.dll | 3 + .../lib/win64/sdkencryptedappticket64.lib | Bin 0 -> 4554 bytes .../ThirdParty/steam/matchmakingtypes.h | 251 + .../osx32/libsteam_api.dylib | Bin 0 -> 609216 bytes .../steam/redistributable_bin/steam_api.dll | 3 + .../steam/redistributable_bin/steam_api.lib | Bin 0 -> 297550 bytes .../redistributable_bin/win64/steam_api64.dll | 3 + .../redistributable_bin/win64/steam_api64.lib | Bin 0 -> 294986 bytes .../ThirdParty/steam/steam_api.h | 394 + .../ThirdParty/steam/steam_api.json | 8100 +++++++++++ .../ThirdParty/steam/steam_api_flat.h | 844 ++ .../ThirdParty/steam/steam_api_internal.h | 328 + .../ThirdParty/steam/steam_api_interop.cs | 11339 ++++++++++++++++ .../ThirdParty/steam/steam_gameserver.h | 243 + .../ThirdParty/steam/steamclientpublic.h | 1270 ++ .../steam/steamencryptedappticket.h | 32 + .../ThirdParty/steam/steamhttpenums.h | 98 + .../ThirdParty/steam/steamps3params.h | 112 + .../ThirdParty/steam/steamtypes.h | 184 + .../ThirdParty/steam/steamuniverse.h | 27 + ScreenPlayWorkshop/qmldir | 2 + ScreenPlayWorkshop/screenplayworkshop.pro | 50 + .../screenplayworkshop_plugin.cpp | 11 + .../screenplayworkshop_plugin.h | 12 + ScreenPlayWorkshop/workshop.cpp | 15 + ScreenPlayWorkshop/workshop.h | 16 + 57 files changed, 30891 insertions(+), 1 deletion(-) create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/isteamapplist.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/isteamapps.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/isteamappticket.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/isteamclient.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/isteamcontroller.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/isteamfriends.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/isteamgamecoordinator.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/isteamgameserver.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/isteamgameserverstats.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/isteamhtmlsurface.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/isteamhttp.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/isteaminventory.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/isteammasterserverupdater.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/isteammatchmaking.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/isteammusic.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/isteammusicremote.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/isteamnetworking.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/isteamparentalsettings.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/isteamps3overlayrenderer.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/isteamremotestorage.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/isteamscreenshots.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/isteamugc.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/isteamunifiedmessages.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/isteamuser.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/isteamuserstats.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/isteamutils.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/isteamvideo.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/lib/osx32/libsdkencryptedappticket.dylib create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/lib/win32/sdkencryptedappticket.dll create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/lib/win32/sdkencryptedappticket.lib create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/lib/win64/sdkencryptedappticket64.dll create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/lib/win64/sdkencryptedappticket64.lib create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/matchmakingtypes.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/redistributable_bin/osx32/libsteam_api.dylib create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/redistributable_bin/steam_api.dll create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/redistributable_bin/steam_api.lib create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/redistributable_bin/win64/steam_api64.dll create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/redistributable_bin/win64/steam_api64.lib create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/steam_api.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/steam_api.json create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/steam_api_flat.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/steam_api_internal.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/steam_api_interop.cs create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/steam_gameserver.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/steamclientpublic.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/steamencryptedappticket.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/steamhttpenums.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/steamps3params.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/steamtypes.h create mode 100644 ScreenPlayWorkshop/ThirdParty/steam/steamuniverse.h create mode 100644 ScreenPlayWorkshop/qmldir create mode 100644 ScreenPlayWorkshop/screenplayworkshop.pro create mode 100644 ScreenPlayWorkshop/screenplayworkshop_plugin.cpp create mode 100644 ScreenPlayWorkshop/screenplayworkshop_plugin.h create mode 100644 ScreenPlayWorkshop/workshop.cpp create mode 100644 ScreenPlayWorkshop/workshop.h diff --git a/ScreenPlay.pro b/ScreenPlay.pro index 2f704f03..b2e07a5a 100644 --- a/ScreenPlay.pro +++ b/ScreenPlay.pro @@ -6,8 +6,10 @@ SUBDIRS = \ ScreenPlayWindow/ScreenPlayWindow.pro \ ScreenPlay/ThirdParty/qt-google-analytics/qt-google-analytics.pro \ ScreenPlay/ThirdParty/stomt-qt-sdk/sdk/stomt-qt-sdk.pro \ - ScreenPlayWidget/ScreenPlayWidget.pro + ScreenPlayWidget/ScreenPlayWidget.pro \ + ScreenPlayWorkshop/ScreenPlayWorkshop.pro ScreenPlayWindow.depends = ScreenPlaySDK ScreenPlayWidget.depends = ScreenPlaySDK ScreenPlay.depends = qt-google-analytics +ScreenPlay.depends = ScreenPlayWorkshop diff --git a/ScreenPlayWorkshop/ThirdParty/steam/isteamapplist.h b/ScreenPlayWorkshop/ThirdParty/steam/isteamapplist.h new file mode 100644 index 00000000..d6789095 --- /dev/null +++ b/ScreenPlayWorkshop/ThirdParty/steam/isteamapplist.h @@ -0,0 +1,63 @@ +//====== Copyright © 1996-2008, Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to app data in Steam +// +//============================================================================= + +#ifndef ISTEAMAPPLIST_H +#define ISTEAMAPPLIST_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isteamclient.h" +#include "steamtypes.h" + +//----------------------------------------------------------------------------- +// Purpose: This is a restricted interface that can only be used by previously approved apps, +// contact your Steam Account Manager if you believe you need access to this API. +// This interface lets you detect installed apps for the local Steam client, useful for debugging tools +// to offer lists of apps to debug via Steam. +//----------------------------------------------------------------------------- +class ISteamAppList +{ +public: + virtual uint32 GetNumInstalledApps() = 0; + virtual uint32 GetInstalledApps( AppId_t *pvecAppID, uint32 unMaxAppIDs ) = 0; + + virtual int GetAppName( AppId_t nAppID, OUT_STRING() char *pchName, int cchNameMax ) = 0; // returns -1 if no name was found + virtual int GetAppInstallDir( AppId_t nAppID, char *pchDirectory, int cchNameMax ) = 0; // returns -1 if no dir was found + + virtual int GetAppBuildId( AppId_t nAppID ) = 0; // return the buildid of this app, may change at any time based on backend updates to the game +}; + +#define STEAMAPPLIST_INTERFACE_VERSION "STEAMAPPLIST_INTERFACE_VERSION001" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + + +//--------------------------------------------------------------------------------- +// Purpose: Sent when a new app is installed +//--------------------------------------------------------------------------------- +DEFINE_CALLBACK( SteamAppInstalled_t, k_iSteamAppListCallbacks + 1 ); + CALLBACK_MEMBER( 0, AppId_t, m_nAppID ) // ID of the app that installs +END_DEFINE_CALLBACK_1() + + +//--------------------------------------------------------------------------------- +// Purpose: Sent when an app is uninstalled +//--------------------------------------------------------------------------------- +DEFINE_CALLBACK( SteamAppUninstalled_t, k_iSteamAppListCallbacks + 2 ); + CALLBACK_MEMBER( 0, AppId_t, m_nAppID ) // ID of the app that installs +END_DEFINE_CALLBACK_1() + + +#pragma pack( pop ) +#endif // ISTEAMAPPLIST_H diff --git a/ScreenPlayWorkshop/ThirdParty/steam/isteamapps.h b/ScreenPlayWorkshop/ThirdParty/steam/isteamapps.h new file mode 100644 index 00000000..9a97b4a3 --- /dev/null +++ b/ScreenPlayWorkshop/ThirdParty/steam/isteamapps.h @@ -0,0 +1,176 @@ +//====== Copyright © 1996-2008, Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to app data in Steam +// +//============================================================================= + +#ifndef ISTEAMAPPS_H +#define ISTEAMAPPS_H +#ifdef _WIN32 +#pragma once +#endif + +const int k_cubAppProofOfPurchaseKeyMax = 240; // max supported length of a legacy cd key + + +//----------------------------------------------------------------------------- +// Purpose: interface to app data +//----------------------------------------------------------------------------- +class ISteamApps +{ +public: + virtual bool BIsSubscribed() = 0; + virtual bool BIsLowViolence() = 0; + virtual bool BIsCybercafe() = 0; + virtual bool BIsVACBanned() = 0; + virtual const char *GetCurrentGameLanguage() = 0; + virtual const char *GetAvailableGameLanguages() = 0; + + // only use this member if you need to check ownership of another game related to yours, a demo for example + virtual bool BIsSubscribedApp( AppId_t appID ) = 0; + + // Takes AppID of DLC and checks if the user owns the DLC & if the DLC is installed + virtual bool BIsDlcInstalled( AppId_t appID ) = 0; + + // returns the Unix time of the purchase of the app + virtual uint32 GetEarliestPurchaseUnixTime( AppId_t nAppID ) = 0; + + // Checks if the user is subscribed to the current app through a free weekend + // This function will return false for users who have a retail or other type of license + // Before using, please ask your Valve technical contact how to package and secure your free weekened + virtual bool BIsSubscribedFromFreeWeekend() = 0; + + // Returns the number of DLC pieces for the running app + virtual int GetDLCCount() = 0; + + // Returns metadata for DLC by index, of range [0, GetDLCCount()] + virtual bool BGetDLCDataByIndex( int iDLC, AppId_t *pAppID, bool *pbAvailable, char *pchName, int cchNameBufferSize ) = 0; + + // Install/Uninstall control for optional DLC + virtual void InstallDLC( AppId_t nAppID ) = 0; + virtual void UninstallDLC( AppId_t nAppID ) = 0; + + // Request legacy cd-key for yourself or owned DLC. If you are interested in this + // data then make sure you provide us with a list of valid keys to be distributed + // to users when they purchase the game, before the game ships. + // You'll receive an AppProofOfPurchaseKeyResponse_t callback when + // the key is available (which may be immediately). + virtual void RequestAppProofOfPurchaseKey( AppId_t nAppID ) = 0; + + virtual bool GetCurrentBetaName( char *pchName, int cchNameBufferSize ) = 0; // returns current beta branch name, 'public' is the default branch + virtual bool MarkContentCorrupt( bool bMissingFilesOnly ) = 0; // signal Steam that game files seems corrupt or missing + virtual uint32 GetInstalledDepots( AppId_t appID, DepotId_t *pvecDepots, uint32 cMaxDepots ) = 0; // return installed depots in mount order + + // returns current app install folder for AppID, returns folder name length + virtual uint32 GetAppInstallDir( AppId_t appID, char *pchFolder, uint32 cchFolderBufferSize ) = 0; + virtual bool BIsAppInstalled( AppId_t appID ) = 0; // returns true if that app is installed (not necessarily owned) + + virtual CSteamID GetAppOwner() = 0; // returns the SteamID of the original owner. If different from current user, it's borrowed + + // Returns the associated launch param if the game is run via steam://run///?param1=value1;param2=value2;param3=value3 etc. + // Parameter names starting with the character '@' are reserved for internal use and will always return and empty string. + // Parameter names starting with an underscore '_' are reserved for steam features -- they can be queried by the game, + // but it is advised that you not param names beginning with an underscore for your own features. + virtual const char *GetLaunchQueryParam( const char *pchKey ) = 0; + + // get download progress for optional DLC + virtual bool GetDlcDownloadProgress( AppId_t nAppID, uint64 *punBytesDownloaded, uint64 *punBytesTotal ) = 0; + + // return the buildid of this app, may change at any time based on backend updates to the game + virtual int GetAppBuildId() = 0; + + // Request all proof of purchase keys for the calling appid and asociated DLC. + // A series of AppProofOfPurchaseKeyResponse_t callbacks will be sent with + // appropriate appid values, ending with a final callback where the m_nAppId + // member is k_uAppIdInvalid (zero). + virtual void RequestAllProofOfPurchaseKeys() = 0; + + CALL_RESULT( FileDetailsResult_t ) + virtual SteamAPICall_t GetFileDetails( const char* pszFileName ) = 0; +}; + +#define STEAMAPPS_INTERFACE_VERSION "STEAMAPPS_INTERFACE_VERSION008" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif +//----------------------------------------------------------------------------- +// Purpose: posted after the user gains ownership of DLC & that DLC is installed +//----------------------------------------------------------------------------- +struct DlcInstalled_t +{ + enum { k_iCallback = k_iSteamAppsCallbacks + 5 }; + AppId_t m_nAppID; // AppID of the DLC +}; + + +//----------------------------------------------------------------------------- +// Purpose: possible results when registering an activation code +//----------------------------------------------------------------------------- +enum ERegisterActivationCodeResult +{ + k_ERegisterActivationCodeResultOK = 0, + k_ERegisterActivationCodeResultFail = 1, + k_ERegisterActivationCodeResultAlreadyRegistered = 2, + k_ERegisterActivationCodeResultTimeout = 3, + k_ERegisterActivationCodeAlreadyOwned = 4, +}; + + +//----------------------------------------------------------------------------- +// Purpose: response to RegisterActivationCode() +//----------------------------------------------------------------------------- +struct RegisterActivationCodeResponse_t +{ + enum { k_iCallback = k_iSteamAppsCallbacks + 8 }; + ERegisterActivationCodeResult m_eResult; + uint32 m_unPackageRegistered; // package that was registered. Only set on success +}; + + +//--------------------------------------------------------------------------------- +// Purpose: posted after the user gains executes a steam url with query parameters +// such as steam://run///?param1=value1;param2=value2;param3=value3; etc +// while the game is already running. The new params can be queried +// with GetLaunchQueryParam. +//--------------------------------------------------------------------------------- +struct NewLaunchQueryParameters_t +{ + enum { k_iCallback = k_iSteamAppsCallbacks + 14 }; +}; + + +//----------------------------------------------------------------------------- +// Purpose: response to RequestAppProofOfPurchaseKey/RequestAllProofOfPurchaseKeys +// for supporting third-party CD keys, or other proof-of-purchase systems. +//----------------------------------------------------------------------------- +struct AppProofOfPurchaseKeyResponse_t +{ + enum { k_iCallback = k_iSteamAppsCallbacks + 21 }; + EResult m_eResult; + uint32 m_nAppID; + uint32 m_cchKeyLength; + char m_rgchKey[k_cubAppProofOfPurchaseKeyMax]; +}; + + +//----------------------------------------------------------------------------- +// Purpose: response to GetFileDetails +//----------------------------------------------------------------------------- +struct FileDetailsResult_t +{ + enum { k_iCallback = k_iSteamAppsCallbacks + 23 }; + EResult m_eResult; + uint64 m_ulFileSize; // original file size in bytes + uint8 m_FileSHA[20]; // original file SHA1 hash + uint32 m_unFlags; // +}; + + +#pragma pack( pop ) +#endif // ISTEAMAPPS_H diff --git a/ScreenPlayWorkshop/ThirdParty/steam/isteamappticket.h b/ScreenPlayWorkshop/ThirdParty/steam/isteamappticket.h new file mode 100644 index 00000000..21fb9e13 --- /dev/null +++ b/ScreenPlayWorkshop/ThirdParty/steam/isteamappticket.h @@ -0,0 +1,28 @@ +//====== Copyright 1996-2008, Valve Corporation, All rights reserved. ======= +// +// Purpose: a private, but well versioned, interface to get at critical bits +// of a steam3 appticket - consumed by the simple drm wrapper to let it +// ask about ownership with greater confidence. +// +//============================================================================= + +#ifndef ISTEAMAPPTICKET_H +#define ISTEAMAPPTICKET_H +#pragma once + +//----------------------------------------------------------------------------- +// Purpose: hand out a reasonable "future proof" view of an app ownership ticket +// the raw (signed) buffer, and indices into that buffer where the appid and +// steamid are located. the sizes of the appid and steamid are implicit in +// (each version of) the interface - currently uin32 appid and uint64 steamid +//----------------------------------------------------------------------------- +class ISteamAppTicket +{ +public: + virtual uint32 GetAppOwnershipTicketData( uint32 nAppID, void *pvBuffer, uint32 cbBufferLength, uint32 *piAppId, uint32 *piSteamId, uint32 *piSignature, uint32 *pcbSignature ) = 0; +}; + +#define STEAMAPPTICKET_INTERFACE_VERSION "STEAMAPPTICKET_INTERFACE_VERSION001" + + +#endif // ISTEAMAPPTICKET_H diff --git a/ScreenPlayWorkshop/ThirdParty/steam/isteamclient.h b/ScreenPlayWorkshop/ThirdParty/steam/isteamclient.h new file mode 100644 index 00000000..af8828d0 --- /dev/null +++ b/ScreenPlayWorkshop/ThirdParty/steam/isteamclient.h @@ -0,0 +1,526 @@ +//====== Copyright � 1996-2008, Valve Corporation, All rights reserved. ======= +// +// Purpose: Main interface for loading and accessing Steamworks API's from the +// Steam client. +// For most uses, this code is wrapped inside of SteamAPI_Init() +//============================================================================= + +#ifndef ISTEAMCLIENT_H +#define ISTEAMCLIENT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "steamtypes.h" +#include "steamclientpublic.h" + +// Define compile time assert macros to let us validate the structure sizes. +#define VALVE_COMPILE_TIME_ASSERT( pred ) typedef char compile_time_assert_type[(pred) ? 1 : -1]; + +#ifndef REFERENCE +#define REFERENCE(arg) ((void)arg) +#endif + +#if ( defined(STEAM_API_EXPORTS) || defined(STEAM_API_NODLL) ) && !defined(API_GEN) +#define STEAM_PRIVATE_API( ... ) __VA_ARGS__ +#elif defined(STEAM_API_EXPORTS) && defined(API_GEN) +#define STEAM_PRIVATE_API( ... ) +#else +#define STEAM_PRIVATE_API( ... ) protected: __VA_ARGS__ public: +#endif + +#if defined(__linux__) || defined(__APPLE__) +// The 32-bit version of gcc has the alignment requirement for uint64 and double set to +// 4 meaning that even with #pragma pack(8) these types will only be four-byte aligned. +// The 64-bit version of gcc has the alignment requirement for these types set to +// 8 meaning that unless we use #pragma pack(4) our structures will get bigger. +// The 64-bit structure packing has to match the 32-bit structure packing for each platform. +#define VALVE_CALLBACK_PACK_SMALL +#else +#define VALVE_CALLBACK_PACK_LARGE +#endif + +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error ??? +#endif + +typedef struct ValvePackingSentinel_t +{ + uint32 m_u32; + uint64 m_u64; + uint16 m_u16; + double m_d; +} ValvePackingSentinel_t; + +#pragma pack( pop ) + + +#if defined(VALVE_CALLBACK_PACK_SMALL) +VALVE_COMPILE_TIME_ASSERT( sizeof(ValvePackingSentinel_t) == 24 ) +#elif defined(VALVE_CALLBACK_PACK_LARGE) +VALVE_COMPILE_TIME_ASSERT( sizeof(ValvePackingSentinel_t) == 32 ) +#else +#error ??? +#endif + + +// handle to a communication pipe to the Steam client +typedef int32 HSteamPipe; +// handle to single instance of a steam user +typedef int32 HSteamUser; +// function prototype +#if defined( POSIX ) +#define __cdecl +#endif +extern "C" typedef void (__cdecl *SteamAPIWarningMessageHook_t)(int, const char *); +extern "C" typedef uint32 ( *SteamAPI_CheckCallbackRegistered_t )( int iCallbackNum ); +#if defined( __SNC__ ) + #pragma diag_suppress=1700 // warning 1700: class "%s" has virtual functions but non-virtual destructor +#endif + +// interface predec +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; + +//----------------------------------------------------------------------------- +// Purpose: Interface to creating a new steam instance, or to +// connect to an existing steam instance, whether it's in a +// different process or is local. +// +// For most scenarios this is all handled automatically via SteamAPI_Init(). +// You'll only need these APIs if you have a more complex versioning scheme, +// or if you want to implement a multiplexed gameserver where a single process +// is handling multiple games at once with independent gameserver SteamIDs. +//----------------------------------------------------------------------------- +class ISteamClient +{ +public: + // Creates a communication pipe to the Steam client. + // NOT THREADSAFE - ensure that no other threads are accessing Steamworks API when calling + virtual HSteamPipe CreateSteamPipe() = 0; + + // Releases a previously created communications pipe + // NOT THREADSAFE - ensure that no other threads are accessing Steamworks API when calling + virtual bool BReleaseSteamPipe( HSteamPipe hSteamPipe ) = 0; + + // connects to an existing global user, failing if none exists + // used by the game to coordinate with the steamUI + // NOT THREADSAFE - ensure that no other threads are accessing Steamworks API when calling + virtual HSteamUser ConnectToGlobalUser( HSteamPipe hSteamPipe ) = 0; + + // used by game servers, create a steam user that won't be shared with anyone else + // NOT THREADSAFE - ensure that no other threads are accessing Steamworks API when calling + virtual HSteamUser CreateLocalUser( HSteamPipe *phSteamPipe, EAccountType eAccountType ) = 0; + + // removes an allocated user + // NOT THREADSAFE - ensure that no other threads are accessing Steamworks API when calling + virtual void ReleaseUser( HSteamPipe hSteamPipe, HSteamUser hUser ) = 0; + + // retrieves the ISteamUser interface associated with the handle + virtual ISteamUser *GetISteamUser( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // retrieves the ISteamGameServer interface associated with the handle + virtual ISteamGameServer *GetISteamGameServer( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // set the local IP and Port to bind to + // this must be set before CreateLocalUser() + virtual void SetLocalIPBinding( uint32 unIP, uint16 usPort ) = 0; + + // returns the ISteamFriends interface + virtual ISteamFriends *GetISteamFriends( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // returns the ISteamUtils interface + virtual ISteamUtils *GetISteamUtils( HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // returns the ISteamMatchmaking interface + virtual ISteamMatchmaking *GetISteamMatchmaking( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // returns the ISteamMatchmakingServers interface + virtual ISteamMatchmakingServers *GetISteamMatchmakingServers( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // returns the a generic interface + virtual void *GetISteamGenericInterface( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // returns the ISteamUserStats interface + virtual ISteamUserStats *GetISteamUserStats( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // returns the ISteamGameServerStats interface + virtual ISteamGameServerStats *GetISteamGameServerStats( HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // returns apps interface + virtual ISteamApps *GetISteamApps( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // networking + virtual ISteamNetworking *GetISteamNetworking( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // remote storage + virtual ISteamRemoteStorage *GetISteamRemoteStorage( HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // user screenshots + virtual ISteamScreenshots *GetISteamScreenshots( HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // Deprecated. Applications should use SteamAPI_RunCallbacks() or SteamGameServer_RunCallbacks() instead. + STEAM_PRIVATE_API( virtual void RunFrame() = 0; ) + + // returns the number of IPC calls made since the last time this function was called + // Used for perf debugging so you can understand how many IPC calls your game makes per frame + // Every IPC call is at minimum a thread context switch if not a process one so you want to rate + // control how often you do them. + virtual uint32 GetIPCCallCount() = 0; + + // API warning handling + // 'int' is the severity; 0 for msg, 1 for warning + // 'const char *' is the text of the message + // callbacks will occur directly after the API function is called that generated the warning or message. + virtual void SetWarningMessageHook( SteamAPIWarningMessageHook_t pFunction ) = 0; + + // Trigger global shutdown for the DLL + virtual bool BShutdownIfAllPipesClosed() = 0; + + // Expose HTTP interface + virtual ISteamHTTP *GetISteamHTTP( HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // Deprecated - the ISteamUnifiedMessages interface is no longer intended for public consumption. + STEAM_PRIVATE_API( virtual void *DEPRECATED_GetISteamUnifiedMessages( HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0 ; ) + + // Exposes the ISteamController interface + virtual ISteamController *GetISteamController( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // Exposes the ISteamUGC interface + virtual ISteamUGC *GetISteamUGC( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // returns app list interface, only available on specially registered apps + virtual ISteamAppList *GetISteamAppList( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // Music Player + virtual ISteamMusic *GetISteamMusic( HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // Music Player Remote + virtual ISteamMusicRemote *GetISteamMusicRemote(HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char *pchVersion) = 0; + + // html page display + virtual ISteamHTMLSurface *GetISteamHTMLSurface(HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char *pchVersion) = 0; + + // Helper functions for internal Steam usage + STEAM_PRIVATE_API( virtual void DEPRECATED_Set_SteamAPI_CPostAPIResultInProcess( void (*)() ) = 0; ) + STEAM_PRIVATE_API( virtual void DEPRECATED_Remove_SteamAPI_CPostAPIResultInProcess( void (*)() ) = 0; ) + STEAM_PRIVATE_API( virtual void Set_SteamAPI_CCheckCallbackRegisteredInProcess( SteamAPI_CheckCallbackRegistered_t func ) = 0; ) + + // inventory + virtual ISteamInventory *GetISteamInventory( HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // Video + virtual ISteamVideo *GetISteamVideo( HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // Parental controls + virtual ISteamParentalSettings *GetISteamParentalSettings( HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; +}; + + +#define STEAMCLIENT_INTERFACE_VERSION "SteamClient017" + +//----------------------------------------------------------------------------- +// 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_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 }; + +//----------------------------------------------------------------------------- +// The CALLBACK macros are for client side callback logging enabled with +// log_callback +// Do not change any of these. +//----------------------------------------------------------------------------- + +#ifdef STEAM_CALLBACK_INSPECTION_ENABLED + +#define DEFINE_CALLBACK( callbackname, callbackid ) \ +struct callbackname { \ + typedef callbackname SteamCallback_t; \ + enum { k_iCallback = callbackid }; \ + static callbackname *GetNullPointer() { return 0; } \ + static const char *GetCallbackName() { return #callbackname; } \ + static uint32 GetCallbackID() { return callbackname::k_iCallback; } + +#define CALLBACK_MEMBER( varidx, vartype, varname ) \ + public: vartype varname ; \ + static void GetMemberVar_##varidx( unsigned int &varOffset, unsigned int &varSize, uint32 &varCount, const char **pszName, const char **pszType ) { \ + varOffset = (unsigned int)(size_t)&GetNullPointer()->varname; \ + varSize = sizeof( vartype ); \ + varCount = 1; \ + *pszName = #varname; *pszType = #vartype; } + +#define CALLBACK_ARRAY( varidx, vartype, varname, varcount ) \ + public: vartype varname [ varcount ]; \ + static void GetMemberVar_##varidx( unsigned int &varOffset, unsigned int &varSize, uint32 &varCount, const char **pszName, const char **pszType ) { \ + varOffset = (unsigned int)(size_t)&GetNullPointer()->varname[0]; \ + varSize = sizeof( vartype ); \ + varCount = varcount; \ + *pszName = #varname; *pszType = #vartype; } + + +#define END_CALLBACK_INTERNAL_BEGIN( numvars ) \ + static uint32 GetNumMemberVariables() { return numvars; } \ + static bool GetMemberVariable( uint32 index, uint32 &varOffset, uint32 &varSize, uint32 &varCount, const char **pszName, const char **pszType ) { \ + switch ( index ) { default : return false; + + +#define END_CALLBACK_INTERNAL_SWITCH( varidx ) case varidx : GetMemberVar_##varidx( varOffset, varSize, varCount, pszName, pszType ); return true; + +#define END_CALLBACK_INTERNAL_END() }; } }; + +#define END_DEFINE_CALLBACK_0() \ + static uint32 GetNumMemberVariables() { return 0; } \ + static bool GetMemberVariable( uint32 index, uint32 &varOffset, uint32 &varSize, uint32 &varCount, const char **pszName, const char **pszType ) { REFERENCE( pszType ); REFERENCE( pszName ); REFERENCE( varCount ); REFERENCE( varSize ); REFERENCE( varOffset ); REFERENCE( index ); return false; } \ + }; + +#else + +#define DEFINE_CALLBACK( callbackname, callbackid ) struct callbackname { typedef callbackname SteamCallback_t; enum { k_iCallback = callbackid }; +#define CALLBACK_MEMBER( varidx, vartype, varname ) public: vartype varname ; +#define CALLBACK_ARRAY( varidx, vartype, varname, varcount ) public: vartype varname [ varcount ]; +#define END_CALLBACK_INTERNAL_BEGIN( numvars ) +#define END_CALLBACK_INTERNAL_SWITCH( varidx ) +#define END_CALLBACK_INTERNAL_END() }; +#define END_DEFINE_CALLBACK_0() }; + +#endif + +#define END_DEFINE_CALLBACK_1() \ + END_CALLBACK_INTERNAL_BEGIN( 1 ) \ + END_CALLBACK_INTERNAL_SWITCH( 0 ) \ + END_CALLBACK_INTERNAL_END() + +#define END_DEFINE_CALLBACK_2() \ + END_CALLBACK_INTERNAL_BEGIN( 2 ) \ + END_CALLBACK_INTERNAL_SWITCH( 0 ) \ + END_CALLBACK_INTERNAL_SWITCH( 1 ) \ + END_CALLBACK_INTERNAL_END() + +#define END_DEFINE_CALLBACK_3() \ + END_CALLBACK_INTERNAL_BEGIN( 3 ) \ + END_CALLBACK_INTERNAL_SWITCH( 0 ) \ + END_CALLBACK_INTERNAL_SWITCH( 1 ) \ + END_CALLBACK_INTERNAL_SWITCH( 2 ) \ + END_CALLBACK_INTERNAL_END() + +#define END_DEFINE_CALLBACK_4() \ + END_CALLBACK_INTERNAL_BEGIN( 4 ) \ + END_CALLBACK_INTERNAL_SWITCH( 0 ) \ + END_CALLBACK_INTERNAL_SWITCH( 1 ) \ + END_CALLBACK_INTERNAL_SWITCH( 2 ) \ + END_CALLBACK_INTERNAL_SWITCH( 3 ) \ + END_CALLBACK_INTERNAL_END() + +#define END_DEFINE_CALLBACK_5() \ + END_CALLBACK_INTERNAL_BEGIN( 4 ) \ + END_CALLBACK_INTERNAL_SWITCH( 0 ) \ + END_CALLBACK_INTERNAL_SWITCH( 1 ) \ + END_CALLBACK_INTERNAL_SWITCH( 2 ) \ + END_CALLBACK_INTERNAL_SWITCH( 3 ) \ + END_CALLBACK_INTERNAL_SWITCH( 4 ) \ + END_CALLBACK_INTERNAL_END() + + +#define END_DEFINE_CALLBACK_6() \ + END_CALLBACK_INTERNAL_BEGIN( 6 ) \ + END_CALLBACK_INTERNAL_SWITCH( 0 ) \ + END_CALLBACK_INTERNAL_SWITCH( 1 ) \ + END_CALLBACK_INTERNAL_SWITCH( 2 ) \ + END_CALLBACK_INTERNAL_SWITCH( 3 ) \ + END_CALLBACK_INTERNAL_SWITCH( 4 ) \ + END_CALLBACK_INTERNAL_SWITCH( 5 ) \ + END_CALLBACK_INTERNAL_END() + +#define END_DEFINE_CALLBACK_7() \ + END_CALLBACK_INTERNAL_BEGIN( 7 ) \ + END_CALLBACK_INTERNAL_SWITCH( 0 ) \ + END_CALLBACK_INTERNAL_SWITCH( 1 ) \ + END_CALLBACK_INTERNAL_SWITCH( 2 ) \ + END_CALLBACK_INTERNAL_SWITCH( 3 ) \ + END_CALLBACK_INTERNAL_SWITCH( 4 ) \ + END_CALLBACK_INTERNAL_SWITCH( 5 ) \ + END_CALLBACK_INTERNAL_SWITCH( 6 ) \ + END_CALLBACK_INTERNAL_END() + +#define END_DEFINE_CALLBACK_8() \ + END_CALLBACK_INTERNAL_BEGIN( 8 ) \ + END_CALLBACK_INTERNAL_SWITCH( 0 ) \ + END_CALLBACK_INTERNAL_SWITCH( 1 ) \ + END_CALLBACK_INTERNAL_SWITCH( 2 ) \ + END_CALLBACK_INTERNAL_SWITCH( 3 ) \ + END_CALLBACK_INTERNAL_SWITCH( 4 ) \ + END_CALLBACK_INTERNAL_SWITCH( 5 ) \ + END_CALLBACK_INTERNAL_SWITCH( 6 ) \ + END_CALLBACK_INTERNAL_SWITCH( 7 ) \ + END_CALLBACK_INTERNAL_END() + +#define END_DEFINE_CALLBACK_9() \ + END_CALLBACK_INTERNAL_BEGIN( 9 ) \ + END_CALLBACK_INTERNAL_SWITCH( 0 ) \ + END_CALLBACK_INTERNAL_SWITCH( 1 ) \ + END_CALLBACK_INTERNAL_SWITCH( 2 ) \ + END_CALLBACK_INTERNAL_SWITCH( 3 ) \ + END_CALLBACK_INTERNAL_SWITCH( 4 ) \ + END_CALLBACK_INTERNAL_SWITCH( 5 ) \ + END_CALLBACK_INTERNAL_SWITCH( 6 ) \ + END_CALLBACK_INTERNAL_SWITCH( 7 ) \ + END_CALLBACK_INTERNAL_SWITCH( 8 ) \ + END_CALLBACK_INTERNAL_END() + +#define END_DEFINE_CALLBACK_10() \ + END_CALLBACK_INTERNAL_BEGIN( 10 ) \ + END_CALLBACK_INTERNAL_SWITCH( 0 ) \ + END_CALLBACK_INTERNAL_SWITCH( 1 ) \ + END_CALLBACK_INTERNAL_SWITCH( 2 ) \ + END_CALLBACK_INTERNAL_SWITCH( 3 ) \ + END_CALLBACK_INTERNAL_SWITCH( 4 ) \ + END_CALLBACK_INTERNAL_SWITCH( 5 ) \ + END_CALLBACK_INTERNAL_SWITCH( 6 ) \ + END_CALLBACK_INTERNAL_SWITCH( 7 ) \ + END_CALLBACK_INTERNAL_SWITCH( 8 ) \ + END_CALLBACK_INTERNAL_SWITCH( 9 ) \ + END_CALLBACK_INTERNAL_END() + +#define END_DEFINE_CALLBACK_11() \ + END_CALLBACK_INTERNAL_BEGIN( 11 ) \ + END_CALLBACK_INTERNAL_SWITCH( 0 ) \ + END_CALLBACK_INTERNAL_SWITCH( 1 ) \ + END_CALLBACK_INTERNAL_SWITCH( 2 ) \ + END_CALLBACK_INTERNAL_SWITCH( 3 ) \ + END_CALLBACK_INTERNAL_SWITCH( 4 ) \ + END_CALLBACK_INTERNAL_SWITCH( 5 ) \ + END_CALLBACK_INTERNAL_SWITCH( 6 ) \ + END_CALLBACK_INTERNAL_SWITCH( 7 ) \ + END_CALLBACK_INTERNAL_SWITCH( 8 ) \ + END_CALLBACK_INTERNAL_SWITCH( 9 ) \ + END_CALLBACK_INTERNAL_SWITCH( 10 ) \ + END_CALLBACK_INTERNAL_END() + +#define END_DEFINE_CALLBACK_12() \ + END_CALLBACK_INTERNAL_BEGIN( 12 ) \ + END_CALLBACK_INTERNAL_SWITCH( 0 ) \ + END_CALLBACK_INTERNAL_SWITCH( 1 ) \ + END_CALLBACK_INTERNAL_SWITCH( 2 ) \ + END_CALLBACK_INTERNAL_SWITCH( 3 ) \ + END_CALLBACK_INTERNAL_SWITCH( 4 ) \ + END_CALLBACK_INTERNAL_SWITCH( 5 ) \ + END_CALLBACK_INTERNAL_SWITCH( 6 ) \ + END_CALLBACK_INTERNAL_SWITCH( 7 ) \ + END_CALLBACK_INTERNAL_SWITCH( 8 ) \ + END_CALLBACK_INTERNAL_SWITCH( 9 ) \ + END_CALLBACK_INTERNAL_SWITCH( 10 ) \ + END_CALLBACK_INTERNAL_SWITCH( 11 ) \ + END_CALLBACK_INTERNAL_END() + +#define END_DEFINE_CALLBACK_13() \ + END_CALLBACK_INTERNAL_BEGIN( 13 ) \ + END_CALLBACK_INTERNAL_SWITCH( 0 ) \ + END_CALLBACK_INTERNAL_SWITCH( 1 ) \ + END_CALLBACK_INTERNAL_SWITCH( 2 ) \ + END_CALLBACK_INTERNAL_SWITCH( 3 ) \ + END_CALLBACK_INTERNAL_SWITCH( 4 ) \ + END_CALLBACK_INTERNAL_SWITCH( 5 ) \ + END_CALLBACK_INTERNAL_SWITCH( 6 ) \ + END_CALLBACK_INTERNAL_SWITCH( 7 ) \ + END_CALLBACK_INTERNAL_SWITCH( 8 ) \ + END_CALLBACK_INTERNAL_SWITCH( 9 ) \ + END_CALLBACK_INTERNAL_SWITCH( 10 ) \ + END_CALLBACK_INTERNAL_SWITCH( 11 ) \ + END_CALLBACK_INTERNAL_SWITCH( 12 ) \ + END_CALLBACK_INTERNAL_END() + +#define END_DEFINE_CALLBACK_14() \ + END_CALLBACK_INTERNAL_BEGIN( 14 ) \ + END_CALLBACK_INTERNAL_SWITCH( 0 ) \ + END_CALLBACK_INTERNAL_SWITCH( 1 ) \ + END_CALLBACK_INTERNAL_SWITCH( 2 ) \ + END_CALLBACK_INTERNAL_SWITCH( 3 ) \ + END_CALLBACK_INTERNAL_SWITCH( 4 ) \ + END_CALLBACK_INTERNAL_SWITCH( 5 ) \ + END_CALLBACK_INTERNAL_SWITCH( 6 ) \ + END_CALLBACK_INTERNAL_SWITCH( 7 ) \ + END_CALLBACK_INTERNAL_SWITCH( 8 ) \ + END_CALLBACK_INTERNAL_SWITCH( 9 ) \ + END_CALLBACK_INTERNAL_SWITCH( 10 ) \ + END_CALLBACK_INTERNAL_SWITCH( 11 ) \ + END_CALLBACK_INTERNAL_SWITCH( 12 ) \ + END_CALLBACK_INTERNAL_SWITCH( 13 ) \ + END_CALLBACK_INTERNAL_END() + +#endif // ISTEAMCLIENT_H diff --git a/ScreenPlayWorkshop/ThirdParty/steam/isteamcontroller.h b/ScreenPlayWorkshop/ThirdParty/steam/isteamcontroller.h new file mode 100644 index 00000000..6f31b750 --- /dev/null +++ b/ScreenPlayWorkshop/ThirdParty/steam/isteamcontroller.h @@ -0,0 +1,461 @@ +//====== Copyright 1996-2013, Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to valve controller +// +//============================================================================= + +#ifndef ISTEAMCONTROLLER_H +#define ISTEAMCONTROLLER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isteamclient.h" + +#define STEAM_CONTROLLER_MAX_COUNT 16 + +#define STEAM_CONTROLLER_MAX_ANALOG_ACTIONS 16 + +#define STEAM_CONTROLLER_MAX_DIGITAL_ACTIONS 128 + +#define STEAM_CONTROLLER_MAX_ORIGINS 8 + +// When sending an option to a specific controller handle, you can send to all controllers via this command +#define STEAM_CONTROLLER_HANDLE_ALL_CONTROLLERS UINT64_MAX + +#define STEAM_CONTROLLER_MIN_ANALOG_ACTION_DATA -1.0f +#define STEAM_CONTROLLER_MAX_ANALOG_ACTION_DATA 1.0f + +enum ESteamControllerPad +{ + k_ESteamControllerPad_Left, + k_ESteamControllerPad_Right +}; + +enum EControllerSource +{ + k_EControllerSource_None, + k_EControllerSource_LeftTrackpad, + k_EControllerSource_RightTrackpad, + k_EControllerSource_Joystick, + k_EControllerSource_ABXY, + k_EControllerSource_Switch, + k_EControllerSource_LeftTrigger, + k_EControllerSource_RightTrigger, + k_EControllerSource_Gyro, + k_EControllerSource_CenterTrackpad, // PS4 + k_EControllerSource_RightJoystick, // Traditional Controllers + k_EControllerSource_DPad, // Traditional Controllers + k_EControllerSource_Key, // Keyboards with scan codes + k_EControllerSource_Mouse, // Traditional mouse + k_EControllerSource_Count +}; + +enum EControllerSourceMode +{ + k_EControllerSourceMode_None, + k_EControllerSourceMode_Dpad, + k_EControllerSourceMode_Buttons, + k_EControllerSourceMode_FourButtons, + k_EControllerSourceMode_AbsoluteMouse, + k_EControllerSourceMode_RelativeMouse, + k_EControllerSourceMode_JoystickMove, + k_EControllerSourceMode_JoystickMouse, + k_EControllerSourceMode_JoystickCamera, + k_EControllerSourceMode_ScrollWheel, + k_EControllerSourceMode_Trigger, + k_EControllerSourceMode_TouchMenu, + k_EControllerSourceMode_MouseJoystick, + k_EControllerSourceMode_MouseRegion, + k_EControllerSourceMode_RadialMenu, + k_EControllerSourceMode_SingleButton, + k_EControllerSourceMode_Switches +}; + +enum EControllerActionOrigin +{ + // Steam Controller + k_EControllerActionOrigin_None, + k_EControllerActionOrigin_A, + k_EControllerActionOrigin_B, + k_EControllerActionOrigin_X, + k_EControllerActionOrigin_Y, + k_EControllerActionOrigin_LeftBumper, + k_EControllerActionOrigin_RightBumper, + k_EControllerActionOrigin_LeftGrip, + k_EControllerActionOrigin_RightGrip, + k_EControllerActionOrigin_Start, + k_EControllerActionOrigin_Back, + k_EControllerActionOrigin_LeftPad_Touch, + k_EControllerActionOrigin_LeftPad_Swipe, + k_EControllerActionOrigin_LeftPad_Click, + k_EControllerActionOrigin_LeftPad_DPadNorth, + k_EControllerActionOrigin_LeftPad_DPadSouth, + k_EControllerActionOrigin_LeftPad_DPadWest, + k_EControllerActionOrigin_LeftPad_DPadEast, + k_EControllerActionOrigin_RightPad_Touch, + k_EControllerActionOrigin_RightPad_Swipe, + k_EControllerActionOrigin_RightPad_Click, + k_EControllerActionOrigin_RightPad_DPadNorth, + k_EControllerActionOrigin_RightPad_DPadSouth, + k_EControllerActionOrigin_RightPad_DPadWest, + k_EControllerActionOrigin_RightPad_DPadEast, + k_EControllerActionOrigin_LeftTrigger_Pull, + k_EControllerActionOrigin_LeftTrigger_Click, + k_EControllerActionOrigin_RightTrigger_Pull, + k_EControllerActionOrigin_RightTrigger_Click, + k_EControllerActionOrigin_LeftStick_Move, + k_EControllerActionOrigin_LeftStick_Click, + k_EControllerActionOrigin_LeftStick_DPadNorth, + k_EControllerActionOrigin_LeftStick_DPadSouth, + k_EControllerActionOrigin_LeftStick_DPadWest, + k_EControllerActionOrigin_LeftStick_DPadEast, + k_EControllerActionOrigin_Gyro_Move, + k_EControllerActionOrigin_Gyro_Pitch, + k_EControllerActionOrigin_Gyro_Yaw, + k_EControllerActionOrigin_Gyro_Roll, + + // PS4 Dual Shock + k_EControllerActionOrigin_PS4_X, + k_EControllerActionOrigin_PS4_Circle, + k_EControllerActionOrigin_PS4_Triangle, + k_EControllerActionOrigin_PS4_Square, + k_EControllerActionOrigin_PS4_LeftBumper, + k_EControllerActionOrigin_PS4_RightBumper, + k_EControllerActionOrigin_PS4_Options, //Start + k_EControllerActionOrigin_PS4_Share, //Back + k_EControllerActionOrigin_PS4_LeftPad_Touch, + k_EControllerActionOrigin_PS4_LeftPad_Swipe, + k_EControllerActionOrigin_PS4_LeftPad_Click, + k_EControllerActionOrigin_PS4_LeftPad_DPadNorth, + k_EControllerActionOrigin_PS4_LeftPad_DPadSouth, + k_EControllerActionOrigin_PS4_LeftPad_DPadWest, + k_EControllerActionOrigin_PS4_LeftPad_DPadEast, + k_EControllerActionOrigin_PS4_RightPad_Touch, + k_EControllerActionOrigin_PS4_RightPad_Swipe, + k_EControllerActionOrigin_PS4_RightPad_Click, + k_EControllerActionOrigin_PS4_RightPad_DPadNorth, + k_EControllerActionOrigin_PS4_RightPad_DPadSouth, + k_EControllerActionOrigin_PS4_RightPad_DPadWest, + k_EControllerActionOrigin_PS4_RightPad_DPadEast, + k_EControllerActionOrigin_PS4_CenterPad_Touch, + k_EControllerActionOrigin_PS4_CenterPad_Swipe, + k_EControllerActionOrigin_PS4_CenterPad_Click, + k_EControllerActionOrigin_PS4_CenterPad_DPadNorth, + k_EControllerActionOrigin_PS4_CenterPad_DPadSouth, + k_EControllerActionOrigin_PS4_CenterPad_DPadWest, + k_EControllerActionOrigin_PS4_CenterPad_DPadEast, + k_EControllerActionOrigin_PS4_LeftTrigger_Pull, + k_EControllerActionOrigin_PS4_LeftTrigger_Click, + k_EControllerActionOrigin_PS4_RightTrigger_Pull, + k_EControllerActionOrigin_PS4_RightTrigger_Click, + k_EControllerActionOrigin_PS4_LeftStick_Move, + k_EControllerActionOrigin_PS4_LeftStick_Click, + k_EControllerActionOrigin_PS4_LeftStick_DPadNorth, + k_EControllerActionOrigin_PS4_LeftStick_DPadSouth, + k_EControllerActionOrigin_PS4_LeftStick_DPadWest, + k_EControllerActionOrigin_PS4_LeftStick_DPadEast, + k_EControllerActionOrigin_PS4_RightStick_Move, + k_EControllerActionOrigin_PS4_RightStick_Click, + k_EControllerActionOrigin_PS4_RightStick_DPadNorth, + k_EControllerActionOrigin_PS4_RightStick_DPadSouth, + k_EControllerActionOrigin_PS4_RightStick_DPadWest, + k_EControllerActionOrigin_PS4_RightStick_DPadEast, + k_EControllerActionOrigin_PS4_DPad_North, + k_EControllerActionOrigin_PS4_DPad_South, + k_EControllerActionOrigin_PS4_DPad_West, + k_EControllerActionOrigin_PS4_DPad_East, + k_EControllerActionOrigin_PS4_Gyro_Move, + k_EControllerActionOrigin_PS4_Gyro_Pitch, + k_EControllerActionOrigin_PS4_Gyro_Yaw, + k_EControllerActionOrigin_PS4_Gyro_Roll, + + // XBox One + k_EControllerActionOrigin_XBoxOne_A, + k_EControllerActionOrigin_XBoxOne_B, + k_EControllerActionOrigin_XBoxOne_X, + k_EControllerActionOrigin_XBoxOne_Y, + k_EControllerActionOrigin_XBoxOne_LeftBumper, + k_EControllerActionOrigin_XBoxOne_RightBumper, + k_EControllerActionOrigin_XBoxOne_Menu, //Start + k_EControllerActionOrigin_XBoxOne_View, //Back + k_EControllerActionOrigin_XBoxOne_LeftTrigger_Pull, + k_EControllerActionOrigin_XBoxOne_LeftTrigger_Click, + k_EControllerActionOrigin_XBoxOne_RightTrigger_Pull, + k_EControllerActionOrigin_XBoxOne_RightTrigger_Click, + k_EControllerActionOrigin_XBoxOne_LeftStick_Move, + k_EControllerActionOrigin_XBoxOne_LeftStick_Click, + k_EControllerActionOrigin_XBoxOne_LeftStick_DPadNorth, + k_EControllerActionOrigin_XBoxOne_LeftStick_DPadSouth, + k_EControllerActionOrigin_XBoxOne_LeftStick_DPadWest, + k_EControllerActionOrigin_XBoxOne_LeftStick_DPadEast, + k_EControllerActionOrigin_XBoxOne_RightStick_Move, + k_EControllerActionOrigin_XBoxOne_RightStick_Click, + k_EControllerActionOrigin_XBoxOne_RightStick_DPadNorth, + k_EControllerActionOrigin_XBoxOne_RightStick_DPadSouth, + k_EControllerActionOrigin_XBoxOne_RightStick_DPadWest, + k_EControllerActionOrigin_XBoxOne_RightStick_DPadEast, + k_EControllerActionOrigin_XBoxOne_DPad_North, + k_EControllerActionOrigin_XBoxOne_DPad_South, + k_EControllerActionOrigin_XBoxOne_DPad_West, + k_EControllerActionOrigin_XBoxOne_DPad_East, + + // XBox 360 + k_EControllerActionOrigin_XBox360_A, + k_EControllerActionOrigin_XBox360_B, + k_EControllerActionOrigin_XBox360_X, + k_EControllerActionOrigin_XBox360_Y, + k_EControllerActionOrigin_XBox360_LeftBumper, + k_EControllerActionOrigin_XBox360_RightBumper, + k_EControllerActionOrigin_XBox360_Start, //Start + k_EControllerActionOrigin_XBox360_Back, //Back + k_EControllerActionOrigin_XBox360_LeftTrigger_Pull, + k_EControllerActionOrigin_XBox360_LeftTrigger_Click, + k_EControllerActionOrigin_XBox360_RightTrigger_Pull, + k_EControllerActionOrigin_XBox360_RightTrigger_Click, + k_EControllerActionOrigin_XBox360_LeftStick_Move, + k_EControllerActionOrigin_XBox360_LeftStick_Click, + k_EControllerActionOrigin_XBox360_LeftStick_DPadNorth, + k_EControllerActionOrigin_XBox360_LeftStick_DPadSouth, + k_EControllerActionOrigin_XBox360_LeftStick_DPadWest, + k_EControllerActionOrigin_XBox360_LeftStick_DPadEast, + k_EControllerActionOrigin_XBox360_RightStick_Move, + k_EControllerActionOrigin_XBox360_RightStick_Click, + k_EControllerActionOrigin_XBox360_RightStick_DPadNorth, + k_EControllerActionOrigin_XBox360_RightStick_DPadSouth, + k_EControllerActionOrigin_XBox360_RightStick_DPadWest, + k_EControllerActionOrigin_XBox360_RightStick_DPadEast, + k_EControllerActionOrigin_XBox360_DPad_North, + k_EControllerActionOrigin_XBox360_DPad_South, + k_EControllerActionOrigin_XBox360_DPad_West, + k_EControllerActionOrigin_XBox360_DPad_East, + + // SteamController V2 + k_EControllerActionOrigin_SteamV2_A, + k_EControllerActionOrigin_SteamV2_B, + k_EControllerActionOrigin_SteamV2_X, + k_EControllerActionOrigin_SteamV2_Y, + k_EControllerActionOrigin_SteamV2_LeftBumper, + k_EControllerActionOrigin_SteamV2_RightBumper, + k_EControllerActionOrigin_SteamV2_LeftGrip, + k_EControllerActionOrigin_SteamV2_RightGrip, + k_EControllerActionOrigin_SteamV2_LeftGrip_Upper, + k_EControllerActionOrigin_SteamV2_RightGrip_Upper, + k_EControllerActionOrigin_SteamV2_LeftBumper_Pressure, + k_EControllerActionOrigin_SteamV2_RightBumper_Pressure, + k_EControllerActionOrigin_SteamV2_LeftGrip_Pressure, + k_EControllerActionOrigin_SteamV2_RightGrip_Pressure, + k_EControllerActionOrigin_SteamV2_LeftGrip_Upper_Pressure, + k_EControllerActionOrigin_SteamV2_RightGrip_Upper_Pressure, + k_EControllerActionOrigin_SteamV2_Start, + k_EControllerActionOrigin_SteamV2_Back, + k_EControllerActionOrigin_SteamV2_LeftPad_Touch, + k_EControllerActionOrigin_SteamV2_LeftPad_Swipe, + k_EControllerActionOrigin_SteamV2_LeftPad_Click, + k_EControllerActionOrigin_SteamV2_LeftPad_Pressure, + k_EControllerActionOrigin_SteamV2_LeftPad_DPadNorth, + k_EControllerActionOrigin_SteamV2_LeftPad_DPadSouth, + k_EControllerActionOrigin_SteamV2_LeftPad_DPadWest, + k_EControllerActionOrigin_SteamV2_LeftPad_DPadEast, + k_EControllerActionOrigin_SteamV2_RightPad_Touch, + k_EControllerActionOrigin_SteamV2_RightPad_Swipe, + k_EControllerActionOrigin_SteamV2_RightPad_Click, + k_EControllerActionOrigin_SteamV2_RightPad_Pressure, + k_EControllerActionOrigin_SteamV2_RightPad_DPadNorth, + k_EControllerActionOrigin_SteamV2_RightPad_DPadSouth, + k_EControllerActionOrigin_SteamV2_RightPad_DPadWest, + k_EControllerActionOrigin_SteamV2_RightPad_DPadEast, + k_EControllerActionOrigin_SteamV2_LeftTrigger_Pull, + k_EControllerActionOrigin_SteamV2_LeftTrigger_Click, + k_EControllerActionOrigin_SteamV2_RightTrigger_Pull, + k_EControllerActionOrigin_SteamV2_RightTrigger_Click, + k_EControllerActionOrigin_SteamV2_LeftStick_Move, + k_EControllerActionOrigin_SteamV2_LeftStick_Click, + k_EControllerActionOrigin_SteamV2_LeftStick_DPadNorth, + k_EControllerActionOrigin_SteamV2_LeftStick_DPadSouth, + k_EControllerActionOrigin_SteamV2_LeftStick_DPadWest, + k_EControllerActionOrigin_SteamV2_LeftStick_DPadEast, + k_EControllerActionOrigin_SteamV2_Gyro_Move, + k_EControllerActionOrigin_SteamV2_Gyro_Pitch, + k_EControllerActionOrigin_SteamV2_Gyro_Yaw, + k_EControllerActionOrigin_SteamV2_Gyro_Roll, + + k_EControllerActionOrigin_Count +}; + +enum ESteamControllerLEDFlag +{ + k_ESteamControllerLEDFlag_SetColor, + k_ESteamControllerLEDFlag_RestoreUserDefault +}; + +enum ESteamInputType +{ + k_ESteamInputType_Unknown, + k_ESteamInputType_SteamController, + k_ESteamInputType_XBox360Controller, + k_ESteamInputType_XBoxOneController, + k_ESteamInputType_GenericXInput, + k_ESteamInputType_PS4Controller, +}; + +// ControllerHandle_t is used to refer to a specific controller. +// This handle will consistently identify a controller, even if it is disconnected and re-connected +typedef uint64 ControllerHandle_t; + + +// These handles are used to refer to a specific in-game action or action set +// All action handles should be queried during initialization for performance reasons +typedef uint64 ControllerActionSetHandle_t; +typedef uint64 ControllerDigitalActionHandle_t; +typedef uint64 ControllerAnalogActionHandle_t; + +#pragma pack( push, 1 ) + +struct ControllerAnalogActionData_t +{ + // Type of data coming from this action, this will match what got specified in the action set + EControllerSourceMode eMode; + + // The current state of this action; will be delta updates for mouse actions + float x, y; + + // Whether or not this action is currently available to be bound in the active action set + bool bActive; +}; + +struct ControllerDigitalActionData_t +{ + // The current state of this action; will be true if currently pressed + bool bState; + + // Whether or not this action is currently available to be bound in the active action set + bool bActive; +}; + +struct ControllerMotionData_t +{ + // Sensor-fused absolute rotation; will drift in heading + float rotQuatX; + float rotQuatY; + float rotQuatZ; + float rotQuatW; + + // Positional acceleration + float posAccelX; + float posAccelY; + float posAccelZ; + + // Angular velocity + float rotVelX; + float rotVelY; + float rotVelZ; +}; + +#pragma pack( pop ) + + +//----------------------------------------------------------------------------- +// Purpose: Native Steam controller support API +//----------------------------------------------------------------------------- +class ISteamController +{ +public: + + // Init and Shutdown must be called when starting/ending use of this interface + virtual bool Init() = 0; + virtual bool Shutdown() = 0; + + // Synchronize API state with the latest Steam Controller inputs available. This + // is performed automatically by SteamAPI_RunCallbacks, but for the absolute lowest + // possible latency, you call this directly before reading controller state. + virtual void RunFrame() = 0; + + // Enumerate currently connected controllers + // handlesOut should point to a STEAM_CONTROLLER_MAX_COUNT sized array of ControllerHandle_t handles + // Returns the number of handles written to handlesOut + virtual int GetConnectedControllers( ControllerHandle_t *handlesOut ) = 0; + + // Invokes the Steam overlay and brings up the binding screen + // Returns false is overlay is disabled / unavailable, or the user is not in Big Picture mode + virtual bool ShowBindingPanel( ControllerHandle_t controllerHandle ) = 0; + + // ACTION SETS + // Lookup the handle for an Action Set. Best to do this once on startup, and store the handles for all future API calls. + virtual ControllerActionSetHandle_t GetActionSetHandle( const char *pszActionSetName ) = 0; + + // Reconfigure the controller to use the specified action set (ie 'Menu', 'Walk' or 'Drive') + // This is cheap, and can be safely called repeatedly. It's often easier to repeatedly call it in + // your state loops, instead of trying to place it in all of your state transitions. + virtual void ActivateActionSet( ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetHandle ) = 0; + virtual ControllerActionSetHandle_t GetCurrentActionSet( ControllerHandle_t controllerHandle ) = 0; + + virtual void ActivateActionSetLayer( ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetLayerHandle ) = 0; + virtual void DeactivateActionSetLayer( ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetLayerHandle ) = 0; + virtual void DeactivateAllActionSetLayers( ControllerHandle_t controllerHandle ) = 0; + virtual int GetActiveActionSetLayers( ControllerHandle_t controllerHandle, ControllerActionSetHandle_t *handlesOut ) = 0; + + + // ACTIONS + // Lookup the handle for a digital action. Best to do this once on startup, and store the handles for all future API calls. + virtual ControllerDigitalActionHandle_t GetDigitalActionHandle( const char *pszActionName ) = 0; + + // Returns the current state of the supplied digital game action + virtual ControllerDigitalActionData_t GetDigitalActionData( ControllerHandle_t controllerHandle, ControllerDigitalActionHandle_t digitalActionHandle ) = 0; + + // Get the origin(s) for a digital action within an action set. Returns the number of origins supplied in originsOut. Use this to display the appropriate on-screen prompt for the action. + // originsOut should point to a STEAM_CONTROLLER_MAX_ORIGINS sized array of EControllerActionOrigin handles + virtual int GetDigitalActionOrigins( ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetHandle, ControllerDigitalActionHandle_t digitalActionHandle, EControllerActionOrigin *originsOut ) = 0; + + // Lookup the handle for an analog action. Best to do this once on startup, and store the handles for all future API calls. + virtual ControllerAnalogActionHandle_t GetAnalogActionHandle( const char *pszActionName ) = 0; + + // Returns the current state of these supplied analog game action + virtual ControllerAnalogActionData_t GetAnalogActionData( ControllerHandle_t controllerHandle, ControllerAnalogActionHandle_t analogActionHandle ) = 0; + + // Get the origin(s) for an analog action within an action set. Returns the number of origins supplied in originsOut. Use this to display the appropriate on-screen prompt for the action. + // originsOut should point to a STEAM_CONTROLLER_MAX_ORIGINS sized array of EControllerActionOrigin handles + virtual int GetAnalogActionOrigins( ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetHandle, ControllerAnalogActionHandle_t analogActionHandle, EControllerActionOrigin *originsOut ) = 0; + + virtual void StopAnalogActionMomentum( ControllerHandle_t controllerHandle, ControllerAnalogActionHandle_t eAction ) = 0; + + // Trigger a haptic pulse on a controller + virtual void TriggerHapticPulse( ControllerHandle_t controllerHandle, ESteamControllerPad eTargetPad, unsigned short usDurationMicroSec ) = 0; + + // Trigger a pulse with a duty cycle of usDurationMicroSec / usOffMicroSec, unRepeat times. + // nFlags is currently unused and reserved for future use. + virtual void TriggerRepeatedHapticPulse( ControllerHandle_t controllerHandle, ESteamControllerPad eTargetPad, unsigned short usDurationMicroSec, unsigned short usOffMicroSec, unsigned short unRepeat, unsigned int nFlags ) = 0; + + // Tigger a vibration event on supported controllers. + virtual void TriggerVibration( ControllerHandle_t controllerHandle, unsigned short usLeftSpeed, unsigned short usRightSpeed ) = 0; + + // Set the controller LED color on supported controllers. + virtual void SetLEDColor( ControllerHandle_t controllerHandle, uint8 nColorR, uint8 nColorG, uint8 nColorB, unsigned int nFlags ) = 0; + + // Returns the associated gamepad index for the specified controller, if emulating a gamepad + virtual int GetGamepadIndexForController( ControllerHandle_t ulControllerHandle ) = 0; + + // Returns the associated controller handle for the specified emulated gamepad + virtual ControllerHandle_t GetControllerForGamepadIndex( int nIndex ) = 0; + + // Returns raw motion data from the specified controller + virtual ControllerMotionData_t GetMotionData( ControllerHandle_t controllerHandle ) = 0; + + // Attempt to display origins of given action in the controller HUD, for the currently active action set + // Returns false is overlay is disabled / unavailable, or the user is not in Big Picture mode + virtual bool ShowDigitalActionOrigins( ControllerHandle_t controllerHandle, ControllerDigitalActionHandle_t digitalActionHandle, float flScale, float flXPosition, float flYPosition ) = 0; + virtual bool ShowAnalogActionOrigins( ControllerHandle_t controllerHandle, ControllerAnalogActionHandle_t analogActionHandle, float flScale, float flXPosition, float flYPosition ) = 0; + + // Returns a localized string (from Steam's language setting) for the specified origin + virtual const char *GetStringForActionOrigin( EControllerActionOrigin eOrigin ) = 0; + + // Get a local path to art for on-screen glyph for a particular origin + virtual const char *GetGlyphForActionOrigin( EControllerActionOrigin eOrigin ) = 0; + + // Returns the input type for a particular handle + virtual ESteamInputType GetInputTypeForHandle( ControllerHandle_t controllerHandle ) = 0; +}; + +#define STEAMCONTROLLER_INTERFACE_VERSION "SteamController006" + +#endif // ISTEAMCONTROLLER_H diff --git a/ScreenPlayWorkshop/ThirdParty/steam/isteamfriends.h b/ScreenPlayWorkshop/ThirdParty/steam/isteamfriends.h new file mode 100644 index 00000000..c1754c26 --- /dev/null +++ b/ScreenPlayWorkshop/ThirdParty/steam/isteamfriends.h @@ -0,0 +1,639 @@ +//====== Copyright (C) 1996-2008, Valve Corporation, All rights reserved. ===== +// +// Purpose: interface to both friends list data and general information about users +// +//============================================================================= + +#ifndef ISTEAMFRIENDS_H +#define ISTEAMFRIENDS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isteamclient.h" +#include "steamclientpublic.h" + + +//----------------------------------------------------------------------------- +// Purpose: set of relationships to other users +//----------------------------------------------------------------------------- +enum EFriendRelationship +{ + k_EFriendRelationshipNone = 0, + k_EFriendRelationshipBlocked = 1, // this doesn't get stored; the user has just done an Ignore on an friendship invite + k_EFriendRelationshipRequestRecipient = 2, + k_EFriendRelationshipFriend = 3, + k_EFriendRelationshipRequestInitiator = 4, + k_EFriendRelationshipIgnored = 5, // this is stored; the user has explicit blocked this other user from comments/chat/etc + k_EFriendRelationshipIgnoredFriend = 6, + k_EFriendRelationshipSuggested_DEPRECATED = 7, // was used by the original implementation of the facebook linking feature, but now unused. + + // keep this updated + k_EFriendRelationshipMax = 8, +}; + +// maximum length of friend group name (not including terminating nul!) +const int k_cchMaxFriendsGroupName = 64; + +// maximum number of groups a single user is allowed +const int k_cFriendsGroupLimit = 100; + +// friends group identifier type +typedef int16 FriendsGroupID_t; + +// invalid friends group identifier constant +const FriendsGroupID_t k_FriendsGroupID_Invalid = -1; + +const int k_cEnumerateFollowersMax = 50; + + +//----------------------------------------------------------------------------- +// Purpose: list of states a friend can be in +//----------------------------------------------------------------------------- +enum EPersonaState +{ + k_EPersonaStateOffline = 0, // friend is not currently logged on + k_EPersonaStateOnline = 1, // friend is logged on + k_EPersonaStateBusy = 2, // user is on, but busy + k_EPersonaStateAway = 3, // auto-away feature + k_EPersonaStateSnooze = 4, // auto-away for a long time + k_EPersonaStateLookingToTrade = 5, // Online, trading + k_EPersonaStateLookingToPlay = 6, // Online, wanting to play + k_EPersonaStateMax, +}; + + +//----------------------------------------------------------------------------- +// Purpose: flags for enumerating friends list, or quickly checking a the relationship between users +//----------------------------------------------------------------------------- +enum EFriendFlags +{ + k_EFriendFlagNone = 0x00, + k_EFriendFlagBlocked = 0x01, + k_EFriendFlagFriendshipRequested = 0x02, + k_EFriendFlagImmediate = 0x04, // "regular" friend + k_EFriendFlagClanMember = 0x08, + k_EFriendFlagOnGameServer = 0x10, + // k_EFriendFlagHasPlayedWith = 0x20, // not currently used + // k_EFriendFlagFriendOfFriend = 0x40, // not currently used + k_EFriendFlagRequestingFriendship = 0x80, + k_EFriendFlagRequestingInfo = 0x100, + k_EFriendFlagIgnored = 0x200, + k_EFriendFlagIgnoredFriend = 0x400, + // k_EFriendFlagSuggested = 0x800, // not used + k_EFriendFlagChatMember = 0x1000, + k_EFriendFlagAll = 0xFFFF, +}; + + +// friend game played information +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif +struct FriendGameInfo_t +{ + CGameID m_gameID; + uint32 m_unGameIP; + uint16 m_usGamePort; + uint16 m_usQueryPort; + CSteamID m_steamIDLobby; +}; +#pragma pack( pop ) + +// maximum number of characters in a user's name. Two flavors; one for UTF-8 and one for UTF-16. +// The UTF-8 version has to be very generous to accomodate characters that get large when encoded +// in UTF-8. +enum +{ + k_cchPersonaNameMax = 128, + k_cwchPersonaNameMax = 32, +}; + +//----------------------------------------------------------------------------- +// Purpose: user restriction flags +//----------------------------------------------------------------------------- +enum EUserRestriction +{ + k_nUserRestrictionNone = 0, // no known chat/content restriction + k_nUserRestrictionUnknown = 1, // we don't know yet (user offline) + k_nUserRestrictionAnyChat = 2, // user is not allowed to (or can't) send/recv any chat + k_nUserRestrictionVoiceChat = 4, // user is not allowed to (or can't) send/recv voice chat + k_nUserRestrictionGroupChat = 8, // user is not allowed to (or can't) send/recv group chat + k_nUserRestrictionRating = 16, // user is too young according to rating in current region + k_nUserRestrictionGameInvites = 32, // user cannot send or recv game invites (e.g. mobile) + k_nUserRestrictionTrading = 64, // user cannot participate in trading (console, mobile) +}; + +//----------------------------------------------------------------------------- +// Purpose: information about user sessions +//----------------------------------------------------------------------------- +struct FriendSessionStateInfo_t +{ + uint32 m_uiOnlineSessionInstances; + uint8 m_uiPublishedToFriendsSessionInstance; +}; + + + +// size limit on chat room or member metadata +const uint32 k_cubChatMetadataMax = 8192; + +// size limits on Rich Presence data +enum { k_cchMaxRichPresenceKeys = 20 }; +enum { k_cchMaxRichPresenceKeyLength = 64 }; +enum { k_cchMaxRichPresenceValueLength = 256 }; + +// These values are passed as parameters to the store +enum EOverlayToStoreFlag +{ + k_EOverlayToStoreFlag_None = 0, + k_EOverlayToStoreFlag_AddToCart = 1, + k_EOverlayToStoreFlag_AddToCartAndShow = 2, +}; + +//----------------------------------------------------------------------------- +// Purpose: interface to accessing information about individual users, +// that can be a friend, in a group, on a game server or in a lobby with the local user +//----------------------------------------------------------------------------- +class ISteamFriends +{ +public: + // returns the local players name - guaranteed to not be NULL. + // this is the same name as on the users community profile page + // this is stored in UTF-8 format + // like all the other interface functions that return a char *, it's important that this pointer is not saved + // off; it will eventually be free'd or re-allocated + virtual const char *GetPersonaName() = 0; + + // Sets the player name, stores it on the server and publishes the changes to all friends who are online. + // Changes take place locally immediately, and a PersonaStateChange_t is posted, presuming success. + // + // The final results are available through the return value SteamAPICall_t, using SetPersonaNameResponse_t. + // + // If the name change fails to happen on the server, then an additional global PersonaStateChange_t will be posted + // to change the name back, in addition to the SetPersonaNameResponse_t callback. + CALL_RESULT( SetPersonaNameResponse_t ) + virtual SteamAPICall_t SetPersonaName( const char *pchPersonaName ) = 0; + + // gets the status of the current user + virtual EPersonaState GetPersonaState() = 0; + + // friend iteration + // takes a set of k_EFriendFlags, and returns the number of users the client knows about who meet that criteria + // then GetFriendByIndex() can then be used to return the id's of each of those users + virtual int GetFriendCount( int iFriendFlags ) = 0; + + // returns the steamID of a user + // iFriend is a index of range [0, GetFriendCount()) + // iFriendsFlags must be the same value as used in GetFriendCount() + // the returned CSteamID can then be used by all the functions below to access details about the user + virtual CSteamID GetFriendByIndex( int iFriend, int iFriendFlags ) = 0; + + // returns a relationship to a user + virtual EFriendRelationship GetFriendRelationship( CSteamID steamIDFriend ) = 0; + + // returns the current status of the specified user + // this will only be known by the local user if steamIDFriend is in their friends list; on the same game server; in a chat room or lobby; or in a small group with the local user + virtual EPersonaState GetFriendPersonaState( CSteamID steamIDFriend ) = 0; + + // returns the name another user - guaranteed to not be NULL. + // same rules as GetFriendPersonaState() apply as to whether or not the user knowns the name of the other user + // note that on first joining a lobby, chat room or game server the local user will not known the name of the other users automatically; that information will arrive asyncronously + // + virtual const char *GetFriendPersonaName( CSteamID steamIDFriend ) = 0; + + // returns true if the friend is actually in a game, and fills in pFriendGameInfo with an extra details + virtual bool GetFriendGamePlayed( CSteamID steamIDFriend, OUT_STRUCT() FriendGameInfo_t *pFriendGameInfo ) = 0; + // accesses old friends names - returns an empty string when their are no more items in the history + virtual const char *GetFriendPersonaNameHistory( CSteamID steamIDFriend, int iPersonaName ) = 0; + // friends steam level + virtual int GetFriendSteamLevel( CSteamID steamIDFriend ) = 0; + + // Returns nickname the current user has set for the specified player. Returns NULL if the no nickname has been set for that player. + virtual const char *GetPlayerNickname( CSteamID steamIDPlayer ) = 0; + + // friend grouping (tag) apis + // returns the number of friends groups + virtual int GetFriendsGroupCount() = 0; + // returns the friends group ID for the given index (invalid indices return k_FriendsGroupID_Invalid) + virtual FriendsGroupID_t GetFriendsGroupIDByIndex( int iFG ) = 0; + // returns the name for the given friends group (NULL in the case of invalid friends group IDs) + virtual const char *GetFriendsGroupName( FriendsGroupID_t friendsGroupID ) = 0; + // returns the number of members in a given friends group + virtual int GetFriendsGroupMembersCount( FriendsGroupID_t friendsGroupID ) = 0; + // gets up to nMembersCount members of the given friends group, if fewer exist than requested those positions' SteamIDs will be invalid + virtual void GetFriendsGroupMembersList( FriendsGroupID_t friendsGroupID, OUT_ARRAY_CALL(nMembersCount, GetFriendsGroupMembersCount, friendsGroupID ) CSteamID *pOutSteamIDMembers, int nMembersCount ) = 0; + + // returns true if the specified user meets any of the criteria specified in iFriendFlags + // iFriendFlags can be the union (binary or, |) of one or more k_EFriendFlags values + virtual bool HasFriend( CSteamID steamIDFriend, int iFriendFlags ) = 0; + + // clan (group) iteration and access functions + virtual int GetClanCount() = 0; + virtual CSteamID GetClanByIndex( int iClan ) = 0; + virtual const char *GetClanName( CSteamID steamIDClan ) = 0; + virtual const char *GetClanTag( CSteamID steamIDClan ) = 0; + // returns the most recent information we have about what's happening in a clan + virtual bool GetClanActivityCounts( CSteamID steamIDClan, int *pnOnline, int *pnInGame, int *pnChatting ) = 0; + // for clans a user is a member of, they will have reasonably up-to-date information, but for others you'll have to download the info to have the latest + virtual SteamAPICall_t DownloadClanActivityCounts( ARRAY_COUNT(cClansToRequest) CSteamID *psteamIDClans, int cClansToRequest ) = 0; + + // iterators for getting users in a chat room, lobby, game server or clan + // note that large clans that cannot be iterated by the local user + // note that the current user must be in a lobby to retrieve CSteamIDs of other users in that lobby + // steamIDSource can be the steamID of a group, game server, lobby or chat room + virtual int GetFriendCountFromSource( CSteamID steamIDSource ) = 0; + virtual CSteamID GetFriendFromSourceByIndex( CSteamID steamIDSource, int iFriend ) = 0; + + // returns true if the local user can see that steamIDUser is a member or in steamIDSource + virtual bool IsUserInSource( CSteamID steamIDUser, CSteamID steamIDSource ) = 0; + + // User is in a game pressing the talk button (will suppress the microphone for all voice comms from the Steam friends UI) + virtual void SetInGameVoiceSpeaking( CSteamID steamIDUser, bool bSpeaking ) = 0; + + // activates the game overlay, with an optional dialog to open + // valid options are "Friends", "Community", "Players", "Settings", "OfficialGameGroup", "Stats", "Achievements" + virtual void ActivateGameOverlay( const char *pchDialog ) = 0; + + // activates game overlay to a specific place + // valid options are + // "steamid" - opens the overlay web browser to the specified user or groups profile + // "chat" - opens a chat window to the specified user, or joins the group chat + // "jointrade" - opens a window to a Steam Trading session that was started with the ISteamEconomy/StartTrade Web API + // "stats" - opens the overlay web browser to the specified user's stats + // "achievements" - opens the overlay web browser to the specified user's achievements + // "friendadd" - opens the overlay in minimal mode prompting the user to add the target user as a friend + // "friendremove" - opens the overlay in minimal mode prompting the user to remove the target friend + // "friendrequestaccept" - opens the overlay in minimal mode prompting the user to accept an incoming friend invite + // "friendrequestignore" - opens the overlay in minimal mode prompting the user to ignore an incoming friend invite + virtual void ActivateGameOverlayToUser( const char *pchDialog, CSteamID steamID ) = 0; + + // activates game overlay web browser directly to the specified URL + // full address with protocol type is required, e.g. http://www.steamgames.com/ + virtual void ActivateGameOverlayToWebPage( const char *pchURL ) = 0; + + // activates game overlay to store page for app + virtual void ActivateGameOverlayToStore( AppId_t nAppID, EOverlayToStoreFlag eFlag ) = 0; + + // Mark a target user as 'played with'. This is a client-side only feature that requires that the calling user is + // in game + virtual void SetPlayedWith( CSteamID steamIDUserPlayedWith ) = 0; + + // activates game overlay to open the invite dialog. Invitations will be sent for the provided lobby. + virtual void ActivateGameOverlayInviteDialog( CSteamID steamIDLobby ) = 0; + + // gets the small (32x32) avatar of the current user, which is a handle to be used in IClientUtils::GetImageRGBA(), or 0 if none set + virtual int GetSmallFriendAvatar( CSteamID steamIDFriend ) = 0; + + // gets the medium (64x64) avatar of the current user, which is a handle to be used in IClientUtils::GetImageRGBA(), or 0 if none set + virtual int GetMediumFriendAvatar( CSteamID steamIDFriend ) = 0; + + // gets the large (184x184) avatar of the current user, which is a handle to be used in IClientUtils::GetImageRGBA(), or 0 if none set + // returns -1 if this image has yet to be loaded, in this case wait for a AvatarImageLoaded_t callback and then call this again + virtual int GetLargeFriendAvatar( CSteamID steamIDFriend ) = 0; + + // requests information about a user - persona name & avatar + // if bRequireNameOnly is set, then the avatar of a user isn't downloaded + // - it's a lot slower to download avatars and churns the local cache, so if you don't need avatars, don't request them + // if returns true, it means that data is being requested, and a PersonaStateChanged_t callback will be posted when it's retrieved + // if returns false, it means that we already have all the details about that user, and functions can be called immediately + virtual bool RequestUserInformation( CSteamID steamIDUser, bool bRequireNameOnly ) = 0; + + // requests information about a clan officer list + // when complete, data is returned in ClanOfficerListResponse_t call result + // this makes available the calls below + // you can only ask about clans that a user is a member of + // note that this won't download avatars automatically; if you get an officer, + // and no avatar image is available, call RequestUserInformation( steamID, false ) to download the avatar + CALL_RESULT( ClanOfficerListResponse_t ) + virtual SteamAPICall_t RequestClanOfficerList( CSteamID steamIDClan ) = 0; + + // iteration of clan officers - can only be done when a RequestClanOfficerList() call has completed + + // returns the steamID of the clan owner + virtual CSteamID GetClanOwner( CSteamID steamIDClan ) = 0; + // returns the number of officers in a clan (including the owner) + virtual int GetClanOfficerCount( CSteamID steamIDClan ) = 0; + // returns the steamID of a clan officer, by index, of range [0,GetClanOfficerCount) + virtual CSteamID GetClanOfficerByIndex( CSteamID steamIDClan, int iOfficer ) = 0; + // if current user is chat restricted, he can't send or receive any text/voice chat messages. + // the user can't see custom avatars. But the user can be online and send/recv game invites. + // a chat restricted user can't add friends or join any groups. + virtual uint32 GetUserRestrictions() = 0; + + // Rich Presence data is automatically shared between friends who are in the same game + // Each user has a set of Key/Value pairs + // Note the following limits: k_cchMaxRichPresenceKeys, k_cchMaxRichPresenceKeyLength, k_cchMaxRichPresenceValueLength + // There are two magic keys: + // "status" - a UTF-8 string that will show up in the 'view game info' dialog in the Steam friends list + // "connect" - a UTF-8 string that contains the command-line for how a friend can connect to a game + // GetFriendRichPresence() returns an empty string "" if no value is set + // SetRichPresence() to a NULL or an empty string deletes the key + // You can iterate the current set of keys for a friend with GetFriendRichPresenceKeyCount() + // and GetFriendRichPresenceKeyByIndex() (typically only used for debugging) + virtual bool SetRichPresence( const char *pchKey, const char *pchValue ) = 0; + virtual void ClearRichPresence() = 0; + virtual const char *GetFriendRichPresence( CSteamID steamIDFriend, const char *pchKey ) = 0; + virtual int GetFriendRichPresenceKeyCount( CSteamID steamIDFriend ) = 0; + virtual const char *GetFriendRichPresenceKeyByIndex( CSteamID steamIDFriend, int iKey ) = 0; + // Requests rich presence for a specific user. + virtual void RequestFriendRichPresence( CSteamID steamIDFriend ) = 0; + + // rich invite support + // if the target accepts the invite, the pchConnectString gets added to the command-line for launching the game + // if the game is already running, a GameRichPresenceJoinRequested_t callback is posted containing the connect string + // invites can only be sent to friends + virtual bool InviteUserToGame( CSteamID steamIDFriend, const char *pchConnectString ) = 0; + + // recently-played-with friends iteration + // this iterates the entire list of users recently played with, across games + // GetFriendCoplayTime() returns as a unix time + virtual int GetCoplayFriendCount() = 0; + virtual CSteamID GetCoplayFriend( int iCoplayFriend ) = 0; + virtual int GetFriendCoplayTime( CSteamID steamIDFriend ) = 0; + virtual AppId_t GetFriendCoplayGame( CSteamID steamIDFriend ) = 0; + + // chat interface for games + // this allows in-game access to group (clan) chats from in the game + // the behavior is somewhat sophisticated, because the user may or may not be already in the group chat from outside the game or in the overlay + // use ActivateGameOverlayToUser( "chat", steamIDClan ) to open the in-game overlay version of the chat + CALL_RESULT( JoinClanChatRoomCompletionResult_t ) + virtual SteamAPICall_t JoinClanChatRoom( CSteamID steamIDClan ) = 0; + virtual bool LeaveClanChatRoom( CSteamID steamIDClan ) = 0; + virtual int GetClanChatMemberCount( CSteamID steamIDClan ) = 0; + virtual CSteamID GetChatMemberByIndex( CSteamID steamIDClan, int iUser ) = 0; + virtual bool SendClanChatMessage( CSteamID steamIDClanChat, const char *pchText ) = 0; + virtual int GetClanChatMessage( CSteamID steamIDClanChat, int iMessage, void *prgchText, int cchTextMax, EChatEntryType *peChatEntryType, OUT_STRUCT() CSteamID *psteamidChatter ) = 0; + virtual bool IsClanChatAdmin( CSteamID steamIDClanChat, CSteamID steamIDUser ) = 0; + + // interact with the Steam (game overlay / desktop) + virtual bool IsClanChatWindowOpenInSteam( CSteamID steamIDClanChat ) = 0; + virtual bool OpenClanChatWindowInSteam( CSteamID steamIDClanChat ) = 0; + virtual bool CloseClanChatWindowInSteam( CSteamID steamIDClanChat ) = 0; + + // peer-to-peer chat interception + // this is so you can show P2P chats inline in the game + virtual bool SetListenForFriendsMessages( bool bInterceptEnabled ) = 0; + virtual bool ReplyToFriendMessage( CSteamID steamIDFriend, const char *pchMsgToSend ) = 0; + virtual int GetFriendMessage( CSteamID steamIDFriend, int iMessageID, void *pvData, int cubData, EChatEntryType *peChatEntryType ) = 0; + + // following apis + CALL_RESULT( FriendsGetFollowerCount_t ) + virtual SteamAPICall_t GetFollowerCount( CSteamID steamID ) = 0; + CALL_RESULT( FriendsIsFollowing_t ) + virtual SteamAPICall_t IsFollowing( CSteamID steamID ) = 0; + CALL_RESULT( FriendsEnumerateFollowingList_t ) + virtual SteamAPICall_t EnumerateFollowingList( uint32 unStartIndex ) = 0; + + virtual bool IsClanPublic( CSteamID steamIDClan ) = 0; + virtual bool IsClanOfficialGameGroup( CSteamID steamIDClan ) = 0; +}; + +#define STEAMFRIENDS_INTERFACE_VERSION "SteamFriends015" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + +//----------------------------------------------------------------------------- +// Purpose: called when a friends' status changes +//----------------------------------------------------------------------------- +struct PersonaStateChange_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 4 }; + + uint64 m_ulSteamID; // steamID of the friend who changed + int m_nChangeFlags; // what's changed +}; + + +// used in PersonaStateChange_t::m_nChangeFlags to describe what's changed about a user +// these flags describe what the client has learned has changed recently, so on startup you'll see a name, avatar & relationship change for every friend +enum EPersonaChange +{ + k_EPersonaChangeName = 0x0001, + k_EPersonaChangeStatus = 0x0002, + k_EPersonaChangeComeOnline = 0x0004, + k_EPersonaChangeGoneOffline = 0x0008, + k_EPersonaChangeGamePlayed = 0x0010, + k_EPersonaChangeGameServer = 0x0020, + k_EPersonaChangeAvatar = 0x0040, + k_EPersonaChangeJoinedSource= 0x0080, + k_EPersonaChangeLeftSource = 0x0100, + k_EPersonaChangeRelationshipChanged = 0x0200, + k_EPersonaChangeNameFirstSet = 0x0400, + k_EPersonaChangeFacebookInfo = 0x0800, + k_EPersonaChangeNickname = 0x1000, + k_EPersonaChangeSteamLevel = 0x2000, +}; + + +//----------------------------------------------------------------------------- +// Purpose: posted when game overlay activates or deactivates +// the game can use this to be pause or resume single player games +//----------------------------------------------------------------------------- +struct GameOverlayActivated_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 31 }; + uint8 m_bActive; // true if it's just been activated, false otherwise +}; + + +//----------------------------------------------------------------------------- +// Purpose: called when the user tries to join a different game server from their friends list +// game client should attempt to connect to specified server when this is received +//----------------------------------------------------------------------------- +struct GameServerChangeRequested_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 32 }; + char m_rgchServer[64]; // server address ("127.0.0.1:27015", "tf2.valvesoftware.com") + char m_rgchPassword[64]; // server password, if any +}; + + +//----------------------------------------------------------------------------- +// Purpose: called when the user tries to join a lobby from their friends list +// game client should attempt to connect to specified lobby when this is received +//----------------------------------------------------------------------------- +struct GameLobbyJoinRequested_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 33 }; + CSteamID m_steamIDLobby; + + // The friend they did the join via (will be invalid if not directly via a friend) + // + // On PS3, the friend will be invalid if this was triggered by a PSN invite via the XMB, but + // the account type will be console user so you can tell at least that this was from a PSN friend + // rather than a Steam friend. + CSteamID m_steamIDFriend; +}; + + +//----------------------------------------------------------------------------- +// Purpose: called when an avatar is loaded in from a previous GetLargeFriendAvatar() call +// if the image wasn't already available +//----------------------------------------------------------------------------- +struct AvatarImageLoaded_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 34 }; + CSteamID m_steamID; // steamid the avatar has been loaded for + int m_iImage; // the image index of the now loaded image + int m_iWide; // width of the loaded image + int m_iTall; // height of the loaded image +}; + + +//----------------------------------------------------------------------------- +// Purpose: marks the return of a request officer list call +//----------------------------------------------------------------------------- +struct ClanOfficerListResponse_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 35 }; + CSteamID m_steamIDClan; + int m_cOfficers; + uint8 m_bSuccess; +}; + + +//----------------------------------------------------------------------------- +// Purpose: callback indicating updated data about friends rich presence information +//----------------------------------------------------------------------------- +struct FriendRichPresenceUpdate_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 36 }; + CSteamID m_steamIDFriend; // friend who's rich presence has changed + AppId_t m_nAppID; // the appID of the game (should always be the current game) +}; + + +//----------------------------------------------------------------------------- +// Purpose: called when the user tries to join a game from their friends list +// rich presence will have been set with the "connect" key which is set here +//----------------------------------------------------------------------------- +struct GameRichPresenceJoinRequested_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 37 }; + CSteamID m_steamIDFriend; // the friend they did the join via (will be invalid if not directly via a friend) + char m_rgchConnect[k_cchMaxRichPresenceValueLength]; +}; + + +//----------------------------------------------------------------------------- +// Purpose: a chat message has been received for a clan chat the game has joined +//----------------------------------------------------------------------------- +struct GameConnectedClanChatMsg_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 38 }; + CSteamID m_steamIDClanChat; + CSteamID m_steamIDUser; + int m_iMessageID; +}; + + +//----------------------------------------------------------------------------- +// Purpose: a user has joined a clan chat +//----------------------------------------------------------------------------- +struct GameConnectedChatJoin_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 39 }; + CSteamID m_steamIDClanChat; + CSteamID m_steamIDUser; +}; + + +//----------------------------------------------------------------------------- +// Purpose: a user has left the chat we're in +//----------------------------------------------------------------------------- +struct GameConnectedChatLeave_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 40 }; + CSteamID m_steamIDClanChat; + CSteamID m_steamIDUser; + bool m_bKicked; // true if admin kicked + bool m_bDropped; // true if Steam connection dropped +}; + + +//----------------------------------------------------------------------------- +// Purpose: a DownloadClanActivityCounts() call has finished +//----------------------------------------------------------------------------- +struct DownloadClanActivityCountsResult_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 41 }; + bool m_bSuccess; +}; + + +//----------------------------------------------------------------------------- +// Purpose: a JoinClanChatRoom() call has finished +//----------------------------------------------------------------------------- +struct JoinClanChatRoomCompletionResult_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 42 }; + CSteamID m_steamIDClanChat; + EChatRoomEnterResponse m_eChatRoomEnterResponse; +}; + +//----------------------------------------------------------------------------- +// Purpose: a chat message has been received from a user +//----------------------------------------------------------------------------- +struct GameConnectedFriendChatMsg_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 43 }; + CSteamID m_steamIDUser; + int m_iMessageID; +}; + + +struct FriendsGetFollowerCount_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 44 }; + EResult m_eResult; + CSteamID m_steamID; + int m_nCount; +}; + + +struct FriendsIsFollowing_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 45 }; + EResult m_eResult; + CSteamID m_steamID; + bool m_bIsFollowing; +}; + + +struct FriendsEnumerateFollowingList_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 46 }; + EResult m_eResult; + CSteamID m_rgSteamID[ k_cEnumerateFollowersMax ]; + int32 m_nResultsReturned; + int32 m_nTotalResultCount; +}; + +//----------------------------------------------------------------------------- +// Purpose: reports the result of an attempt to change the user's persona name +//----------------------------------------------------------------------------- +struct SetPersonaNameResponse_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 47 }; + + bool m_bSuccess; // true if name change succeeded completely. + bool m_bLocalSuccess; // true if name change was retained locally. (We might not have been able to communicate with Steam) + EResult m_result; // detailed result code +}; + + +#pragma pack( pop ) + +#endif // ISTEAMFRIENDS_H diff --git a/ScreenPlayWorkshop/ThirdParty/steam/isteamgamecoordinator.h b/ScreenPlayWorkshop/ThirdParty/steam/isteamgamecoordinator.h new file mode 100644 index 00000000..5ab0637f --- /dev/null +++ b/ScreenPlayWorkshop/ThirdParty/steam/isteamgamecoordinator.h @@ -0,0 +1,75 @@ +//====== Copyright ©, Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to the game coordinator for this application +// +//============================================================================= + +#ifndef ISTEAMGAMECOORDINATOR +#define ISTEAMGAMECOORDINATOR +#ifdef _WIN32 +#pragma once +#endif + +#include "steamtypes.h" +#include "steamclientpublic.h" + + +// list of possible return values from the ISteamGameCoordinator API +enum EGCResults +{ + k_EGCResultOK = 0, + k_EGCResultNoMessage = 1, // There is no message in the queue + k_EGCResultBufferTooSmall = 2, // The buffer is too small for the requested message + k_EGCResultNotLoggedOn = 3, // The client is not logged onto Steam + k_EGCResultInvalidMessage = 4, // Something was wrong with the message being sent with SendMessage +}; + + +//----------------------------------------------------------------------------- +// Purpose: Functions for sending and receiving messages from the Game Coordinator +// for this application +//----------------------------------------------------------------------------- +class ISteamGameCoordinator +{ +public: + + // sends a message to the Game Coordinator + virtual EGCResults SendMessage( uint32 unMsgType, const void *pubData, uint32 cubData ) = 0; + + // returns true if there is a message waiting from the game coordinator + virtual bool IsMessageAvailable( uint32 *pcubMsgSize ) = 0; + + // fills the provided buffer with the first message in the queue and returns k_EGCResultOK or + // returns k_EGCResultNoMessage if there is no message waiting. pcubMsgSize is filled with the message size. + // If the provided buffer is not large enough to fit the entire message, k_EGCResultBufferTooSmall is returned + // and the message remains at the head of the queue. + virtual EGCResults RetrieveMessage( uint32 *punMsgType, void *pubDest, uint32 cubDest, uint32 *pcubMsgSize ) = 0; + +}; +#define STEAMGAMECOORDINATOR_INTERFACE_VERSION "SteamGameCoordinator001" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + +// callback notification - A new message is available for reading from the message queue +struct GCMessageAvailable_t +{ + enum { k_iCallback = k_iSteamGameCoordinatorCallbacks + 1 }; + uint32 m_nMessageSize; +}; + +// callback notification - A message failed to make it to the GC. It may be down temporarily +struct GCMessageFailed_t +{ + enum { k_iCallback = k_iSteamGameCoordinatorCallbacks + 2 }; +}; + +#pragma pack( pop ) + +#endif // ISTEAMGAMECOORDINATOR diff --git a/ScreenPlayWorkshop/ThirdParty/steam/isteamgameserver.h b/ScreenPlayWorkshop/ThirdParty/steam/isteamgameserver.h new file mode 100644 index 00000000..e19f1dda --- /dev/null +++ b/ScreenPlayWorkshop/ThirdParty/steam/isteamgameserver.h @@ -0,0 +1,387 @@ +//====== Copyright (c) 1996-2008, Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to steam for game servers +// +//============================================================================= + +#ifndef ISTEAMGAMESERVER_H +#define ISTEAMGAMESERVER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isteamclient.h" + +#define MASTERSERVERUPDATERPORT_USEGAMESOCKETSHARE ((uint16)-1) + +//----------------------------------------------------------------------------- +// Purpose: Functions for authenticating users via Steam to play on a game server +//----------------------------------------------------------------------------- +class ISteamGameServer +{ +public: + +// +// Basic server data. These properties, if set, must be set before before calling LogOn. They +// may not be changed after logged in. +// + + /// This is called by SteamGameServer_Init, and you will usually not need to call it directly + virtual bool InitGameServer( uint32 unIP, uint16 usGamePort, uint16 usQueryPort, uint32 unFlags, AppId_t nGameAppId, const char *pchVersionString ) = 0; + + /// Game product identifier. This is currently used by the master server for version checking purposes. + /// It's a required field, but will eventually will go away, and the AppID will be used for this purpose. + virtual void SetProduct( const char *pszProduct ) = 0; + + /// Description of the game. This is a required field and is displayed in the steam server browser....for now. + /// This is a required field, but it will go away eventually, as the data should be determined from the AppID. + virtual void SetGameDescription( const char *pszGameDescription ) = 0; + + /// If your game is a "mod," pass the string that identifies it. The default is an empty string, meaning + /// this application is the original game, not a mod. + /// + /// @see k_cbMaxGameServerGameDir + virtual void SetModDir( const char *pszModDir ) = 0; + + /// Is this is a dedicated server? The default value is false. + virtual void SetDedicatedServer( bool bDedicated ) = 0; + +// +// Login +// + + /// Begin process to login to a persistent game server account + /// + /// You need to register for callbacks to determine the result of this operation. + /// @see SteamServersConnected_t + /// @see SteamServerConnectFailure_t + /// @see SteamServersDisconnected_t + virtual void LogOn( const char *pszToken ) = 0; + + /// Login to a generic, anonymous account. + /// + /// Note: in previous versions of the SDK, this was automatically called within SteamGameServer_Init, + /// but this is no longer the case. + virtual void LogOnAnonymous() = 0; + + /// Begin process of logging game server out of steam + virtual void LogOff() = 0; + + // status functions + virtual bool BLoggedOn() = 0; + virtual bool BSecure() = 0; + virtual CSteamID GetSteamID() = 0; + + /// Returns true if the master server has requested a restart. + /// Only returns true once per request. + virtual bool WasRestartRequested() = 0; + +// +// Server state. These properties may be changed at any time. +// + + /// Max player count that will be reported to server browser and client queries + virtual void SetMaxPlayerCount( int cPlayersMax ) = 0; + + /// Number of bots. Default value is zero + virtual void SetBotPlayerCount( int cBotplayers ) = 0; + + /// Set the name of server as it will appear in the server browser + /// + /// @see k_cbMaxGameServerName + virtual void SetServerName( const char *pszServerName ) = 0; + + /// Set name of map to report in the server browser + /// + /// @see k_cbMaxGameServerName + virtual void SetMapName( const char *pszMapName ) = 0; + + /// Let people know if your server will require a password + virtual void SetPasswordProtected( bool bPasswordProtected ) = 0; + + /// Spectator server. The default value is zero, meaning the service + /// is not used. + virtual void SetSpectatorPort( uint16 unSpectatorPort ) = 0; + + /// Name of the spectator server. (Only used if spectator port is nonzero.) + /// + /// @see k_cbMaxGameServerMapName + virtual void SetSpectatorServerName( const char *pszSpectatorServerName ) = 0; + + /// Call this to clear the whole list of key/values that are sent in rules queries. + virtual void ClearAllKeyValues() = 0; + + /// Call this to add/update a key/value pair. + virtual void SetKeyValue( const char *pKey, const char *pValue ) = 0; + + /// Sets a string defining the "gametags" for this server, this is optional, but if it is set + /// it allows users to filter in the matchmaking/server-browser interfaces based on the value + /// + /// @see k_cbMaxGameServerTags + virtual void SetGameTags( const char *pchGameTags ) = 0; + + /// Sets a string defining the "gamedata" for this server, this is optional, but if it is set + /// it allows users to filter in the matchmaking/server-browser interfaces based on the value + /// don't set this unless it actually changes, its only uploaded to the master once (when + /// acknowledged) + /// + /// @see k_cbMaxGameServerGameData + virtual void SetGameData( const char *pchGameData ) = 0; + + /// Region identifier. This is an optional field, the default value is empty, meaning the "world" region + virtual void SetRegion( const char *pszRegion ) = 0; + +// +// Player list management / authentication +// + + // Handles receiving a new connection from a Steam user. This call will ask the Steam + // servers to validate the users identity, app ownership, and VAC status. If the Steam servers + // are off-line, then it will validate the cached ticket itself which will validate app ownership + // and identity. The AuthBlob here should be acquired on the game client using SteamUser()->InitiateGameConnection() + // and must then be sent up to the game server for authentication. + // + // Return Value: returns true if the users ticket passes basic checks. pSteamIDUser will contain the Steam ID of this user. pSteamIDUser must NOT be NULL + // If the call succeeds then you should expect a GSClientApprove_t or GSClientDeny_t callback which will tell you whether authentication + // for the user has succeeded or failed (the steamid in the callback will match the one returned by this call) + virtual bool SendUserConnectAndAuthenticate( uint32 unIPClient, const void *pvAuthBlob, uint32 cubAuthBlobSize, CSteamID *pSteamIDUser ) = 0; + + // Creates a fake user (ie, a bot) which will be listed as playing on the server, but skips validation. + // + // Return Value: Returns a SteamID for the user to be tracked with, you should call HandleUserDisconnect() + // when this user leaves the server just like you would for a real user. + virtual CSteamID CreateUnauthenticatedUserConnection() = 0; + + // Should be called whenever a user leaves our game server, this lets Steam internally + // track which users are currently on which servers for the purposes of preventing a single + // account being logged into multiple servers, showing who is currently on a server, etc. + virtual void SendUserDisconnect( CSteamID steamIDUser ) = 0; + + // Update the data to be displayed in the server browser and matchmaking interfaces for a user + // currently connected to the server. For regular users you must call this after you receive a + // GSUserValidationSuccess callback. + // + // Return Value: true if successful, false if failure (ie, steamIDUser wasn't for an active player) + virtual bool BUpdateUserData( CSteamID steamIDUser, const char *pchPlayerName, uint32 uScore ) = 0; + + // New auth system APIs - do not mix with the old auth system APIs. + // ---------------------------------------------------------------- + + // Retrieve ticket to be sent to the entity who wishes to authenticate you ( using BeginAuthSession API ). + // pcbTicket retrieves the length of the actual ticket. + virtual HAuthTicket GetAuthSessionTicket( void *pTicket, int cbMaxTicket, uint32 *pcbTicket ) = 0; + + // Authenticate ticket ( from GetAuthSessionTicket ) 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 ) + virtual EBeginAuthSessionResult BeginAuthSession( const void *pAuthTicket, int cbAuthTicket, CSteamID steamID ) = 0; + + // Stop tracking started by BeginAuthSession - called when no longer playing game with this entity + virtual void EndAuthSession( CSteamID steamID ) = 0; + + // Cancel auth ticket from GetAuthSessionTicket, called when no longer playing game with the entity you gave the ticket to + virtual void CancelAuthTicket( HAuthTicket hAuthTicket ) = 0; + + // After receiving a user's authentication data, and passing it to SendUserConnectAndAuthenticate, use this function + // to determine if the user owns downloadable content specified by the provided AppID. + virtual EUserHasLicenseForAppResult UserHasLicenseForApp( CSteamID steamID, AppId_t appID ) = 0; + + // Ask if a user in in the specified group, results returns async by GSUserGroupStatus_t + // returns false if we're not connected to the steam servers and thus cannot ask + virtual bool RequestUserGroupStatus( CSteamID steamIDUser, CSteamID steamIDGroup ) = 0; + + + // these two functions s are deprecated, and will not return results + // they will be removed in a future version of the SDK + virtual void GetGameplayStats( ) = 0; + CALL_RESULT( GSReputation_t ) + virtual SteamAPICall_t GetServerReputation() = 0; + + // Returns the public IP of the server according to Steam, useful when the server is + // behind NAT and you want to advertise its IP in a lobby for other clients to directly + // connect to + virtual uint32 GetPublicIP() = 0; + +// These are in GameSocketShare mode, where instead of ISteamGameServer creating its own +// socket to talk to the master server on, it lets the game use its socket to forward messages +// back and forth. This prevents us from requiring server ops to open up yet another port +// in their firewalls. +// +// the IP address and port should be in host order, i.e 127.0.0.1 == 0x7f000001 + + // These are used when you've elected to multiplex the game server's UDP socket + // rather than having the master server updater use its own sockets. + // + // Source games use this to simplify the job of the server admins, so they + // don't have to open up more ports on their firewalls. + + // Call this when a packet that starts with 0xFFFFFFFF comes in. That means + // it's for us. + virtual bool HandleIncomingPacket( const void *pData, int cbData, uint32 srcIP, uint16 srcPort ) = 0; + + // AFTER calling HandleIncomingPacket for any packets that came in that frame, call this. + // This gets a packet that the master server updater needs to send out on UDP. + // It returns the length of the packet it wants to send, or 0 if there are no more packets to send. + // Call this each frame until it returns 0. + virtual int GetNextOutgoingPacket( void *pOut, int cbMaxOut, uint32 *pNetAdr, uint16 *pPort ) = 0; + +// +// Control heartbeats / advertisement with master server +// + + // Call this as often as you like to tell the master server updater whether or not + // you want it to be active (default: off). + virtual void EnableHeartbeats( bool bActive ) = 0; + + // You usually don't need to modify this. + // Pass -1 to use the default value for iHeartbeatInterval. + // Some mods change this. + virtual void SetHeartbeatInterval( int iHeartbeatInterval ) = 0; + + // Force a heartbeat to steam at the next opportunity + virtual void ForceHeartbeat() = 0; + + // associate this game server with this clan for the purposes of computing player compat + CALL_RESULT( AssociateWithClanResult_t ) + virtual SteamAPICall_t AssociateWithClan( CSteamID steamIDClan ) = 0; + + // ask if any of the current players dont want to play with this new player - or vice versa + CALL_RESULT( ComputeNewPlayerCompatibilityResult_t ) + virtual SteamAPICall_t ComputeNewPlayerCompatibility( CSteamID steamIDNewPlayer ) = 0; + +}; + +#define STEAMGAMESERVER_INTERFACE_VERSION "SteamGameServer012" + +// game server flags +const uint32 k_unServerFlagNone = 0x00; +const uint32 k_unServerFlagActive = 0x01; // server has users playing +const uint32 k_unServerFlagSecure = 0x02; // server wants to be secure +const uint32 k_unServerFlagDedicated = 0x04; // server is dedicated +const uint32 k_unServerFlagLinux = 0x08; // linux build +const uint32 k_unServerFlagPassworded = 0x10; // password protected +const uint32 k_unServerFlagPrivate = 0x20; // server shouldn't list on master server and + // won't enforce authentication of users that connect to the server. + // Useful when you run a server where the clients may not + // be connected to the internet but you want them to play (i.e LANs) + + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + + +// client has been approved to connect to this game server +struct GSClientApprove_t +{ + enum { k_iCallback = k_iSteamGameServerCallbacks + 1 }; + CSteamID m_SteamID; // SteamID of approved player + CSteamID m_OwnerSteamID; // SteamID of original owner for game license +}; + + +// client has been denied to connection to this game server +struct GSClientDeny_t +{ + enum { k_iCallback = k_iSteamGameServerCallbacks + 2 }; + CSteamID m_SteamID; + EDenyReason m_eDenyReason; + char m_rgchOptionalText[128]; +}; + + +// request the game server should kick the user +struct GSClientKick_t +{ + enum { k_iCallback = k_iSteamGameServerCallbacks + 3 }; + CSteamID m_SteamID; + EDenyReason m_eDenyReason; +}; + +// NOTE: callback values 4 and 5 are skipped because they are used for old deprecated callbacks, +// do not reuse them here. + + +// client achievement info +struct GSClientAchievementStatus_t +{ + enum { k_iCallback = k_iSteamGameServerCallbacks + 6 }; + uint64 m_SteamID; + char m_pchAchievement[128]; + bool m_bUnlocked; +}; + +// received when the game server requests to be displayed as secure (VAC protected) +// m_bSecure is true if the game server should display itself as secure to users, false otherwise +struct GSPolicyResponse_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 15 }; + uint8 m_bSecure; +}; + +// GS gameplay stats info +struct GSGameplayStats_t +{ + enum { k_iCallback = k_iSteamGameServerCallbacks + 7 }; + EResult m_eResult; // Result of the call + int32 m_nRank; // Overall rank of the server (0-based) + uint32 m_unTotalConnects; // Total number of clients who have ever connected to the server + uint32 m_unTotalMinutesPlayed; // Total number of minutes ever played on the server +}; + +// send as a reply to RequestUserGroupStatus() +struct GSClientGroupStatus_t +{ + enum { k_iCallback = k_iSteamGameServerCallbacks + 8 }; + CSteamID m_SteamIDUser; + CSteamID m_SteamIDGroup; + bool m_bMember; + bool m_bOfficer; +}; + +// Sent as a reply to GetServerReputation() +struct GSReputation_t +{ + enum { k_iCallback = k_iSteamGameServerCallbacks + 9 }; + EResult m_eResult; // Result of the call; + uint32 m_unReputationScore; // The reputation score for the game server + bool m_bBanned; // True if the server is banned from the Steam + // master servers + + // The following members are only filled out if m_bBanned is true. They will all + // be set to zero otherwise. Master server bans are by IP so it is possible to be + // banned even when the score is good high if there is a bad server on another port. + // This information can be used to determine which server is bad. + + uint32 m_unBannedIP; // The IP of the banned server + uint16 m_usBannedPort; // The port of the banned server + uint64 m_ulBannedGameID; // The game ID the banned server is serving + uint32 m_unBanExpires; // Time the ban expires, expressed in the Unix epoch (seconds since 1/1/1970) +}; + +// Sent as a reply to AssociateWithClan() +struct AssociateWithClanResult_t +{ + enum { k_iCallback = k_iSteamGameServerCallbacks + 10 }; + EResult m_eResult; // Result of the call; +}; + +// Sent as a reply to ComputeNewPlayerCompatibility() +struct ComputeNewPlayerCompatibilityResult_t +{ + enum { k_iCallback = k_iSteamGameServerCallbacks + 11 }; + EResult m_eResult; // Result of the call; + int m_cPlayersThatDontLikeCandidate; + int m_cPlayersThatCandidateDoesntLike; + int m_cClanPlayersThatDontLikeCandidate; + CSteamID m_SteamIDCandidate; +}; + + +#pragma pack( pop ) + +#endif // ISTEAMGAMESERVER_H diff --git a/ScreenPlayWorkshop/ThirdParty/steam/isteamgameserverstats.h b/ScreenPlayWorkshop/ThirdParty/steam/isteamgameserverstats.h new file mode 100644 index 00000000..e7922c9c --- /dev/null +++ b/ScreenPlayWorkshop/ThirdParty/steam/isteamgameserverstats.h @@ -0,0 +1,101 @@ +//====== Copyright © Valve Corporation, All rights reserved. ======= +// +// Purpose: interface for game servers to steam stats and achievements +// +//============================================================================= + +#ifndef ISTEAMGAMESERVERSTATS_H +#define ISTEAMGAMESERVERSTATS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isteamclient.h" + +//----------------------------------------------------------------------------- +// Purpose: Functions for authenticating users via Steam to play on a game server +//----------------------------------------------------------------------------- +class ISteamGameServerStats +{ +public: + // downloads stats for the user + // returns a GSStatsReceived_t callback when completed + // if the user has no stats, GSStatsReceived_t.m_eResult will be set to k_EResultFail + // these stats will only be auto-updated for clients playing on the server. For other + // users you'll need to call RequestUserStats() again to refresh any data + CALL_RESULT( GSStatsReceived_t ) + virtual SteamAPICall_t RequestUserStats( CSteamID steamIDUser ) = 0; + + // requests stat information for a user, usable after a successful call to RequestUserStats() + virtual bool GetUserStat( CSteamID steamIDUser, const char *pchName, int32 *pData ) = 0; + virtual bool GetUserStat( CSteamID steamIDUser, const char *pchName, float *pData ) = 0; + virtual bool GetUserAchievement( CSteamID steamIDUser, const char *pchName, bool *pbAchieved ) = 0; + + // Set / update stats and achievements. + // Note: These updates will work only on stats game servers are allowed to edit and only for + // game servers that have been declared as officially controlled by the game creators. + // Set the IP range of your official servers on the Steamworks page + virtual bool SetUserStat( CSteamID steamIDUser, const char *pchName, int32 nData ) = 0; + virtual bool SetUserStat( CSteamID steamIDUser, const char *pchName, float fData ) = 0; + virtual bool UpdateUserAvgRateStat( CSteamID steamIDUser, const char *pchName, float flCountThisSession, double dSessionLength ) = 0; + + virtual bool SetUserAchievement( CSteamID steamIDUser, const char *pchName ) = 0; + virtual bool ClearUserAchievement( CSteamID steamIDUser, const char *pchName ) = 0; + + // Store the current data on the server, will get a GSStatsStored_t callback when set. + // + // 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. + CALL_RESULT( GSStatsStored_t ) + virtual SteamAPICall_t StoreUserStats( CSteamID steamIDUser ) = 0; +}; + +#define STEAMGAMESERVERSTATS_INTERFACE_VERSION "SteamGameServerStats001" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + +//----------------------------------------------------------------------------- +// Purpose: called when the latests stats and achievements have been received +// from the server +//----------------------------------------------------------------------------- +struct GSStatsReceived_t +{ + enum { k_iCallback = k_iSteamGameServerStatsCallbacks }; + EResult m_eResult; // Success / error fetching the stats + CSteamID m_steamIDUser; // The user for whom the stats are retrieved for +}; + + +//----------------------------------------------------------------------------- +// Purpose: result of a request to store the user stats for a game +//----------------------------------------------------------------------------- +struct GSStatsStored_t +{ + enum { k_iCallback = k_iSteamGameServerStatsCallbacks + 1 }; + EResult m_eResult; // success / error + CSteamID m_steamIDUser; // The user for whom the stats were stored +}; + +//----------------------------------------------------------------------------- +// Purpose: Callback indicating that a user's stats have been unloaded. +// Call RequestUserStats again to access stats for this user +//----------------------------------------------------------------------------- +struct GSStatsUnloaded_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 8 }; + CSteamID m_steamIDUser; // User whose stats have been unloaded +}; + +#pragma pack( pop ) + + +#endif // ISTEAMGAMESERVERSTATS_H diff --git a/ScreenPlayWorkshop/ThirdParty/steam/isteamhtmlsurface.h b/ScreenPlayWorkshop/ThirdParty/steam/isteamhtmlsurface.h new file mode 100644 index 00000000..117599ce --- /dev/null +++ b/ScreenPlayWorkshop/ThirdParty/steam/isteamhtmlsurface.h @@ -0,0 +1,466 @@ +//====== Copyright 1996-2013, Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to display html pages in a texture +// +//============================================================================= + +#ifndef ISTEAMHTMLSURFACE_H +#define ISTEAMHTMLSURFACE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isteamclient.h" + +typedef uint32 HHTMLBrowser; +const uint32 INVALID_HTMLBROWSER = 0; + +//----------------------------------------------------------------------------- +// Purpose: Functions for displaying HTML pages and interacting with them +//----------------------------------------------------------------------------- +class ISteamHTMLSurface +{ +public: + virtual ~ISteamHTMLSurface() {} + + // Must call init and shutdown when starting/ending use of the interface + virtual bool Init() = 0; + virtual bool Shutdown() = 0; + + // Create a browser object for display of a html page, when creation is complete the call handle + // will return a HTML_BrowserReady_t callback for the HHTMLBrowser of your new browser. + // The user agent string is a substring to be added to the general user agent string so you can + // identify your client on web servers. + // The userCSS string lets you apply a CSS style sheet to every displayed page, leave null if + // you do not require this functionality. + // + // YOU MUST HAVE IMPLEMENTED HANDLERS FOR HTML_BrowserReady_t, HTML_StartRequest_t, + // HTML_JSAlert_t, HTML_JSConfirm_t, and HTML_FileOpenDialog_t! See the CALLBACKS + // section of this interface (AllowStartRequest, etc) for more details. If you do + // not implement these callback handlers, the browser may appear to hang instead of + // navigating to new pages or triggering javascript popups. + // + CALL_RESULT( HTML_BrowserReady_t ) + virtual SteamAPICall_t CreateBrowser( const char *pchUserAgent, const char *pchUserCSS ) = 0; + + // Call this when you are done with a html surface, this lets us free the resources being used by it + virtual void RemoveBrowser( HHTMLBrowser unBrowserHandle ) = 0; + + // Navigate to this URL, results in a HTML_StartRequest_t as the request commences + virtual void LoadURL( HHTMLBrowser unBrowserHandle, const char *pchURL, const char *pchPostData ) = 0; + + // Tells the surface the size in pixels to display the surface + virtual void SetSize( HHTMLBrowser unBrowserHandle, uint32 unWidth, uint32 unHeight ) = 0; + + // Stop the load of the current html page + virtual void StopLoad( HHTMLBrowser unBrowserHandle ) = 0; + // Reload (most likely from local cache) the current page + virtual void Reload( HHTMLBrowser unBrowserHandle ) = 0; + // navigate back in the page history + virtual void GoBack( HHTMLBrowser unBrowserHandle ) = 0; + // navigate forward in the page history + virtual void GoForward( HHTMLBrowser unBrowserHandle ) = 0; + + // add this header to any url requests from this browser + virtual void AddHeader( HHTMLBrowser unBrowserHandle, const char *pchKey, const char *pchValue ) = 0; + // run this javascript script in the currently loaded page + virtual void ExecuteJavascript( HHTMLBrowser unBrowserHandle, const char *pchScript ) = 0; + + enum EHTMLMouseButton + { + eHTMLMouseButton_Left = 0, + eHTMLMouseButton_Right = 1, + eHTMLMouseButton_Middle = 2, + }; + + // Mouse click and mouse movement commands + virtual void MouseUp( HHTMLBrowser unBrowserHandle, EHTMLMouseButton eMouseButton ) = 0; + virtual void MouseDown( HHTMLBrowser unBrowserHandle, EHTMLMouseButton eMouseButton ) = 0; + virtual void MouseDoubleClick( HHTMLBrowser unBrowserHandle, EHTMLMouseButton eMouseButton ) = 0; + // x and y are relative to the HTML bounds + virtual void MouseMove( HHTMLBrowser unBrowserHandle, int x, int y ) = 0; + // nDelta is pixels of scroll + virtual void MouseWheel( HHTMLBrowser unBrowserHandle, int32 nDelta ) = 0; + + enum EMouseCursor + { + dc_user = 0, + dc_none, + dc_arrow, + dc_ibeam, + dc_hourglass, + dc_waitarrow, + dc_crosshair, + dc_up, + dc_sizenw, + dc_sizese, + dc_sizene, + dc_sizesw, + dc_sizew, + dc_sizee, + dc_sizen, + dc_sizes, + dc_sizewe, + dc_sizens, + dc_sizeall, + dc_no, + dc_hand, + dc_blank, // don't show any custom cursor, just use your default + dc_middle_pan, + dc_north_pan, + dc_north_east_pan, + dc_east_pan, + dc_south_east_pan, + dc_south_pan, + dc_south_west_pan, + dc_west_pan, + dc_north_west_pan, + dc_alias, + dc_cell, + dc_colresize, + dc_copycur, + dc_verticaltext, + dc_rowresize, + dc_zoomin, + dc_zoomout, + dc_help, + dc_custom, + + dc_last, // custom cursors start from this value and up + }; + + enum EHTMLKeyModifiers + { + k_eHTMLKeyModifier_None = 0, + k_eHTMLKeyModifier_AltDown = 1 << 0, + k_eHTMLKeyModifier_CtrlDown = 1 << 1, + k_eHTMLKeyModifier_ShiftDown = 1 << 2, + }; + + // keyboard interactions, native keycode is the virtual key code value from your OS + virtual void KeyDown( HHTMLBrowser unBrowserHandle, uint32 nNativeKeyCode, EHTMLKeyModifiers eHTMLKeyModifiers ) = 0; + virtual void KeyUp( HHTMLBrowser unBrowserHandle, uint32 nNativeKeyCode, EHTMLKeyModifiers eHTMLKeyModifiers ) = 0; + // cUnicodeChar is the unicode character point for this keypress (and potentially multiple chars per press) + virtual void KeyChar( HHTMLBrowser unBrowserHandle, uint32 cUnicodeChar, EHTMLKeyModifiers eHTMLKeyModifiers ) = 0; + + // programmatically scroll this many pixels on the page + virtual void SetHorizontalScroll( HHTMLBrowser unBrowserHandle, uint32 nAbsolutePixelScroll ) = 0; + virtual void SetVerticalScroll( HHTMLBrowser unBrowserHandle, uint32 nAbsolutePixelScroll ) = 0; + + // tell the html control if it has key focus currently, controls showing the I-beam cursor in text controls amongst other things + virtual void SetKeyFocus( HHTMLBrowser unBrowserHandle, bool bHasKeyFocus ) = 0; + + // open the current pages html code in the local editor of choice, used for debugging + virtual void ViewSource( HHTMLBrowser unBrowserHandle ) = 0; + // copy the currently selected text on the html page to the local clipboard + virtual void CopyToClipboard( HHTMLBrowser unBrowserHandle ) = 0; + // paste from the local clipboard to the current html page + virtual void PasteFromClipboard( HHTMLBrowser unBrowserHandle ) = 0; + + // find this string in the browser, if bCurrentlyInFind is true then instead cycle to the next matching element + virtual void Find( HHTMLBrowser unBrowserHandle, const char *pchSearchStr, bool bCurrentlyInFind, bool bReverse ) = 0; + // cancel a currently running find + virtual void StopFind( HHTMLBrowser unBrowserHandle ) = 0; + + // return details about the link at position x,y on the current page + virtual void GetLinkAtPosition( HHTMLBrowser unBrowserHandle, int x, int y ) = 0; + + // set a webcookie for the hostname in question + virtual void SetCookie( const char *pchHostname, const char *pchKey, const char *pchValue, const char *pchPath = "/", RTime32 nExpires = 0, bool bSecure = false, bool bHTTPOnly = false ) = 0; + + // Zoom the current page by flZoom ( from 0.0 to 2.0, so to zoom to 120% use 1.2 ), zooming around point X,Y in the page (use 0,0 if you don't care) + virtual void SetPageScaleFactor( HHTMLBrowser unBrowserHandle, float flZoom, int nPointX, int nPointY ) = 0; + + // Enable/disable low-resource background mode, where javascript and repaint timers are throttled, resources are + // more aggressively purged from memory, and audio/video elements are paused. When background mode is enabled, + // all HTML5 video and audio objects will execute ".pause()" and gain the property "._steam_background_paused = 1". + // When background mode is disabled, any video or audio objects with that property will resume with ".play()". + virtual void SetBackgroundMode( HHTMLBrowser unBrowserHandle, bool bBackgroundMode ) = 0; + + // Scale the output display space by this factor, this is useful when displaying content on high dpi devices. + // Specifies the ratio between physical and logical pixels. + virtual void SetDPIScalingFactor( HHTMLBrowser unBrowserHandle, float flDPIScaling ) = 0; + + // CALLBACKS + // + // These set of functions are used as responses to callback requests + // + + // You MUST call this in response to a HTML_StartRequest_t callback + // Set bAllowed to true to allow this navigation, false to cancel it and stay + // on the current page. You can use this feature to limit the valid pages + // allowed in your HTML surface. + virtual void AllowStartRequest( HHTMLBrowser unBrowserHandle, bool bAllowed ) = 0; + + // You MUST call this in response to a HTML_JSAlert_t or HTML_JSConfirm_t callback + // Set bResult to true for the OK option of a confirm, use false otherwise + virtual void JSDialogResponse( HHTMLBrowser unBrowserHandle, bool bResult ) = 0; + + // You MUST call this in response to a HTML_FileOpenDialog_t callback + IGNOREATTR() + virtual void FileLoadDialogResponse( HHTMLBrowser unBrowserHandle, const char **pchSelectedFiles ) = 0; +}; + +#define STEAMHTMLSURFACE_INTERFACE_VERSION "STEAMHTMLSURFACE_INTERFACE_VERSION_004" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + + +//----------------------------------------------------------------------------- +// Purpose: The browser is ready for use +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_BrowserReady_t, k_iSteamHTMLSurfaceCallbacks + 1 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // this browser is now fully created and ready to navigate to pages +END_DEFINE_CALLBACK_1() + + +//----------------------------------------------------------------------------- +// Purpose: the browser has a pending paint +//----------------------------------------------------------------------------- +DEFINE_CALLBACK(HTML_NeedsPaint_t, k_iSteamHTMLSurfaceCallbacks + 2) +CALLBACK_MEMBER(0, HHTMLBrowser, unBrowserHandle) // the browser that needs the paint +CALLBACK_MEMBER(1, const char *, pBGRA ) // a pointer to the B8G8R8A8 data for this surface, valid until SteamAPI_RunCallbacks is next called +CALLBACK_MEMBER(2, uint32, unWide) // the total width of the pBGRA texture +CALLBACK_MEMBER(3, uint32, unTall) // the total height of the pBGRA texture +CALLBACK_MEMBER(4, uint32, unUpdateX) // the offset in X for the damage rect for this update +CALLBACK_MEMBER(5, uint32, unUpdateY) // the offset in Y for the damage rect for this update +CALLBACK_MEMBER(6, uint32, unUpdateWide) // the width of the damage rect for this update +CALLBACK_MEMBER(7, uint32, unUpdateTall) // the height of the damage rect for this update +CALLBACK_MEMBER(8, uint32, unScrollX) // the page scroll the browser was at when this texture was rendered +CALLBACK_MEMBER(9, uint32, unScrollY) // the page scroll the browser was at when this texture was rendered +CALLBACK_MEMBER(10, float, flPageScale) // the page scale factor on this page when rendered +CALLBACK_MEMBER(11, uint32, unPageSerial) // incremented on each new page load, you can use this to reject draws while navigating to new pages +END_DEFINE_CALLBACK_12() + + +//----------------------------------------------------------------------------- +// Purpose: The browser wanted to navigate to a new page +// NOTE - you MUST call AllowStartRequest in response to this callback +//----------------------------------------------------------------------------- +DEFINE_CALLBACK(HTML_StartRequest_t, k_iSteamHTMLSurfaceCallbacks + 3) +CALLBACK_MEMBER(0, HHTMLBrowser, unBrowserHandle) // the handle of the surface navigating +CALLBACK_MEMBER(1, const char *, pchURL) // the url they wish to navigate to +CALLBACK_MEMBER(2, const char *, pchTarget) // the html link target type (i.e _blank, _self, _parent, _top ) +CALLBACK_MEMBER(3, const char *, pchPostData ) // any posted data for the request +CALLBACK_MEMBER(4, bool, bIsRedirect) // true if this was a http/html redirect from the last load request +END_DEFINE_CALLBACK_5() + + +//----------------------------------------------------------------------------- +// Purpose: The browser has been requested to close due to user interaction (usually from a javascript window.close() call) +//----------------------------------------------------------------------------- +DEFINE_CALLBACK(HTML_CloseBrowser_t, k_iSteamHTMLSurfaceCallbacks + 4) +CALLBACK_MEMBER(0, HHTMLBrowser, unBrowserHandle) // the handle of the surface +END_DEFINE_CALLBACK_1() + + +//----------------------------------------------------------------------------- +// Purpose: the browser is navigating to a new url +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_URLChanged_t, k_iSteamHTMLSurfaceCallbacks + 5 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface navigating +CALLBACK_MEMBER( 1, const char *, pchURL ) // the url they wish to navigate to +CALLBACK_MEMBER( 2, const char *, pchPostData ) // any posted data for the request +CALLBACK_MEMBER( 3, bool, bIsRedirect ) // true if this was a http/html redirect from the last load request +CALLBACK_MEMBER( 4, const char *, pchPageTitle ) // the title of the page +CALLBACK_MEMBER( 5, bool, bNewNavigation ) // true if this was from a fresh tab and not a click on an existing page +END_DEFINE_CALLBACK_6() + + +//----------------------------------------------------------------------------- +// Purpose: A page is finished loading +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_FinishedRequest_t, k_iSteamHTMLSurfaceCallbacks + 6 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +CALLBACK_MEMBER( 1, const char *, pchURL ) // +CALLBACK_MEMBER( 2, const char *, pchPageTitle ) // +END_DEFINE_CALLBACK_3() + + +//----------------------------------------------------------------------------- +// Purpose: a request to load this url in a new tab +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_OpenLinkInNewTab_t, k_iSteamHTMLSurfaceCallbacks + 7 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +CALLBACK_MEMBER( 1, const char *, pchURL ) // +END_DEFINE_CALLBACK_2() + + +//----------------------------------------------------------------------------- +// Purpose: the page has a new title now +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_ChangedTitle_t, k_iSteamHTMLSurfaceCallbacks + 8 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +CALLBACK_MEMBER( 1, const char *, pchTitle ) // +END_DEFINE_CALLBACK_2() + + +//----------------------------------------------------------------------------- +// Purpose: results from a search +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_SearchResults_t, k_iSteamHTMLSurfaceCallbacks + 9 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +CALLBACK_MEMBER( 1, uint32, unResults ) // +CALLBACK_MEMBER( 2, uint32, unCurrentMatch ) // +END_DEFINE_CALLBACK_3() + + +//----------------------------------------------------------------------------- +// Purpose: page history status changed on the ability to go backwards and forward +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_CanGoBackAndForward_t, k_iSteamHTMLSurfaceCallbacks + 10 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +CALLBACK_MEMBER( 1, bool, bCanGoBack ) // +CALLBACK_MEMBER( 2, bool, bCanGoForward ) // +END_DEFINE_CALLBACK_3() + + +//----------------------------------------------------------------------------- +// Purpose: details on the visibility and size of the horizontal scrollbar +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_HorizontalScroll_t, k_iSteamHTMLSurfaceCallbacks + 11 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +CALLBACK_MEMBER( 1, uint32, unScrollMax ) // +CALLBACK_MEMBER( 2, uint32, unScrollCurrent ) // +CALLBACK_MEMBER( 3, float, flPageScale ) // +CALLBACK_MEMBER( 4, bool , bVisible ) // +CALLBACK_MEMBER( 5, uint32, unPageSize ) // +END_DEFINE_CALLBACK_6() + + +//----------------------------------------------------------------------------- +// Purpose: details on the visibility and size of the vertical scrollbar +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_VerticalScroll_t, k_iSteamHTMLSurfaceCallbacks + 12 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +CALLBACK_MEMBER( 1, uint32, unScrollMax ) // +CALLBACK_MEMBER( 2, uint32, unScrollCurrent ) // +CALLBACK_MEMBER( 3, float, flPageScale ) // +CALLBACK_MEMBER( 4, bool, bVisible ) // +CALLBACK_MEMBER( 5, uint32, unPageSize ) // +END_DEFINE_CALLBACK_6() + + +//----------------------------------------------------------------------------- +// Purpose: response to GetLinkAtPosition call +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_LinkAtPosition_t, k_iSteamHTMLSurfaceCallbacks + 13 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +CALLBACK_MEMBER( 1, uint32, x ) // NOTE - Not currently set +CALLBACK_MEMBER( 2, uint32, y ) // NOTE - Not currently set +CALLBACK_MEMBER( 3, const char *, pchURL ) // +CALLBACK_MEMBER( 4, bool, bInput ) // +CALLBACK_MEMBER( 5, bool, bLiveLink ) // +END_DEFINE_CALLBACK_6() + + + +//----------------------------------------------------------------------------- +// Purpose: show a Javascript alert dialog, call JSDialogResponse +// when the user dismisses this dialog (or right away to ignore it) +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_JSAlert_t, k_iSteamHTMLSurfaceCallbacks + 14 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +CALLBACK_MEMBER( 1, const char *, pchMessage ) // +END_DEFINE_CALLBACK_2() + + +//----------------------------------------------------------------------------- +// Purpose: show a Javascript confirmation dialog, call JSDialogResponse +// when the user dismisses this dialog (or right away to ignore it) +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_JSConfirm_t, k_iSteamHTMLSurfaceCallbacks + 15 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +CALLBACK_MEMBER( 1, const char *, pchMessage ) // +END_DEFINE_CALLBACK_2() + + +//----------------------------------------------------------------------------- +// Purpose: when received show a file open dialog +// then call FileLoadDialogResponse with the file(s) the user selected. +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_FileOpenDialog_t, k_iSteamHTMLSurfaceCallbacks + 16 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +CALLBACK_MEMBER( 1, const char *, pchTitle ) // +CALLBACK_MEMBER( 2, const char *, pchInitialFile ) // +END_DEFINE_CALLBACK_3() + + +//----------------------------------------------------------------------------- +// Purpose: a new html window has been created +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_NewWindow_t, k_iSteamHTMLSurfaceCallbacks + 21 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the current surface +CALLBACK_MEMBER( 1, const char *, pchURL ) // the page to load +CALLBACK_MEMBER( 2, uint32, unX ) // the x pos into the page to display the popup +CALLBACK_MEMBER( 3, uint32, unY ) // the y pos into the page to display the popup +CALLBACK_MEMBER( 4, uint32, unWide ) // the total width of the pBGRA texture +CALLBACK_MEMBER( 5, uint32, unTall ) // the total height of the pBGRA texture +CALLBACK_MEMBER( 6, HHTMLBrowser, unNewWindow_BrowserHandle ) // the handle of the new window surface +END_DEFINE_CALLBACK_7() + + +//----------------------------------------------------------------------------- +// Purpose: change the cursor to display +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_SetCursor_t, k_iSteamHTMLSurfaceCallbacks + 22 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +CALLBACK_MEMBER( 1, uint32, eMouseCursor ) // the EMouseCursor to display +END_DEFINE_CALLBACK_2() + + +//----------------------------------------------------------------------------- +// Purpose: informational message from the browser +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_StatusText_t, k_iSteamHTMLSurfaceCallbacks + 23 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +CALLBACK_MEMBER( 1, const char *, pchMsg ) // the EMouseCursor to display +END_DEFINE_CALLBACK_2() + + +//----------------------------------------------------------------------------- +// Purpose: show a tooltip +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_ShowToolTip_t, k_iSteamHTMLSurfaceCallbacks + 24 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +CALLBACK_MEMBER( 1, const char *, pchMsg ) // the EMouseCursor to display +END_DEFINE_CALLBACK_2() + + +//----------------------------------------------------------------------------- +// Purpose: update the text of an existing tooltip +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_UpdateToolTip_t, k_iSteamHTMLSurfaceCallbacks + 25 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +CALLBACK_MEMBER( 1, const char *, pchMsg ) // the EMouseCursor to display +END_DEFINE_CALLBACK_2() + + +//----------------------------------------------------------------------------- +// Purpose: hide the tooltip you are showing +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_HideToolTip_t, k_iSteamHTMLSurfaceCallbacks + 26 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +END_DEFINE_CALLBACK_1() + + +//----------------------------------------------------------------------------- +// Purpose: The browser has restarted due to an internal failure, use this new handle value +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_BrowserRestarted_t, k_iSteamHTMLSurfaceCallbacks + 27 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // this is the new browser handle after the restart +CALLBACK_MEMBER( 1, HHTMLBrowser, unOldBrowserHandle ) // the handle for the browser before the restart, if your handle was this then switch to using unBrowserHandle for API calls +END_DEFINE_CALLBACK_2() + + +#pragma pack( pop ) + + +#endif // ISTEAMHTMLSURFACE_H diff --git a/ScreenPlayWorkshop/ThirdParty/steam/isteamhttp.h b/ScreenPlayWorkshop/ThirdParty/steam/isteamhttp.h new file mode 100644 index 00000000..8fab537d --- /dev/null +++ b/ScreenPlayWorkshop/ThirdParty/steam/isteamhttp.h @@ -0,0 +1,210 @@ +//====== Copyright © 1996-2009, Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to http client +// +//============================================================================= + +#ifndef ISTEAMHTTP_H +#define ISTEAMHTTP_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isteamclient.h" +#include "steamhttpenums.h" + +// Handle to a HTTP Request handle +typedef uint32 HTTPRequestHandle; +#define INVALID_HTTPREQUEST_HANDLE 0 + +typedef uint32 HTTPCookieContainerHandle; +#define INVALID_HTTPCOOKIE_HANDLE 0 + +//----------------------------------------------------------------------------- +// Purpose: interface to http client +//----------------------------------------------------------------------------- +class ISteamHTTP +{ +public: + + // Initializes a new HTTP request, returning a handle to use in further operations on it. Requires + // the method (GET or POST) and the absolute URL for the request. Both http and https are supported, + // so this string must start with http:// or https:// and should look like http://store.steampowered.com/app/250/ + // or such. + virtual HTTPRequestHandle CreateHTTPRequest( EHTTPMethod eHTTPRequestMethod, const char *pchAbsoluteURL ) = 0; + + // Set a context value for the request, which will be returned in the HTTPRequestCompleted_t callback after + // sending the request. This is just so the caller can easily keep track of which callbacks go with which request data. + virtual bool SetHTTPRequestContextValue( HTTPRequestHandle hRequest, uint64 ulContextValue ) = 0; + + // Set a timeout in seconds for the HTTP request, must be called prior to sending the request. Default + // timeout is 60 seconds if you don't call this. Returns false if the handle is invalid, or the request + // has already been sent. + virtual bool SetHTTPRequestNetworkActivityTimeout( HTTPRequestHandle hRequest, uint32 unTimeoutSeconds ) = 0; + + // Set a request header value for the request, must be called prior to sending the request. Will + // return false if the handle is invalid or the request is already sent. + virtual bool SetHTTPRequestHeaderValue( HTTPRequestHandle hRequest, const char *pchHeaderName, const char *pchHeaderValue ) = 0; + + // Set a GET or POST parameter value on the request, which is set will depend on the EHTTPMethod specified + // when creating the request. Must be called prior to sending the request. Will return false if the + // handle is invalid or the request is already sent. + virtual bool SetHTTPRequestGetOrPostParameter( HTTPRequestHandle hRequest, const char *pchParamName, const char *pchParamValue ) = 0; + + // Sends the HTTP request, will return false on a bad handle, otherwise use SteamCallHandle to wait on + // asynchronous response via callback. + // + // Note: If the user is in offline mode in Steam, then this will add a only-if-cached cache-control + // header and only do a local cache lookup rather than sending any actual remote request. + virtual bool SendHTTPRequest( HTTPRequestHandle hRequest, SteamAPICall_t *pCallHandle ) = 0; + + // Sends the HTTP request, will return false on a bad handle, otherwise use SteamCallHandle to wait on + // asynchronous response via callback for completion, and listen for HTTPRequestHeadersReceived_t and + // HTTPRequestDataReceived_t callbacks while streaming. + virtual bool SendHTTPRequestAndStreamResponse( HTTPRequestHandle hRequest, SteamAPICall_t *pCallHandle ) = 0; + + // Defers a request you have sent, the actual HTTP client code may have many requests queued, and this will move + // the specified request to the tail of the queue. Returns false on invalid handle, or if the request is not yet sent. + virtual bool DeferHTTPRequest( HTTPRequestHandle hRequest ) = 0; + + // Prioritizes a request you have sent, the actual HTTP client code may have many requests queued, and this will move + // the specified request to the head of the queue. Returns false on invalid handle, or if the request is not yet sent. + virtual bool PrioritizeHTTPRequest( HTTPRequestHandle hRequest ) = 0; + + // Checks if a response header is present in a HTTP response given a handle from HTTPRequestCompleted_t, also + // returns the size of the header value if present so the caller and allocate a correctly sized buffer for + // GetHTTPResponseHeaderValue. + virtual bool GetHTTPResponseHeaderSize( HTTPRequestHandle hRequest, const char *pchHeaderName, uint32 *unResponseHeaderSize ) = 0; + + // Gets header values from a HTTP response given a handle from HTTPRequestCompleted_t, will return false if the + // header is not present or if your buffer is too small to contain it's value. You should first call + // BGetHTTPResponseHeaderSize to check for the presence of the header and to find out the size buffer needed. + virtual bool GetHTTPResponseHeaderValue( HTTPRequestHandle hRequest, const char *pchHeaderName, uint8 *pHeaderValueBuffer, uint32 unBufferSize ) = 0; + + // Gets the size of the body data from a HTTP response given a handle from HTTPRequestCompleted_t, will return false if the + // handle is invalid. + virtual bool GetHTTPResponseBodySize( HTTPRequestHandle hRequest, uint32 *unBodySize ) = 0; + + // Gets the body data from a HTTP response given a handle from HTTPRequestCompleted_t, will return false if the + // handle is invalid or is to a streaming response, or if the provided buffer is not the correct size. Use BGetHTTPResponseBodySize first to find out + // the correct buffer size to use. + virtual bool GetHTTPResponseBodyData( HTTPRequestHandle hRequest, uint8 *pBodyDataBuffer, uint32 unBufferSize ) = 0; + + // Gets the body data from a streaming HTTP response given a handle from HTTPRequestDataReceived_t. Will return false if the + // handle is invalid or is to a non-streaming response (meaning it wasn't sent with SendHTTPRequestAndStreamResponse), or if the buffer size and offset + // do not match the size and offset sent in HTTPRequestDataReceived_t. + virtual bool GetHTTPStreamingResponseBodyData( HTTPRequestHandle hRequest, uint32 cOffset, uint8 *pBodyDataBuffer, uint32 unBufferSize ) = 0; + + // Releases an HTTP response handle, should always be called to free resources after receiving a HTTPRequestCompleted_t + // callback and finishing using the response. + virtual bool ReleaseHTTPRequest( HTTPRequestHandle hRequest ) = 0; + + // Gets progress on downloading the body for the request. This will be zero unless a response header has already been + // received which included a content-length field. For responses that contain no content-length it will report + // zero for the duration of the request as the size is unknown until the connection closes. + virtual bool GetHTTPDownloadProgressPct( HTTPRequestHandle hRequest, float *pflPercentOut ) = 0; + + // Sets the body for an HTTP Post request. Will fail and return false on a GET request, and will fail if POST params + // have already been set for the request. Setting this raw body makes it the only contents for the post, the pchContentType + // parameter will set the content-type header for the request so the server may know how to interpret the body. + virtual bool SetHTTPRequestRawPostBody( HTTPRequestHandle hRequest, const char *pchContentType, uint8 *pubBody, uint32 unBodyLen ) = 0; + + // Creates a cookie container handle which you must later free with ReleaseCookieContainer(). If bAllowResponsesToModify=true + // than any response to your requests using this cookie container may add new cookies which may be transmitted with + // future requests. If bAllowResponsesToModify=false than only cookies you explicitly set will be sent. This API is just for + // during process lifetime, after steam restarts no cookies are persisted and you have no way to access the cookie container across + // repeat executions of your process. + virtual HTTPCookieContainerHandle CreateCookieContainer( bool bAllowResponsesToModify ) = 0; + + // Release a cookie container you are finished using, freeing it's memory + virtual bool ReleaseCookieContainer( HTTPCookieContainerHandle hCookieContainer ) = 0; + + // Adds a cookie to the specified cookie container that will be used with future requests. + virtual bool SetCookie( HTTPCookieContainerHandle hCookieContainer, const char *pchHost, const char *pchUrl, const char *pchCookie ) = 0; + + // Set the cookie container to use for a HTTP request + virtual bool SetHTTPRequestCookieContainer( HTTPRequestHandle hRequest, HTTPCookieContainerHandle hCookieContainer ) = 0; + + // Set the extra user agent info for a request, this doesn't clobber the normal user agent, it just adds the extra info on the end + virtual bool SetHTTPRequestUserAgentInfo( HTTPRequestHandle hRequest, const char *pchUserAgentInfo ) = 0; + + // Set that https request should require verified SSL certificate via machines certificate trust store + virtual bool SetHTTPRequestRequiresVerifiedCertificate( HTTPRequestHandle hRequest, bool bRequireVerifiedCertificate ) = 0; + + // Set an absolute timeout on the HTTP request, this is just a total time timeout different than the network activity timeout + // which can bump everytime we get more data + virtual bool SetHTTPRequestAbsoluteTimeoutMS( HTTPRequestHandle hRequest, uint32 unMilliseconds ) = 0; + + // Check if the reason the request failed was because we timed it out (rather than some harder failure) + virtual bool GetHTTPRequestWasTimedOut( HTTPRequestHandle hRequest, bool *pbWasTimedOut ) = 0; +}; + +#define STEAMHTTP_INTERFACE_VERSION "STEAMHTTP_INTERFACE_VERSION002" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + +struct HTTPRequestCompleted_t +{ + enum { k_iCallback = k_iClientHTTPCallbacks + 1 }; + + // Handle value for the request that has completed. + HTTPRequestHandle m_hRequest; + + // Context value that the user defined on the request that this callback is associated with, 0 if + // no context value was set. + uint64 m_ulContextValue; + + // This will be true if we actually got any sort of response from the server (even an error). + // It will be false if we failed due to an internal error or client side network failure. + bool m_bRequestSuccessful; + + // Will be the HTTP status code value returned by the server, k_EHTTPStatusCode200OK is the normal + // OK response, if you get something else you probably need to treat it as a failure. + EHTTPStatusCode m_eStatusCode; + + uint32 m_unBodySize; // Same as GetHTTPResponseBodySize() +}; + + +struct HTTPRequestHeadersReceived_t +{ + enum { k_iCallback = k_iClientHTTPCallbacks + 2 }; + + // Handle value for the request that has received headers. + HTTPRequestHandle m_hRequest; + + // Context value that the user defined on the request that this callback is associated with, 0 if + // no context value was set. + uint64 m_ulContextValue; +}; + +struct HTTPRequestDataReceived_t +{ + enum { k_iCallback = k_iClientHTTPCallbacks + 3 }; + + // Handle value for the request that has received data. + HTTPRequestHandle m_hRequest; + + // Context value that the user defined on the request that this callback is associated with, 0 if + // no context value was set. + uint64 m_ulContextValue; + + + // Offset to provide to GetHTTPStreamingResponseBodyData to get this chunk of data + uint32 m_cOffset; + + // Size to provide to GetHTTPStreamingResponseBodyData to get this chunk of data + uint32 m_cBytesReceived; +}; + + +#pragma pack( pop ) + +#endif // ISTEAMHTTP_H \ No newline at end of file diff --git a/ScreenPlayWorkshop/ThirdParty/steam/isteaminventory.h b/ScreenPlayWorkshop/ThirdParty/steam/isteaminventory.h new file mode 100644 index 00000000..85090a2f --- /dev/null +++ b/ScreenPlayWorkshop/ThirdParty/steam/isteaminventory.h @@ -0,0 +1,429 @@ +//====== Copyright © 1996-2014 Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to Steam Inventory +// +//============================================================================= + +#ifndef ISTEAMINVENTORY_H +#define ISTEAMINVENTORY_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isteamclient.h" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + + +// Every individual instance of an item has a globally-unique ItemInstanceID. +// This ID is unique to the combination of (player, specific item instance) +// and will not be transferred to another player or re-used for another item. +typedef uint64 SteamItemInstanceID_t; + +static const SteamItemInstanceID_t k_SteamItemInstanceIDInvalid = (SteamItemInstanceID_t)~0; + +// Types of items in your game are identified by a 32-bit "item definition number". +// Valid definition numbers are between 1 and 999999999; numbers less than or equal to +// zero are invalid, and numbers greater than or equal to one billion (1x10^9) are +// reserved for internal Steam use. +typedef int32 SteamItemDef_t; + + +enum ESteamItemFlags +{ + // Item status flags - these flags are permanently attached to specific item instances + k_ESteamItemNoTrade = 1 << 0, // This item is account-locked and cannot be traded or given away. + + // Action confirmation flags - these flags are set one time only, as part of a result set + k_ESteamItemRemoved = 1 << 8, // The item has been destroyed, traded away, expired, or otherwise invalidated + k_ESteamItemConsumed = 1 << 9, // The item quantity has been decreased by 1 via ConsumeItem API. + + // All other flag bits are currently reserved for internal Steam use at this time. + // Do not assume anything about the state of other flags which are not defined here. +}; + +struct SteamItemDetails_t +{ + SteamItemInstanceID_t m_itemId; + SteamItemDef_t m_iDefinition; + uint16 m_unQuantity; + uint16 m_unFlags; // see ESteamItemFlags +}; + +typedef int32 SteamInventoryResult_t; + +static const SteamInventoryResult_t k_SteamInventoryResultInvalid = -1; + +typedef uint64 SteamInventoryUpdateHandle_t; +const SteamInventoryUpdateHandle_t k_SteamInventoryUpdateHandleInvalid = 0xffffffffffffffffull; + +//----------------------------------------------------------------------------- +// Purpose: Steam Inventory query and manipulation API +//----------------------------------------------------------------------------- +class ISteamInventory +{ +public: + + // INVENTORY ASYNC RESULT MANAGEMENT + // + // Asynchronous inventory queries always output a result handle which can be used with + // GetResultStatus, GetResultItems, etc. A SteamInventoryResultReady_t callback will + // be triggered when the asynchronous result becomes ready (or fails). + // + + // Find out the status of an asynchronous inventory result handle. Possible values: + // k_EResultPending - still in progress + // k_EResultOK - done, result ready + // k_EResultExpired - done, result ready, maybe out of date (see DeserializeResult) + // k_EResultInvalidParam - ERROR: invalid API call parameters + // k_EResultServiceUnavailable - ERROR: service temporarily down, you may retry later + // k_EResultLimitExceeded - ERROR: operation would exceed per-user inventory limits + // k_EResultFail - ERROR: unknown / generic error + METHOD_DESC(Find out the status of an asynchronous inventory result handle.) + virtual EResult GetResultStatus( SteamInventoryResult_t resultHandle ) = 0; + + // Copies the contents of a result set into a flat array. The specific + // contents of the result set depend on which query which was used. + METHOD_DESC(Copies the contents of a result set into a flat array. The specific contents of the result set depend on which query which was used.) + virtual bool GetResultItems( SteamInventoryResult_t resultHandle, + OUT_ARRAY_COUNT( punOutItemsArraySize,Output array) SteamItemDetails_t *pOutItemsArray, + uint32 *punOutItemsArraySize ) = 0; + + // In combination with GetResultItems, you can use GetResultItemProperty to retrieve + // dynamic string properties for a given item returned in the result set. + // + // Property names are always composed of ASCII letters, numbers, and/or underscores. + // + // Pass a NULL pointer for pchPropertyName to get a comma - separated list of available + // property names. + // + // If pchValueBuffer is NULL, *punValueBufferSize will contain the + // suggested buffer size. Otherwise it will be the number of bytes actually copied + // to pchValueBuffer. If the results do not fit in the given buffer, partial + // results may be copied. + virtual bool GetResultItemProperty( SteamInventoryResult_t resultHandle, + uint32 unItemIndex, + const char *pchPropertyName, + OUT_STRING_COUNT( punValueBufferSizeOut ) char *pchValueBuffer, uint32 *punValueBufferSizeOut ) = 0; + + // Returns the server time at which the result was generated. Compare against + // the value of IClientUtils::GetServerRealTime() to determine age. + METHOD_DESC(Returns the server time at which the result was generated. Compare against the value of IClientUtils::GetServerRealTime() to determine age.) + virtual uint32 GetResultTimestamp( SteamInventoryResult_t resultHandle ) = 0; + + // Returns true if the result belongs to the target steam ID, false if the + // result does not. This is important when using DeserializeResult, to verify + // that a remote player is not pretending to have a different user's inventory. + METHOD_DESC(Returns true if the result belongs to the target steam ID or false if the result does not. This is important when using DeserializeResult to verify that a remote player is not pretending to have a different users inventory.) + virtual bool CheckResultSteamID( SteamInventoryResult_t resultHandle, CSteamID steamIDExpected ) = 0; + + // Destroys a result handle and frees all associated memory. + METHOD_DESC(Destroys a result handle and frees all associated memory.) + virtual void DestroyResult( SteamInventoryResult_t resultHandle ) = 0; + + + // INVENTORY ASYNC QUERY + // + + // Captures the entire state of the current user's Steam inventory. + // You must call DestroyResult on this handle when you are done with it. + // Returns false and sets *pResultHandle to zero if inventory is unavailable. + // Note: calls to this function are subject to rate limits and may return + // cached results if called too frequently. It is suggested that you call + // this function only when you are about to display the user's full inventory, + // or if you expect that the inventory may have changed. + METHOD_DESC(Captures the entire state of the current users Steam inventory.) + virtual bool GetAllItems( SteamInventoryResult_t *pResultHandle ) = 0; + + + // Captures the state of a subset of the current user's Steam inventory, + // identified by an array of item instance IDs. The results from this call + // can be serialized and passed to other players to "prove" that the current + // user owns specific items, without exposing the user's entire inventory. + // For example, you could call GetItemsByID with the IDs of the user's + // currently equipped cosmetic items and serialize this to a buffer, and + // then transmit this buffer to other players upon joining a game. + METHOD_DESC(Captures the state of a subset of the current users Steam inventory identified by an array of item instance IDs.) + virtual bool GetItemsByID( SteamInventoryResult_t *pResultHandle, ARRAY_COUNT( unCountInstanceIDs ) const SteamItemInstanceID_t *pInstanceIDs, uint32 unCountInstanceIDs ) = 0; + + + // RESULT SERIALIZATION AND AUTHENTICATION + // + // Serialized result sets contain a short signature which can't be forged + // or replayed across different game sessions. A result set can be serialized + // on the local client, transmitted to other players via your game networking, + // and deserialized by the remote players. This is a secure way of preventing + // hackers from lying about posessing rare/high-value items. + + // Serializes a result set with signature bytes to an output buffer. Pass + // NULL as an output buffer to get the required size via punOutBufferSize. + // The size of a serialized result depends on the number items which are being + // serialized. When securely transmitting items to other players, it is + // recommended to use "GetItemsByID" first to create a minimal result set. + // Results have a built-in timestamp which will be considered "expired" after + // an hour has elapsed. See DeserializeResult for expiration handling. + virtual bool SerializeResult( SteamInventoryResult_t resultHandle, OUT_BUFFER_COUNT(punOutBufferSize) void *pOutBuffer, uint32 *punOutBufferSize ) = 0; + + // Deserializes a result set and verifies the signature bytes. Returns false + // if bRequireFullOnlineVerify is set but Steam is running in Offline mode. + // Otherwise returns true and then delivers error codes via GetResultStatus. + // + // The bRESERVED_MUST_BE_FALSE flag is reserved for future use and should not + // be set to true by your game at this time. + // + // DeserializeResult has a potential soft-failure mode where the handle status + // is set to k_EResultExpired. GetResultItems() still succeeds in this mode. + // The "expired" result could indicate that the data may be out of date - not + // just due to timed expiration (one hour), but also because one of the items + // in the result set may have been traded or consumed since the result set was + // generated. You could compare the timestamp from GetResultTimestamp() to + // ISteamUtils::GetServerRealTime() to determine how old the data is. You could + // simply ignore the "expired" result code and continue as normal, or you + // could challenge the player with expired data to send an updated result set. + virtual bool DeserializeResult( SteamInventoryResult_t *pOutResultHandle, BUFFER_COUNT(punOutBufferSize) const void *pBuffer, uint32 unBufferSize, bool bRESERVED_MUST_BE_FALSE = false ) = 0; + + + // INVENTORY ASYNC MODIFICATION + // + + // GenerateItems() creates one or more items and then generates a SteamInventoryCallback_t + // notification with a matching nCallbackContext parameter. This API is only intended + // for prototyping - it is only usable by Steam accounts that belong to the publisher group + // for your game. + // If punArrayQuantity is not NULL, it should be the same length as pArrayItems and should + // describe the quantity of each item to generate. + virtual bool GenerateItems( SteamInventoryResult_t *pResultHandle, ARRAY_COUNT(unArrayLength) const SteamItemDef_t *pArrayItemDefs, ARRAY_COUNT(unArrayLength) const uint32 *punArrayQuantity, uint32 unArrayLength ) = 0; + + // GrantPromoItems() checks the list of promotional items for which the user may be eligible + // and grants the items (one time only). On success, the result set will include items which + // were granted, if any. If no items were granted because the user isn't eligible for any + // promotions, this is still considered a success. + METHOD_DESC(GrantPromoItems() checks the list of promotional items for which the user may be eligible and grants the items (one time only).) + virtual bool GrantPromoItems( SteamInventoryResult_t *pResultHandle ) = 0; + + // AddPromoItem() / AddPromoItems() are restricted versions of GrantPromoItems(). Instead of + // scanning for all eligible promotional items, the check is restricted to a single item + // definition or set of item definitions. This can be useful if your game has custom UI for + // showing a specific promo item to the user. + virtual bool AddPromoItem( SteamInventoryResult_t *pResultHandle, SteamItemDef_t itemDef ) = 0; + virtual bool AddPromoItems( SteamInventoryResult_t *pResultHandle, ARRAY_COUNT(unArrayLength) const SteamItemDef_t *pArrayItemDefs, uint32 unArrayLength ) = 0; + + // ConsumeItem() removes items from the inventory, permanently. They cannot be recovered. + // Not for the faint of heart - if your game implements item removal at all, a high-friction + // UI confirmation process is highly recommended. + METHOD_DESC(ConsumeItem() removes items from the inventory permanently.) + virtual bool ConsumeItem( SteamInventoryResult_t *pResultHandle, SteamItemInstanceID_t itemConsume, uint32 unQuantity ) = 0; + + // ExchangeItems() is an atomic combination of item generation and consumption. + // It can be used to implement crafting recipes or transmutations, or items which unpack + // themselves into other items (e.g., a chest). + // Exchange recipes are defined in the ItemDef, and explicitly list the required item + // types and resulting generated type. + // Exchange recipes are evaluated atomically by the Inventory Service; if the supplied + // components do not match the recipe, or do not contain sufficient quantity, the + // exchange will fail. + virtual bool ExchangeItems( SteamInventoryResult_t *pResultHandle, + ARRAY_COUNT(unArrayGenerateLength) const SteamItemDef_t *pArrayGenerate, ARRAY_COUNT(unArrayGenerateLength) const uint32 *punArrayGenerateQuantity, uint32 unArrayGenerateLength, + ARRAY_COUNT(unArrayDestroyLength) const SteamItemInstanceID_t *pArrayDestroy, ARRAY_COUNT(unArrayDestroyLength) const uint32 *punArrayDestroyQuantity, uint32 unArrayDestroyLength ) = 0; + + + // TransferItemQuantity() is intended for use with items which are "stackable" (can have + // quantity greater than one). It can be used to split a stack into two, or to transfer + // quantity from one stack into another stack of identical items. To split one stack into + // two, pass k_SteamItemInstanceIDInvalid for itemIdDest and a new item will be generated. + virtual bool TransferItemQuantity( SteamInventoryResult_t *pResultHandle, SteamItemInstanceID_t itemIdSource, uint32 unQuantity, SteamItemInstanceID_t itemIdDest ) = 0; + + + // TIMED DROPS AND PLAYTIME CREDIT + // + + // Deprecated. Calling this method is not required for proper playtime accounting. + METHOD_DESC( Deprecated method. Playtime accounting is performed on the Steam servers. ) + virtual void SendItemDropHeartbeat() = 0; + + // Playtime credit must be consumed and turned into item drops by your game. Only item + // definitions which are marked as "playtime item generators" can be spawned. The call + // will return an empty result set if there is not enough playtime credit for a drop. + // Your game should call TriggerItemDrop at an appropriate time for the user to receive + // new items, such as between rounds or while the player is dead. Note that players who + // hack their clients could modify the value of "dropListDefinition", so do not use it + // to directly control rarity. + // See your Steamworks configuration to set playtime drop rates for individual itemdefs. + // The client library will suppress too-frequent calls to this method. + METHOD_DESC(Playtime credit must be consumed and turned into item drops by your game.) + virtual bool TriggerItemDrop( SteamInventoryResult_t *pResultHandle, SteamItemDef_t dropListDefinition ) = 0; + + + // Deprecated. This method is not supported. + virtual bool TradeItems( SteamInventoryResult_t *pResultHandle, CSteamID steamIDTradePartner, + ARRAY_COUNT(nArrayGiveLength) const SteamItemInstanceID_t *pArrayGive, ARRAY_COUNT(nArrayGiveLength) const uint32 *pArrayGiveQuantity, uint32 nArrayGiveLength, + ARRAY_COUNT(nArrayGetLength) const SteamItemInstanceID_t *pArrayGet, ARRAY_COUNT(nArrayGetLength) const uint32 *pArrayGetQuantity, uint32 nArrayGetLength ) = 0; + + + // ITEM DEFINITIONS + // + // Item definitions are a mapping of "definition IDs" (integers between 1 and 1000000) + // to a set of string properties. Some of these properties are required to display items + // on the Steam community web site. Other properties can be defined by applications. + // Use of these functions is optional; there is no reason to call LoadItemDefinitions + // if your game hardcodes the numeric definition IDs (eg, purple face mask = 20, blue + // weapon mod = 55) and does not allow for adding new item types without a client patch. + // + + // LoadItemDefinitions triggers the automatic load and refresh of item definitions. + // Every time new item definitions are available (eg, from the dynamic addition of new + // item types while players are still in-game), a SteamInventoryDefinitionUpdate_t + // callback will be fired. + METHOD_DESC(LoadItemDefinitions triggers the automatic load and refresh of item definitions.) + virtual bool LoadItemDefinitions() = 0; + + // GetItemDefinitionIDs returns the set of all defined item definition IDs (which are + // defined via Steamworks configuration, and not necessarily contiguous integers). + // If pItemDefIDs is null, the call will return true and *punItemDefIDsArraySize will + // contain the total size necessary for a subsequent call. Otherwise, the call will + // return false if and only if there is not enough space in the output array. + virtual bool GetItemDefinitionIDs( + OUT_ARRAY_COUNT(punItemDefIDsArraySize,List of item definition IDs) SteamItemDef_t *pItemDefIDs, + DESC(Size of array is passed in and actual size used is returned in this param) uint32 *punItemDefIDsArraySize ) = 0; + + // GetItemDefinitionProperty returns a string property from a given item definition. + // Note that some properties (for example, "name") may be localized and will depend + // on the current Steam language settings (see ISteamApps::GetCurrentGameLanguage). + // Property names are always composed of ASCII letters, numbers, and/or underscores. + // Pass a NULL pointer for pchPropertyName to get a comma - separated list of available + // property names. If pchValueBuffer is NULL, *punValueBufferSize will contain the + // suggested buffer size. Otherwise it will be the number of bytes actually copied + // to pchValueBuffer. If the results do not fit in the given buffer, partial + // results may be copied. + virtual bool GetItemDefinitionProperty( SteamItemDef_t iDefinition, const char *pchPropertyName, + OUT_STRING_COUNT(punValueBufferSizeOut) char *pchValueBuffer, uint32 *punValueBufferSizeOut ) = 0; + + // 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. + // An example usage of this is an item that becomes available every week. + CALL_RESULT( SteamInventoryEligiblePromoItemDefIDs_t ) + virtual SteamAPICall_t RequestEligiblePromoItemDefinitionsIDs( CSteamID steamID ) = 0; + + // After handling a SteamInventoryEligiblePromoItemDefIDs_t call result, use this + // function to pull out the list of item definition ids that the user can be + // manually granted via the AddPromoItems() call. + virtual bool GetEligiblePromoItemDefinitionIDs( + CSteamID steamID, + OUT_ARRAY_COUNT(punItemDefIDsArraySize,List of item definition IDs) SteamItemDef_t *pItemDefIDs, + DESC(Size of array is passed in and actual size used is returned in this param) uint32 *punItemDefIDsArraySize ) = 0; + + // Starts the purchase process for the given item definitions. The callback SteamInventoryStartPurchaseResult_t + // will be posted if Steam was able to initialize the transaction. + // + // Once the purchase has been authorized and completed by the user, the callback SteamInventoryResultReady_t + // will be posted. + CALL_RESULT( SteamInventoryStartPurchaseResult_t ) + virtual SteamAPICall_t StartPurchase( ARRAY_COUNT(unArrayLength) const SteamItemDef_t *pArrayItemDefs, ARRAY_COUNT(unArrayLength) const uint32 *punArrayQuantity, uint32 unArrayLength ) = 0; + + // Request current prices for all applicable item definitions + CALL_RESULT( SteamInventoryRequestPricesResult_t ) + virtual SteamAPICall_t RequestPrices() = 0; + + // Returns the number of items with prices. Need to call RequestPrices() first. + virtual uint32 GetNumItemsWithPrices() = 0; + + // Returns item definition ids and their prices in the user's local currency. + // Need to call RequestPrices() first. + virtual bool GetItemsWithPrices( ARRAY_COUNT(unArrayLength) OUT_ARRAY_COUNT(pArrayItemDefs, Items with prices) SteamItemDef_t *pArrayItemDefs, + ARRAY_COUNT(unArrayLength) OUT_ARRAY_COUNT(pPrices, List of prices for the given item defs) uint64 *pPrices, + uint32 unArrayLength ) = 0; + + // Retrieves the price for the item definition id + // Returns false if there is no price stored for the item definition. + virtual bool GetItemPrice( SteamItemDef_t iDefinition, uint64 *pPrice ) = 0; + + // Create a request to update properties on items + virtual SteamInventoryUpdateHandle_t StartUpdateProperties() = 0; + // Remove the property on the item + virtual bool RemoveProperty( SteamInventoryUpdateHandle_t handle, SteamItemInstanceID_t nItemID, const char *pchPropertyName ) = 0; + // Accessor methods to set properties on items + virtual bool SetProperty( SteamInventoryUpdateHandle_t handle, SteamItemInstanceID_t nItemID, const char *pchPropertyName, const char *pchPropertyValue ) = 0; + virtual bool SetProperty( SteamInventoryUpdateHandle_t handle, SteamItemInstanceID_t nItemID, const char *pchPropertyName, bool bValue ) = 0; + virtual bool SetProperty( SteamInventoryUpdateHandle_t handle, SteamItemInstanceID_t nItemID, const char *pchPropertyName, int64 nValue ) = 0; + virtual bool SetProperty( SteamInventoryUpdateHandle_t handle, SteamItemInstanceID_t nItemID, const char *pchPropertyName, float flValue ) = 0; + // Submit the update request by handle + virtual bool SubmitUpdateProperties( SteamInventoryUpdateHandle_t handle, SteamInventoryResult_t * pResultHandle ) = 0; + +}; + +#define STEAMINVENTORY_INTERFACE_VERSION "STEAMINVENTORY_INTERFACE_V002" + + +// SteamInventoryResultReady_t callbacks are fired whenever asynchronous +// results transition from "Pending" to "OK" or an error state. There will +// always be exactly one callback per handle. +struct SteamInventoryResultReady_t +{ + enum { k_iCallback = k_iClientInventoryCallbacks + 0 }; + SteamInventoryResult_t m_handle; + EResult m_result; +}; + + +// SteamInventoryFullUpdate_t callbacks are triggered when GetAllItems +// successfully returns a result which is newer / fresher than the last +// known result. (It will not trigger if the inventory hasn't changed, +// or if results from two overlapping calls are reversed in flight and +// the earlier result is already known to be stale/out-of-date.) +// The normal ResultReady callback will still be triggered immediately +// afterwards; this is an additional notification for your convenience. +struct SteamInventoryFullUpdate_t +{ + enum { k_iCallback = k_iClientInventoryCallbacks + 1 }; + SteamInventoryResult_t m_handle; +}; + + +// A SteamInventoryDefinitionUpdate_t callback is triggered whenever +// item definitions have been updated, which could be in response to +// LoadItemDefinitions() or any other async request which required +// a definition update in order to process results from the server. +struct SteamInventoryDefinitionUpdate_t +{ + enum { k_iCallback = k_iClientInventoryCallbacks + 2 }; +}; + +// Returned +struct SteamInventoryEligiblePromoItemDefIDs_t +{ + enum { k_iCallback = k_iClientInventoryCallbacks + 3 }; + EResult m_result; + CSteamID m_steamID; + int m_numEligiblePromoItemDefs; + bool m_bCachedData; // indicates that the data was retrieved from the cache and not the server +}; + +// Triggered from StartPurchase call +struct SteamInventoryStartPurchaseResult_t +{ + enum { k_iCallback = k_iClientInventoryCallbacks + 4 }; + EResult m_result; + uint64 m_ulOrderID; + uint64 m_ulTransID; +}; + + +// Triggered from RequestPrices +struct SteamInventoryRequestPricesResult_t +{ + enum { k_iCallback = k_iClientInventoryCallbacks + 5 }; + EResult m_result; + char m_rgchCurrency[4]; +}; + +#pragma pack( pop ) + + +#endif // ISTEAMCONTROLLER_H diff --git a/ScreenPlayWorkshop/ThirdParty/steam/isteammasterserverupdater.h b/ScreenPlayWorkshop/ThirdParty/steam/isteammasterserverupdater.h new file mode 100644 index 00000000..4be0ca5c --- /dev/null +++ b/ScreenPlayWorkshop/ThirdParty/steam/isteammasterserverupdater.h @@ -0,0 +1 @@ +#error "This file isn't used any more" diff --git a/ScreenPlayWorkshop/ThirdParty/steam/isteammatchmaking.h b/ScreenPlayWorkshop/ThirdParty/steam/isteammatchmaking.h new file mode 100644 index 00000000..837d98bd --- /dev/null +++ b/ScreenPlayWorkshop/ThirdParty/steam/isteammatchmaking.h @@ -0,0 +1,751 @@ +//====== Copyright © 1996-2008, Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to steam managing game server/client match making +// +//============================================================================= + +#ifndef ISTEAMMATCHMAKING +#define ISTEAMMATCHMAKING +#ifdef _WIN32 +#pragma once +#endif + +#include "steamtypes.h" +#include "steamclientpublic.h" +#include "matchmakingtypes.h" +#include "isteamclient.h" +#include "isteamfriends.h" + +// lobby type description +enum ELobbyType +{ + k_ELobbyTypePrivate = 0, // only way to join the lobby is to invite to someone else + k_ELobbyTypeFriendsOnly = 1, // shows for friends or invitees, but not in lobby list + k_ELobbyTypePublic = 2, // visible for friends and in lobby list + k_ELobbyTypeInvisible = 3, // returned by search, but not visible to other friends + // useful if you want a user in two lobbies, for example matching groups together + // a user can be in only one regular lobby, and up to two invisible lobbies +}; + +// lobby search filter tools +enum ELobbyComparison +{ + k_ELobbyComparisonEqualToOrLessThan = -2, + k_ELobbyComparisonLessThan = -1, + k_ELobbyComparisonEqual = 0, + k_ELobbyComparisonGreaterThan = 1, + k_ELobbyComparisonEqualToOrGreaterThan = 2, + k_ELobbyComparisonNotEqual = 3, +}; + +// lobby search distance. Lobby results are sorted from closest to farthest. +enum ELobbyDistanceFilter +{ + k_ELobbyDistanceFilterClose, // only lobbies in the same immediate region will be returned + k_ELobbyDistanceFilterDefault, // only lobbies in the same region or near by regions + k_ELobbyDistanceFilterFar, // for games that don't have many latency requirements, will return lobbies about half-way around the globe + k_ELobbyDistanceFilterWorldwide, // no filtering, will match lobbies as far as India to NY (not recommended, expect multiple seconds of latency between the clients) +}; + +// maximum number of characters a lobby metadata key can be +#define k_nMaxLobbyKeyLength 255 + +//----------------------------------------------------------------------------- +// Purpose: Functions for match making services for clients to get to favorites +// and to operate on game lobbies. +//----------------------------------------------------------------------------- +class ISteamMatchmaking +{ +public: + // game server favorites storage + // saves basic details about a multiplayer game server locally + + // returns the number of favorites servers the user has stored + virtual int GetFavoriteGameCount() = 0; + + // returns the details of the game server + // iGame is of range [0,GetFavoriteGameCount()) + // *pnIP, *pnConnPort are filled in the with IP:port of the game server + // *punFlags specify whether the game server was stored as an explicit favorite or in the history of connections + // *pRTime32LastPlayedOnServer is filled in the with the Unix time the favorite was added + virtual bool GetFavoriteGame( int iGame, AppId_t *pnAppID, uint32 *pnIP, uint16 *pnConnPort, uint16 *pnQueryPort, uint32 *punFlags, uint32 *pRTime32LastPlayedOnServer ) = 0; + + // adds the game server to the local list; updates the time played of the server if it already exists in the list + virtual int AddFavoriteGame( AppId_t nAppID, uint32 nIP, uint16 nConnPort, uint16 nQueryPort, uint32 unFlags, uint32 rTime32LastPlayedOnServer ) = 0; + + // removes the game server from the local storage; returns true if one was removed + virtual bool RemoveFavoriteGame( AppId_t nAppID, uint32 nIP, uint16 nConnPort, uint16 nQueryPort, uint32 unFlags ) = 0; + + /////// + // Game lobby functions + + // Get a list of relevant lobbies + // this is an asynchronous request + // results will be returned by LobbyMatchList_t callback & call result, with the number of lobbies found + // this will never return lobbies that are full + // to add more filter, the filter calls below need to be call before each and every RequestLobbyList() call + // use the CCallResult<> object in steam_api.h to match the SteamAPICall_t call result to a function in an object, e.g. + /* + class CMyLobbyListManager + { + CCallResult m_CallResultLobbyMatchList; + void FindLobbies() + { + // SteamMatchmaking()->AddRequestLobbyListFilter*() functions would be called here, before RequestLobbyList() + SteamAPICall_t hSteamAPICall = SteamMatchmaking()->RequestLobbyList(); + m_CallResultLobbyMatchList.Set( hSteamAPICall, this, &CMyLobbyListManager::OnLobbyMatchList ); + } + + void OnLobbyMatchList( LobbyMatchList_t *pLobbyMatchList, bool bIOFailure ) + { + // lobby list has be retrieved from Steam back-end, use results + } + } + */ + // + CALL_RESULT( LobbyMatchList_t ) + virtual SteamAPICall_t RequestLobbyList() = 0; + // filters for lobbies + // this needs to be called before RequestLobbyList() to take effect + // these are cleared on each call to RequestLobbyList() + virtual void AddRequestLobbyListStringFilter( const char *pchKeyToMatch, const char *pchValueToMatch, ELobbyComparison eComparisonType ) = 0; + // numerical comparison + virtual void AddRequestLobbyListNumericalFilter( const char *pchKeyToMatch, int nValueToMatch, ELobbyComparison eComparisonType ) = 0; + // returns results closest to the specified value. Multiple near filters can be added, with early filters taking precedence + virtual void AddRequestLobbyListNearValueFilter( const char *pchKeyToMatch, int nValueToBeCloseTo ) = 0; + // returns only lobbies with the specified number of slots available + virtual void AddRequestLobbyListFilterSlotsAvailable( int nSlotsAvailable ) = 0; + // sets the distance for which we should search for lobbies (based on users IP address to location map on the Steam backed) + virtual void AddRequestLobbyListDistanceFilter( ELobbyDistanceFilter eLobbyDistanceFilter ) = 0; + // sets how many results to return, the lower the count the faster it is to download the lobby results & details to the client + virtual void AddRequestLobbyListResultCountFilter( int cMaxResults ) = 0; + + virtual void AddRequestLobbyListCompatibleMembersFilter( CSteamID steamIDLobby ) = 0; + + // returns the CSteamID of a lobby, as retrieved by a RequestLobbyList call + // should only be called after a LobbyMatchList_t callback is received + // iLobby is of the range [0, LobbyMatchList_t::m_nLobbiesMatching) + // the returned CSteamID::IsValid() will be false if iLobby is out of range + virtual CSteamID GetLobbyByIndex( int iLobby ) = 0; + + // Create a lobby on the Steam servers. + // If private, then the lobby will not be returned by any RequestLobbyList() call; the CSteamID + // of the lobby will need to be communicated via game channels or via InviteUserToLobby() + // this is an asynchronous request + // results will be returned by LobbyCreated_t callback and call result; lobby is joined & ready to use at this point + // a LobbyEnter_t callback will also be received (since the local user is joining their own lobby) + CALL_RESULT( LobbyCreated_t ) + virtual SteamAPICall_t CreateLobby( ELobbyType eLobbyType, int cMaxMembers ) = 0; + + // Joins an existing lobby + // this is an asynchronous request + // results will be returned by LobbyEnter_t callback & call result, check m_EChatRoomEnterResponse to see if was successful + // lobby metadata is available to use immediately on this call completing + CALL_RESULT( LobbyEnter_t ) + virtual SteamAPICall_t JoinLobby( CSteamID steamIDLobby ) = 0; + + // Leave a lobby; this will take effect immediately on the client side + // other users in the lobby will be notified by a LobbyChatUpdate_t callback + virtual void LeaveLobby( CSteamID steamIDLobby ) = 0; + + // Invite another user to the lobby + // the target user will receive a LobbyInvite_t callback + // will return true if the invite is successfully sent, whether or not the target responds + // returns false if the local user is not connected to the Steam servers + // if the other user clicks the join link, a GameLobbyJoinRequested_t will be posted if the user is in-game, + // or if the game isn't running yet the game will be launched with the parameter +connect_lobby <64-bit lobby id> + virtual bool InviteUserToLobby( CSteamID steamIDLobby, CSteamID steamIDInvitee ) = 0; + + // Lobby iteration, for viewing details of users in a lobby + // only accessible if the lobby user is a member of the specified lobby + // persona information for other lobby members (name, avatar, etc.) will be asynchronously received + // and accessible via ISteamFriends interface + + // returns the number of users in the specified lobby + virtual int GetNumLobbyMembers( CSteamID steamIDLobby ) = 0; + // returns the CSteamID of a user in the lobby + // iMember is of range [0,GetNumLobbyMembers()) + // note that the current user must be in a lobby to retrieve CSteamIDs of other users in that lobby + virtual CSteamID GetLobbyMemberByIndex( CSteamID steamIDLobby, int iMember ) = 0; + + // Get data associated with this lobby + // takes a simple key, and returns the string associated with it + // "" will be returned if no value is set, or if steamIDLobby is invalid + virtual const char *GetLobbyData( CSteamID steamIDLobby, const char *pchKey ) = 0; + // Sets a key/value pair in the lobby metadata + // each user in the lobby will be broadcast this new value, and any new users joining will receive any existing data + // this can be used to set lobby names, map, etc. + // to reset a key, just set it to "" + // other users in the lobby will receive notification of the lobby data change via a LobbyDataUpdate_t callback + virtual bool SetLobbyData( CSteamID steamIDLobby, const char *pchKey, const char *pchValue ) = 0; + + // returns the number of metadata keys set on the specified lobby + virtual int GetLobbyDataCount( CSteamID steamIDLobby ) = 0; + + // returns a lobby metadata key/values pair by index, of range [0, GetLobbyDataCount()) + virtual bool GetLobbyDataByIndex( CSteamID steamIDLobby, int iLobbyData, char *pchKey, int cchKeyBufferSize, char *pchValue, int cchValueBufferSize ) = 0; + + // removes a metadata key from the lobby + virtual bool DeleteLobbyData( CSteamID steamIDLobby, const char *pchKey ) = 0; + + // Gets per-user metadata for someone in this lobby + virtual const char *GetLobbyMemberData( CSteamID steamIDLobby, CSteamID steamIDUser, const char *pchKey ) = 0; + // Sets per-user metadata (for the local user implicitly) + virtual void SetLobbyMemberData( CSteamID steamIDLobby, const char *pchKey, const char *pchValue ) = 0; + + // Broadcasts a chat message to the all the users in the lobby + // users in the lobby (including the local user) will receive a LobbyChatMsg_t callback + // returns true if the message is successfully sent + // pvMsgBody can be binary or text data, up to 4k + // if pvMsgBody is text, cubMsgBody should be strlen( text ) + 1, to include the null terminator + virtual bool SendLobbyChatMsg( CSteamID steamIDLobby, const void *pvMsgBody, int cubMsgBody ) = 0; + // Get a chat message as specified in a LobbyChatMsg_t callback + // iChatID is the LobbyChatMsg_t::m_iChatID value in the callback + // *pSteamIDUser is filled in with the CSteamID of the member + // *pvData is filled in with the message itself + // return value is the number of bytes written into the buffer + virtual int GetLobbyChatEntry( CSteamID steamIDLobby, int iChatID, OUT_STRUCT() CSteamID *pSteamIDUser, void *pvData, int cubData, EChatEntryType *peChatEntryType ) = 0; + + // Refreshes metadata for a lobby you're not necessarily in right now + // you never do this for lobbies you're a member of, only if your + // this will send down all the metadata associated with a lobby + // this is an asynchronous call + // returns false if the local user is not connected to the Steam servers + // results will be returned by a LobbyDataUpdate_t callback + // if the specified lobby doesn't exist, LobbyDataUpdate_t::m_bSuccess will be set to false + virtual bool RequestLobbyData( CSteamID steamIDLobby ) = 0; + + // sets the game server associated with the lobby + // usually at this point, the users will join the specified game server + // either the IP/Port or the steamID of the game server has to be valid, depending on how you want the clients to be able to connect + virtual void SetLobbyGameServer( CSteamID steamIDLobby, uint32 unGameServerIP, uint16 unGameServerPort, CSteamID steamIDGameServer ) = 0; + // returns the details of a game server set in a lobby - returns false if there is no game server set, or that lobby doesn't exist + virtual bool GetLobbyGameServer( CSteamID steamIDLobby, uint32 *punGameServerIP, uint16 *punGameServerPort, OUT_STRUCT() CSteamID *psteamIDGameServer ) = 0; + + // set the limit on the # of users who can join the lobby + virtual bool SetLobbyMemberLimit( CSteamID steamIDLobby, int cMaxMembers ) = 0; + // returns the current limit on the # of users who can join the lobby; returns 0 if no limit is defined + virtual int GetLobbyMemberLimit( CSteamID steamIDLobby ) = 0; + + // updates which type of lobby it is + // only lobbies that are k_ELobbyTypePublic or k_ELobbyTypeInvisible, and are set to joinable, will be returned by RequestLobbyList() calls + virtual bool SetLobbyType( CSteamID steamIDLobby, ELobbyType eLobbyType ) = 0; + + // sets whether or not a lobby is joinable - defaults to true for a new lobby + // if set to false, no user can join, even if they are a friend or have been invited + virtual bool SetLobbyJoinable( CSteamID steamIDLobby, bool bLobbyJoinable ) = 0; + + // returns the current lobby owner + // you must be a member of the lobby to access this + // there always one lobby owner - if the current owner leaves, another user will become the owner + // it is possible (bur rare) to join a lobby just as the owner is leaving, thus entering a lobby with self as the owner + virtual CSteamID GetLobbyOwner( CSteamID steamIDLobby ) = 0; + + // changes who the lobby owner is + // you must be the lobby owner for this to succeed, and steamIDNewOwner must be in the lobby + // after completion, the local user will no longer be the owner + virtual bool SetLobbyOwner( CSteamID steamIDLobby, CSteamID steamIDNewOwner ) = 0; + + // link two lobbies for the purposes of checking player compatibility + // you must be the lobby owner of both lobbies + virtual bool SetLinkedLobby( CSteamID steamIDLobby, CSteamID steamIDLobbyDependent ) = 0; + +#ifdef _PS3 + // changes who the lobby owner is + // you must be the lobby owner for this to succeed, and steamIDNewOwner must be in the lobby + // after completion, the local user will no longer be the owner + virtual void CheckForPSNGameBootInvite( unsigned int iGameBootAttributes ) = 0; +#endif + CALL_BACK( LobbyChatUpdate_t ) +}; +#define STEAMMATCHMAKING_INTERFACE_VERSION "SteamMatchMaking009" + + +//----------------------------------------------------------------------------- +// Callback interfaces for server list functions (see ISteamMatchmakingServers below) +// +// The idea here is that your game code implements objects that implement these +// interfaces to receive callback notifications after calling asynchronous functions +// inside the ISteamMatchmakingServers() interface below. +// +// This is different than normal Steam callback handling due to the potentially +// large size of server lists. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Typedef for handle type you will receive when requesting server list. +//----------------------------------------------------------------------------- +typedef void* HServerListRequest; + +//----------------------------------------------------------------------------- +// Purpose: Callback interface for receiving responses after a server list refresh +// or an individual server update. +// +// Since you get these callbacks after requesting full list refreshes you will +// usually implement this interface inside an object like CServerBrowser. If that +// object is getting destructed you should use ISteamMatchMakingServers()->CancelQuery() +// to cancel any in-progress queries so you don't get a callback into the destructed +// object and crash. +//----------------------------------------------------------------------------- +class ISteamMatchmakingServerListResponse +{ +public: + // Server has responded ok with updated data + virtual void ServerResponded( HServerListRequest hRequest, int iServer ) = 0; + + // Server has failed to respond + virtual void ServerFailedToRespond( HServerListRequest hRequest, int iServer ) = 0; + + // A list refresh you had initiated is now 100% completed + virtual void RefreshComplete( HServerListRequest hRequest, EMatchMakingServerResponse response ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Callback interface for receiving responses after pinging an individual server +// +// These callbacks all occur in response to querying an individual server +// via the ISteamMatchmakingServers()->PingServer() call below. If you are +// destructing an object that implements this interface then you should call +// ISteamMatchmakingServers()->CancelServerQuery() passing in the handle to the query +// which is in progress. Failure to cancel in progress queries when destructing +// a callback handler may result in a crash when a callback later occurs. +//----------------------------------------------------------------------------- +class ISteamMatchmakingPingResponse +{ +public: + // Server has responded successfully and has updated data + virtual void ServerResponded( gameserveritem_t &server ) = 0; + + // Server failed to respond to the ping request + virtual void ServerFailedToRespond() = 0; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Callback interface for receiving responses after requesting details on +// who is playing on a particular server. +// +// These callbacks all occur in response to querying an individual server +// via the ISteamMatchmakingServers()->PlayerDetails() call below. If you are +// destructing an object that implements this interface then you should call +// ISteamMatchmakingServers()->CancelServerQuery() passing in the handle to the query +// which is in progress. Failure to cancel in progress queries when destructing +// a callback handler may result in a crash when a callback later occurs. +//----------------------------------------------------------------------------- +class ISteamMatchmakingPlayersResponse +{ +public: + // Got data on a new player on the server -- you'll get this callback once per player + // on the server which you have requested player data on. + virtual void AddPlayerToList( const char *pchName, int nScore, float flTimePlayed ) = 0; + + // The server failed to respond to the request for player details + virtual void PlayersFailedToRespond() = 0; + + // The server has finished responding to the player details request + // (ie, you won't get anymore AddPlayerToList callbacks) + virtual void PlayersRefreshComplete() = 0; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Callback interface for receiving responses after requesting rules +// details on a particular server. +// +// These callbacks all occur in response to querying an individual server +// via the ISteamMatchmakingServers()->ServerRules() call below. If you are +// destructing an object that implements this interface then you should call +// ISteamMatchmakingServers()->CancelServerQuery() passing in the handle to the query +// which is in progress. Failure to cancel in progress queries when destructing +// a callback handler may result in a crash when a callback later occurs. +//----------------------------------------------------------------------------- +class ISteamMatchmakingRulesResponse +{ +public: + // Got data on a rule on the server -- you'll get one of these per rule defined on + // the server you are querying + virtual void RulesResponded( const char *pchRule, const char *pchValue ) = 0; + + // The server failed to respond to the request for rule details + virtual void RulesFailedToRespond() = 0; + + // The server has finished responding to the rule details request + // (ie, you won't get anymore RulesResponded callbacks) + virtual void RulesRefreshComplete() = 0; +}; + + +//----------------------------------------------------------------------------- +// Typedef for handle type you will receive when querying details on an individual server. +//----------------------------------------------------------------------------- +typedef int HServerQuery; +const int HSERVERQUERY_INVALID = 0xffffffff; + +//----------------------------------------------------------------------------- +// Purpose: Functions for match making services for clients to get to game lists and details +//----------------------------------------------------------------------------- +class ISteamMatchmakingServers +{ +public: + // Request a new list of servers of a particular type. These calls each correspond to one of the EMatchMakingType values. + // Each call allocates a new asynchronous request object. + // Request object must be released by calling ReleaseRequest( hServerListRequest ) + virtual HServerListRequest RequestInternetServerList( AppId_t iApp, ARRAY_COUNT(nFilters) MatchMakingKeyValuePair_t **ppchFilters, uint32 nFilters, ISteamMatchmakingServerListResponse *pRequestServersResponse ) = 0; + virtual HServerListRequest RequestLANServerList( AppId_t iApp, ISteamMatchmakingServerListResponse *pRequestServersResponse ) = 0; + virtual HServerListRequest RequestFriendsServerList( AppId_t iApp, ARRAY_COUNT(nFilters) MatchMakingKeyValuePair_t **ppchFilters, uint32 nFilters, ISteamMatchmakingServerListResponse *pRequestServersResponse ) = 0; + virtual HServerListRequest RequestFavoritesServerList( AppId_t iApp, ARRAY_COUNT(nFilters) MatchMakingKeyValuePair_t **ppchFilters, uint32 nFilters, ISteamMatchmakingServerListResponse *pRequestServersResponse ) = 0; + virtual HServerListRequest RequestHistoryServerList( AppId_t iApp, ARRAY_COUNT(nFilters) MatchMakingKeyValuePair_t **ppchFilters, uint32 nFilters, ISteamMatchmakingServerListResponse *pRequestServersResponse ) = 0; + virtual HServerListRequest RequestSpectatorServerList( AppId_t iApp, ARRAY_COUNT(nFilters) MatchMakingKeyValuePair_t **ppchFilters, uint32 nFilters, ISteamMatchmakingServerListResponse *pRequestServersResponse ) = 0; + + // Releases the asynchronous request object and cancels any pending query on it if there's a pending query in progress. + // RefreshComplete callback is not posted when request is released. + virtual void ReleaseRequest( HServerListRequest hServerListRequest ) = 0; + + /* the filter operation codes that go in the key part of MatchMakingKeyValuePair_t should be one of these: + + "map" + - Server passes the filter if the server is playing the specified map. + "gamedataand" + - Server passes the filter if the server's game data (ISteamGameServer::SetGameData) contains all of the + specified strings. The value field is a comma-delimited list of strings to match. + "gamedataor" + - Server passes the filter if the server's game data (ISteamGameServer::SetGameData) contains at least one of the + specified strings. The value field is a comma-delimited list of strings to match. + "gamedatanor" + - Server passes the filter if the server's game data (ISteamGameServer::SetGameData) does not contain any + of the specified strings. The value field is a comma-delimited list of strings to check. + "gametagsand" + - Server passes the filter if the server's game tags (ISteamGameServer::SetGameTags) contains all + of the specified strings. The value field is a comma-delimited list of strings to check. + "gametagsnor" + - Server passes the filter if the server's game tags (ISteamGameServer::SetGameTags) does not contain any + of the specified strings. The value field is a comma-delimited list of strings to check. + "and" (x1 && x2 && ... && xn) + "or" (x1 || x2 || ... || xn) + "nand" !(x1 && x2 && ... && xn) + "nor" !(x1 || x2 || ... || xn) + - Performs Boolean operation on the following filters. The operand to this filter specifies + the "size" of the Boolean inputs to the operation, in Key/value pairs. (The keyvalue + pairs must immediately follow, i.e. this is a prefix logical operator notation.) + In the simplest case where Boolean expressions are not nested, this is simply + the number of operands. + + For example, to match servers on a particular map or with a particular tag, would would + use these filters. + + ( server.map == "cp_dustbowl" || server.gametags.contains("payload") ) + "or", "2" + "map", "cp_dustbowl" + "gametagsand", "payload" + + If logical inputs are nested, then the operand specifies the size of the entire + "length" of its operands, not the number of immediate children. + + ( server.map == "cp_dustbowl" || ( server.gametags.contains("payload") && !server.gametags.contains("payloadrace") ) ) + "or", "4" + "map", "cp_dustbowl" + "and", "2" + "gametagsand", "payload" + "gametagsnor", "payloadrace" + + Unary NOT can be achieved using either "nand" or "nor" with a single operand. + + "addr" + - Server passes the filter if the server's query address matches the specified IP or IP:port. + "gameaddr" + - Server passes the filter if the server's game address matches the specified IP or IP:port. + + The following filter operations ignore the "value" part of MatchMakingKeyValuePair_t + + "dedicated" + - Server passes the filter if it passed true to SetDedicatedServer. + "secure" + - Server passes the filter if the server is VAC-enabled. + "notfull" + - Server passes the filter if the player count is less than the reported max player count. + "hasplayers" + - Server passes the filter if the player count is greater than zero. + "noplayers" + - Server passes the filter if it doesn't have any players. + "linux" + - Server passes the filter if it's a linux server + */ + + // Get details on a given server in the list, you can get the valid range of index + // values by calling GetServerCount(). You will also receive index values in + // ISteamMatchmakingServerListResponse::ServerResponded() callbacks + virtual gameserveritem_t *GetServerDetails( HServerListRequest hRequest, int iServer ) = 0; + + // Cancel an request which is operation on the given list type. You should call this to cancel + // any in-progress requests before destructing a callback object that may have been passed + // to one of the above list request calls. Not doing so may result in a crash when a callback + // occurs on the destructed object. + // Canceling a query does not release the allocated request handle. + // The request handle must be released using ReleaseRequest( hRequest ) + virtual void CancelQuery( HServerListRequest hRequest ) = 0; + + // Ping every server in your list again but don't update the list of servers + // Query callback installed when the server list was requested will be used + // again to post notifications and RefreshComplete, so the callback must remain + // valid until another RefreshComplete is called on it or the request + // is released with ReleaseRequest( hRequest ) + virtual void RefreshQuery( HServerListRequest hRequest ) = 0; + + // Returns true if the list is currently refreshing its server list + virtual bool IsRefreshing( HServerListRequest hRequest ) = 0; + + // How many servers in the given list, GetServerDetails above takes 0... GetServerCount() - 1 + virtual int GetServerCount( HServerListRequest hRequest ) = 0; + + // Refresh a single server inside of a query (rather than all the servers ) + virtual void RefreshServer( HServerListRequest hRequest, int iServer ) = 0; + + + //----------------------------------------------------------------------------- + // Queries to individual servers directly via IP/Port + //----------------------------------------------------------------------------- + + // Request updated ping time and other details from a single server + virtual HServerQuery PingServer( uint32 unIP, uint16 usPort, ISteamMatchmakingPingResponse *pRequestServersResponse ) = 0; + + // Request the list of players currently playing on a server + virtual HServerQuery PlayerDetails( uint32 unIP, uint16 usPort, ISteamMatchmakingPlayersResponse *pRequestServersResponse ) = 0; + + // Request the list of rules that the server is running (See ISteamGameServer::SetKeyValue() to set the rules server side) + virtual HServerQuery ServerRules( uint32 unIP, uint16 usPort, ISteamMatchmakingRulesResponse *pRequestServersResponse ) = 0; + + // Cancel an outstanding Ping/Players/Rules query from above. You should call this to cancel + // any in-progress requests before destructing a callback object that may have been passed + // to one of the above calls to avoid crashing when callbacks occur. + virtual void CancelServerQuery( HServerQuery hServerQuery ) = 0; +}; +#define STEAMMATCHMAKINGSERVERS_INTERFACE_VERSION "SteamMatchMakingServers002" + +// game server flags +const uint32 k_unFavoriteFlagNone = 0x00; +const uint32 k_unFavoriteFlagFavorite = 0x01; // this game favorite entry is for the favorites list +const uint32 k_unFavoriteFlagHistory = 0x02; // this game favorite entry is for the history list + + +//----------------------------------------------------------------------------- +// Purpose: Used in ChatInfo messages - fields specific to a chat member - must fit in a uint32 +//----------------------------------------------------------------------------- +enum EChatMemberStateChange +{ + // Specific to joining / leaving the chatroom + k_EChatMemberStateChangeEntered = 0x0001, // This user has joined or is joining the chat room + k_EChatMemberStateChangeLeft = 0x0002, // This user has left or is leaving the chat room + k_EChatMemberStateChangeDisconnected = 0x0004, // User disconnected without leaving the chat first + k_EChatMemberStateChangeKicked = 0x0008, // User kicked + k_EChatMemberStateChangeBanned = 0x0010, // User kicked and banned +}; + +// returns true of the flags indicate that a user has been removed from the chat +#define BChatMemberStateChangeRemoved( rgfChatMemberStateChangeFlags ) ( rgfChatMemberStateChangeFlags & ( k_EChatMemberStateChangeDisconnected | k_EChatMemberStateChangeLeft | k_EChatMemberStateChangeKicked | k_EChatMemberStateChangeBanned ) ) + + +//----------------------------------------------------------------------------- +// Callbacks for ISteamMatchmaking (which go through the regular Steam callback registration system) +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + +//----------------------------------------------------------------------------- +// Purpose: a server was added/removed from the favorites list, you should refresh now +//----------------------------------------------------------------------------- +struct FavoritesListChanged_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 2 }; + uint32 m_nIP; // an IP of 0 means reload the whole list, any other value means just one server + uint32 m_nQueryPort; + uint32 m_nConnPort; + uint32 m_nAppID; + uint32 m_nFlags; + bool m_bAdd; // true if this is adding the entry, otherwise it is a remove + AccountID_t m_unAccountId; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Someone has invited you to join a Lobby +// normally you don't need to do anything with this, since +// the Steam UI will also display a ' has invited you to the lobby, join?' dialog +// +// if the user outside a game chooses to join, your game will be launched with the parameter "+connect_lobby <64-bit lobby id>", +// or with the callback GameLobbyJoinRequested_t if they're already in-game +//----------------------------------------------------------------------------- +struct LobbyInvite_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 3 }; + + uint64 m_ulSteamIDUser; // Steam ID of the person making the invite + uint64 m_ulSteamIDLobby; // Steam ID of the Lobby + uint64 m_ulGameID; // GameID of the Lobby +}; + + +//----------------------------------------------------------------------------- +// Purpose: Sent on entering a lobby, or on failing to enter +// m_EChatRoomEnterResponse will be set to k_EChatRoomEnterResponseSuccess on success, +// or a higher value on failure (see enum EChatRoomEnterResponse) +//----------------------------------------------------------------------------- +struct LobbyEnter_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 4 }; + + uint64 m_ulSteamIDLobby; // SteamID of the Lobby you have entered + uint32 m_rgfChatPermissions; // Permissions of the current user + bool m_bLocked; // If true, then only invited users may join + uint32 m_EChatRoomEnterResponse; // EChatRoomEnterResponse +}; + + +//----------------------------------------------------------------------------- +// Purpose: The lobby metadata has changed +// if m_ulSteamIDMember is the steamID of a lobby member, use GetLobbyMemberData() to access per-user details +// if m_ulSteamIDMember == m_ulSteamIDLobby, use GetLobbyData() to access lobby metadata +//----------------------------------------------------------------------------- +struct LobbyDataUpdate_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 5 }; + + uint64 m_ulSteamIDLobby; // steamID of the Lobby + uint64 m_ulSteamIDMember; // steamID of the member whose data changed, or the room itself + uint8 m_bSuccess; // true if we lobby data was successfully changed; + // will only be false if RequestLobbyData() was called on a lobby that no longer exists +}; + + +//----------------------------------------------------------------------------- +// Purpose: The lobby chat room state has changed +// this is usually sent when a user has joined or left the lobby +//----------------------------------------------------------------------------- +struct LobbyChatUpdate_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 6 }; + + uint64 m_ulSteamIDLobby; // Lobby ID + uint64 m_ulSteamIDUserChanged; // user who's status in the lobby just changed - can be recipient + uint64 m_ulSteamIDMakingChange; // Chat member who made the change (different from SteamIDUserChange if kicking, muting, etc.) + // for example, if one user kicks another from the lobby, this will be set to the id of the user who initiated the kick + uint32 m_rgfChatMemberStateChange; // bitfield of EChatMemberStateChange values +}; + + +//----------------------------------------------------------------------------- +// Purpose: A chat message for this lobby has been sent +// use GetLobbyChatEntry( m_iChatID ) to retrieve the contents of this message +//----------------------------------------------------------------------------- +struct LobbyChatMsg_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 7 }; + + uint64 m_ulSteamIDLobby; // the lobby id this is in + uint64 m_ulSteamIDUser; // steamID of the user who has sent this message + uint8 m_eChatEntryType; // type of message + uint32 m_iChatID; // index of the chat entry to lookup +}; + + +//----------------------------------------------------------------------------- +// Purpose: A game created a game for all the members of the lobby to join, +// as triggered by a SetLobbyGameServer() +// it's up to the individual clients to take action on this; the usual +// game behavior is to leave the lobby and connect to the specified game server +//----------------------------------------------------------------------------- +struct LobbyGameCreated_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 9 }; + + uint64 m_ulSteamIDLobby; // the lobby we were in + uint64 m_ulSteamIDGameServer; // the new game server that has been created or found for the lobby members + uint32 m_unIP; // IP & Port of the game server (if any) + uint16 m_usPort; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Number of matching lobbies found +// iterate the returned lobbies with GetLobbyByIndex(), from values 0 to m_nLobbiesMatching-1 +//----------------------------------------------------------------------------- +struct LobbyMatchList_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 10 }; + uint32 m_nLobbiesMatching; // Number of lobbies that matched search criteria and we have SteamIDs for +}; + + +//----------------------------------------------------------------------------- +// Purpose: posted if a user is forcefully removed from a lobby +// can occur if a user loses connection to Steam +//----------------------------------------------------------------------------- +struct LobbyKicked_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 12 }; + uint64 m_ulSteamIDLobby; // Lobby + uint64 m_ulSteamIDAdmin; // User who kicked you - possibly the ID of the lobby itself + uint8 m_bKickedDueToDisconnect; // true if you were kicked from the lobby due to the user losing connection to Steam (currently always true) +}; + + +//----------------------------------------------------------------------------- +// Purpose: Result of our request to create a Lobby +// m_eResult == k_EResultOK on success +// at this point, the lobby has been joined and is ready for use +// a LobbyEnter_t callback will also be received (since the local user is joining their own lobby) +//----------------------------------------------------------------------------- +struct LobbyCreated_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 13 }; + + EResult m_eResult; // k_EResultOK - the lobby was successfully created + // k_EResultNoConnection - your Steam client doesn't have a connection to the back-end + // k_EResultTimeout - you the message to the Steam servers, but it didn't respond + // k_EResultFail - the server responded, but with an unknown internal error + // k_EResultAccessDenied - your game isn't set to allow lobbies, or your client does haven't rights to play the game + // k_EResultLimitExceeded - your game client has created too many lobbies + + uint64 m_ulSteamIDLobby; // chat room, zero if failed +}; + +// used by now obsolete RequestFriendsLobbiesResponse_t +// enum { k_iCallback = k_iSteamMatchmakingCallbacks + 14 }; + + +//----------------------------------------------------------------------------- +// Purpose: Result of CheckForPSNGameBootInvite +// m_eResult == k_EResultOK on success +// at this point, the local user may not have finishing joining this lobby; +// game code should wait until the subsequent LobbyEnter_t callback is received +//----------------------------------------------------------------------------- +struct PSNGameBootInviteResult_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 15 }; + + bool m_bGameBootInviteExists; + CSteamID m_steamIDLobby; // Should be valid if m_bGameBootInviteExists == true +}; + + +//----------------------------------------------------------------------------- +// Purpose: Result of our request to create a Lobby +// m_eResult == k_EResultOK on success +// at this point, the lobby has been joined and is ready for use +// a LobbyEnter_t callback will also be received (since the local user is joining their own lobby) +//----------------------------------------------------------------------------- +struct FavoritesListAccountsUpdated_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 16 }; + + EResult m_eResult; +}; + +#pragma pack( pop ) + + +#endif // ISTEAMMATCHMAKING diff --git a/ScreenPlayWorkshop/ThirdParty/steam/isteammusic.h b/ScreenPlayWorkshop/ThirdParty/steam/isteammusic.h new file mode 100644 index 00000000..779a4c2e --- /dev/null +++ b/ScreenPlayWorkshop/ThirdParty/steam/isteammusic.h @@ -0,0 +1,67 @@ +//============ Copyright (c) Valve Corporation, All rights reserved. ============ + +#ifndef ISTEAMMUSIC_H +#define ISTEAMMUSIC_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isteamclient.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +enum AudioPlayback_Status +{ + AudioPlayback_Undefined = 0, + AudioPlayback_Playing = 1, + AudioPlayback_Paused = 2, + AudioPlayback_Idle = 3 +}; + + +//----------------------------------------------------------------------------- +// Purpose: Functions to control music playback in the steam client +//----------------------------------------------------------------------------- +class ISteamMusic +{ +public: + virtual bool BIsEnabled() = 0; + virtual bool BIsPlaying() = 0; + + virtual AudioPlayback_Status GetPlaybackStatus() = 0; + + virtual void Play() = 0; + virtual void Pause() = 0; + virtual void PlayPrevious() = 0; + virtual void PlayNext() = 0; + + // volume is between 0.0 and 1.0 + virtual void SetVolume( float flVolume ) = 0; + virtual float GetVolume() = 0; + +}; + +#define STEAMMUSIC_INTERFACE_VERSION "STEAMMUSIC_INTERFACE_VERSION001" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + + +DEFINE_CALLBACK( PlaybackStatusHasChanged_t, k_iSteamMusicCallbacks + 1 ) +END_DEFINE_CALLBACK_0() + +DEFINE_CALLBACK( VolumeHasChanged_t, k_iSteamMusicCallbacks + 2 ) + CALLBACK_MEMBER( 0, float, m_flNewVolume ) +END_DEFINE_CALLBACK_1() + +#pragma pack( pop ) + + +#endif // #define ISTEAMMUSIC_H diff --git a/ScreenPlayWorkshop/ThirdParty/steam/isteammusicremote.h b/ScreenPlayWorkshop/ThirdParty/steam/isteammusicremote.h new file mode 100644 index 00000000..ea29a7de --- /dev/null +++ b/ScreenPlayWorkshop/ThirdParty/steam/isteammusicremote.h @@ -0,0 +1,129 @@ +//============ Copyright (c) Valve Corporation, All rights reserved. ============ + +#ifndef ISTEAMMUSICREMOTE_H +#define ISTEAMMUSICREMOTE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isteamclient.h" +#include "isteammusic.h" + +#define k_SteamMusicNameMaxLength 255 +#define k_SteamMusicPNGMaxLength 65535 + + +class ISteamMusicRemote +{ +public: + // Service Definition + virtual bool RegisterSteamMusicRemote( const char *pchName ) = 0; + virtual bool DeregisterSteamMusicRemote() = 0; + virtual bool BIsCurrentMusicRemote() = 0; + virtual bool BActivationSuccess( bool bValue ) = 0; + + virtual bool SetDisplayName( const char *pchDisplayName ) = 0; + virtual bool SetPNGIcon_64x64( void *pvBuffer, uint32 cbBufferLength ) = 0; + + // Abilities for the user interface + virtual bool EnablePlayPrevious(bool bValue) = 0; + virtual bool EnablePlayNext( bool bValue ) = 0; + virtual bool EnableShuffled( bool bValue ) = 0; + virtual bool EnableLooped( bool bValue ) = 0; + virtual bool EnableQueue( bool bValue ) = 0; + virtual bool EnablePlaylists( bool bValue ) = 0; + + // Status + virtual bool UpdatePlaybackStatus( AudioPlayback_Status nStatus ) = 0; + virtual bool UpdateShuffled( bool bValue ) = 0; + virtual bool UpdateLooped( bool bValue ) = 0; + virtual bool UpdateVolume( float flValue ) = 0; // volume is between 0.0 and 1.0 + + // Current Entry + virtual bool CurrentEntryWillChange() = 0; + virtual bool CurrentEntryIsAvailable( bool bAvailable ) = 0; + virtual bool UpdateCurrentEntryText( const char *pchText ) = 0; + virtual bool UpdateCurrentEntryElapsedSeconds( int nValue ) = 0; + virtual bool UpdateCurrentEntryCoverArt( void *pvBuffer, uint32 cbBufferLength ) = 0; + virtual bool CurrentEntryDidChange() = 0; + + // Queue + virtual bool QueueWillChange() = 0; + virtual bool ResetQueueEntries() = 0; + virtual bool SetQueueEntry( int nID, int nPosition, const char *pchEntryText ) = 0; + virtual bool SetCurrentQueueEntry( int nID ) = 0; + virtual bool QueueDidChange() = 0; + + // Playlist + virtual bool PlaylistWillChange() = 0; + virtual bool ResetPlaylistEntries() = 0; + virtual bool SetPlaylistEntry( int nID, int nPosition, const char *pchEntryText ) = 0; + virtual bool SetCurrentPlaylistEntry( int nID ) = 0; + virtual bool PlaylistDidChange() = 0; +}; + +#define STEAMMUSICREMOTE_INTERFACE_VERSION "STEAMMUSICREMOTE_INTERFACE_VERSION001" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + + +DEFINE_CALLBACK( MusicPlayerRemoteWillActivate_t, k_iSteamMusicRemoteCallbacks + 1) +END_DEFINE_CALLBACK_0() + +DEFINE_CALLBACK( MusicPlayerRemoteWillDeactivate_t, k_iSteamMusicRemoteCallbacks + 2 ) +END_DEFINE_CALLBACK_0() + +DEFINE_CALLBACK( MusicPlayerRemoteToFront_t, k_iSteamMusicRemoteCallbacks + 3 ) +END_DEFINE_CALLBACK_0() + +DEFINE_CALLBACK( MusicPlayerWillQuit_t, k_iSteamMusicRemoteCallbacks + 4 ) +END_DEFINE_CALLBACK_0() + +DEFINE_CALLBACK( MusicPlayerWantsPlay_t, k_iSteamMusicRemoteCallbacks + 5 ) +END_DEFINE_CALLBACK_0() + +DEFINE_CALLBACK( MusicPlayerWantsPause_t, k_iSteamMusicRemoteCallbacks + 6 ) +END_DEFINE_CALLBACK_0() + +DEFINE_CALLBACK( MusicPlayerWantsPlayPrevious_t, k_iSteamMusicRemoteCallbacks + 7 ) +END_DEFINE_CALLBACK_0() + +DEFINE_CALLBACK( MusicPlayerWantsPlayNext_t, k_iSteamMusicRemoteCallbacks + 8 ) +END_DEFINE_CALLBACK_0() + +DEFINE_CALLBACK( MusicPlayerWantsShuffled_t, k_iSteamMusicRemoteCallbacks + 9 ) + CALLBACK_MEMBER( 0, bool, m_bShuffled ) +END_DEFINE_CALLBACK_1() + +DEFINE_CALLBACK( MusicPlayerWantsLooped_t, k_iSteamMusicRemoteCallbacks + 10 ) + CALLBACK_MEMBER(0, bool, m_bLooped ) +END_DEFINE_CALLBACK_1() + +DEFINE_CALLBACK( MusicPlayerWantsVolume_t, k_iSteamMusicCallbacks + 11 ) + CALLBACK_MEMBER(0, float, m_flNewVolume) +END_DEFINE_CALLBACK_1() + +DEFINE_CALLBACK( MusicPlayerSelectsQueueEntry_t, k_iSteamMusicCallbacks + 12 ) + CALLBACK_MEMBER(0, int, nID ) +END_DEFINE_CALLBACK_1() + +DEFINE_CALLBACK( MusicPlayerSelectsPlaylistEntry_t, k_iSteamMusicCallbacks + 13 ) + CALLBACK_MEMBER(0, int, nID ) +END_DEFINE_CALLBACK_1() + +DEFINE_CALLBACK( MusicPlayerWantsPlayingRepeatStatus_t, k_iSteamMusicRemoteCallbacks + 14 ) + CALLBACK_MEMBER(0, int, m_nPlayingRepeatStatus ) +END_DEFINE_CALLBACK_1() + +#pragma pack( pop ) + + + +#endif // #define ISTEAMMUSICREMOTE_H diff --git a/ScreenPlayWorkshop/ThirdParty/steam/isteamnetworking.h b/ScreenPlayWorkshop/ThirdParty/steam/isteamnetworking.h new file mode 100644 index 00000000..8f70819d --- /dev/null +++ b/ScreenPlayWorkshop/ThirdParty/steam/isteamnetworking.h @@ -0,0 +1,306 @@ +//====== Copyright © 1996-2008, Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to steam managing network connections between game clients & servers +// +//============================================================================= + +#ifndef ISTEAMNETWORKING +#define ISTEAMNETWORKING +#ifdef _WIN32 +#pragma once +#endif + +#include "steamtypes.h" +#include "steamclientpublic.h" + + +// list of possible errors returned by SendP2PPacket() API +// these will be posted in the P2PSessionConnectFail_t callback +enum EP2PSessionError +{ + k_EP2PSessionErrorNone = 0, + k_EP2PSessionErrorNotRunningApp = 1, // target is not running the same game + k_EP2PSessionErrorNoRightsToApp = 2, // local user doesn't own the app that is running + k_EP2PSessionErrorDestinationNotLoggedIn = 3, // target user isn't connected to Steam + k_EP2PSessionErrorTimeout = 4, // target isn't responding, perhaps not calling AcceptP2PSessionWithUser() + // corporate firewalls can also block this (NAT traversal is not firewall traversal) + // make sure that UDP ports 3478, 4379, and 4380 are open in an outbound direction + k_EP2PSessionErrorMax = 5 +}; + +// SendP2PPacket() send types +// Typically k_EP2PSendUnreliable is what you want for UDP-like packets, k_EP2PSendReliable for TCP-like packets +enum EP2PSend +{ + // Basic UDP send. Packets can't be bigger than 1200 bytes (your typical MTU size). Can be lost, or arrive out of order (rare). + // The sending API does have some knowledge of the underlying connection, so if there is no NAT-traversal accomplished or + // there is a recognized adjustment happening on the connection, the packet will be batched until the connection is open again. + k_EP2PSendUnreliable = 0, + + // As above, but if the underlying p2p connection isn't yet established the packet will just be thrown away. Using this on the first + // packet sent to a remote host almost guarantees the packet will be dropped. + // This is only really useful for kinds of data that should never buffer up, i.e. voice payload packets + k_EP2PSendUnreliableNoDelay = 1, + + // Reliable message send. Can send up to 1MB of data in a single message. + // Does fragmentation/re-assembly of messages under the hood, as well as a sliding window for efficient sends of large chunks of data. + k_EP2PSendReliable = 2, + + // As above, but applies the Nagle algorithm to the send - sends will accumulate + // until the current MTU size (typically ~1200 bytes, but can change) or ~200ms has passed (Nagle algorithm). + // Useful if you want to send a set of smaller messages but have the coalesced into a single packet + // Since the reliable stream is all ordered, you can do several small message sends with k_EP2PSendReliableWithBuffering and then + // do a normal k_EP2PSendReliable to force all the buffered data to be sent. + k_EP2PSendReliableWithBuffering = 3, + +}; + + +// connection state to a specified user, returned by GetP2PSessionState() +// this is under-the-hood info about what's going on with a SendP2PPacket(), shouldn't be needed except for debuggin +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif +struct P2PSessionState_t +{ + uint8 m_bConnectionActive; // true if we've got an active open connection + uint8 m_bConnecting; // true if we're currently trying to establish a connection + uint8 m_eP2PSessionError; // last error recorded (see enum above) + uint8 m_bUsingRelay; // true if it's going through a relay server (TURN) + int32 m_nBytesQueuedForSend; + int32 m_nPacketsQueuedForSend; + uint32 m_nRemoteIP; // potential IP:Port of remote host. Could be TURN server. + uint16 m_nRemotePort; // Only exists for compatibility with older authentication api's +}; +#pragma pack( pop ) + + +// handle to a socket +typedef uint32 SNetSocket_t; // CreateP2PConnectionSocket() +typedef uint32 SNetListenSocket_t; // CreateListenSocket() + +// connection progress indicators, used by CreateP2PConnectionSocket() +enum ESNetSocketState +{ + k_ESNetSocketStateInvalid = 0, + + // communication is valid + k_ESNetSocketStateConnected = 1, + + // states while establishing a connection + k_ESNetSocketStateInitiated = 10, // the connection state machine has started + + // p2p connections + k_ESNetSocketStateLocalCandidatesFound = 11, // we've found our local IP info + k_ESNetSocketStateReceivedRemoteCandidates = 12,// we've received information from the remote machine, via the Steam back-end, about their IP info + + // direct connections + k_ESNetSocketStateChallengeHandshake = 15, // we've received a challenge packet from the server + + // failure states + k_ESNetSocketStateDisconnecting = 21, // the API shut it down, and we're in the process of telling the other end + k_ESNetSocketStateLocalDisconnect = 22, // the API shut it down, and we've completed shutdown + k_ESNetSocketStateTimeoutDuringConnect = 23, // we timed out while trying to creating the connection + k_ESNetSocketStateRemoteEndDisconnected = 24, // the remote end has disconnected from us + k_ESNetSocketStateConnectionBroken = 25, // connection has been broken; either the other end has disappeared or our local network connection has broke + +}; + +// describes how the socket is currently connected +enum ESNetSocketConnectionType +{ + k_ESNetSocketConnectionTypeNotConnected = 0, + k_ESNetSocketConnectionTypeUDP = 1, + k_ESNetSocketConnectionTypeUDPRelay = 2, +}; + + +//----------------------------------------------------------------------------- +// Purpose: Functions for making connections and sending data between clients, +// traversing NAT's where possible +//----------------------------------------------------------------------------- +class ISteamNetworking +{ +public: + //////////////////////////////////////////////////////////////////////////////////////////// + // Session-less connection functions + // automatically establishes NAT-traversing or Relay server connections + + // Sends a P2P packet to the specified user + // UDP-like, unreliable and a max packet size of 1200 bytes + // the first packet send may be delayed as the NAT-traversal code runs + // if we can't get through to the user, an error will be posted via the callback P2PSessionConnectFail_t + // see EP2PSend enum above for the descriptions of the different ways of sending packets + // + // nChannel is a routing number you can use to help route message to different systems - you'll have to call ReadP2PPacket() + // with the same channel number in order to retrieve the data on the other end + // using different channels to talk to the same user will still use the same underlying p2p connection, saving on resources + virtual bool SendP2PPacket( CSteamID steamIDRemote, const void *pubData, uint32 cubData, EP2PSend eP2PSendType, int nChannel = 0 ) = 0; + + // returns true if any data is available for read, and the amount of data that will need to be read + virtual bool IsP2PPacketAvailable( uint32 *pcubMsgSize, int nChannel = 0 ) = 0; + + // reads in a packet that has been sent from another user via SendP2PPacket() + // returns the size of the message and the steamID of the user who sent it in the last two parameters + // if the buffer passed in is too small, the message will be truncated + // this call is not blocking, and will return false if no data is available + virtual bool ReadP2PPacket( void *pubDest, uint32 cubDest, uint32 *pcubMsgSize, CSteamID *psteamIDRemote, int nChannel = 0 ) = 0; + + // AcceptP2PSessionWithUser() should only be called in response to a P2PSessionRequest_t callback + // P2PSessionRequest_t will be posted if another user tries to send you a packet that you haven't talked to yet + // if you don't want to talk to the user, just ignore the request + // if the user continues to send you packets, another P2PSessionRequest_t will be posted periodically + // this may be called multiple times for a single user + // (if you've called SendP2PPacket() on the other user, this implicitly accepts the session request) + virtual bool AcceptP2PSessionWithUser( CSteamID steamIDRemote ) = 0; + + // call CloseP2PSessionWithUser() when you're done talking to a user, will free up resources under-the-hood + // if the remote user tries to send data to you again, another P2PSessionRequest_t callback will be posted + virtual bool CloseP2PSessionWithUser( CSteamID steamIDRemote ) = 0; + + // call CloseP2PChannelWithUser() when you're done talking to a user on a specific channel. Once all channels + // open channels to a user have been closed, the open session to the user will be closed and new data from this + // user will trigger a P2PSessionRequest_t callback + virtual bool CloseP2PChannelWithUser( CSteamID steamIDRemote, int nChannel ) = 0; + + // fills out P2PSessionState_t structure with details about the underlying connection to the user + // should only needed for debugging purposes + // returns false if no connection exists to the specified user + virtual bool GetP2PSessionState( CSteamID steamIDRemote, P2PSessionState_t *pConnectionState ) = 0; + + // Allow P2P connections to fall back to being relayed through the Steam servers if a direct connection + // or NAT-traversal cannot be established. Only applies to connections created after setting this value, + // or to existing connections that need to automatically reconnect after this value is set. + // + // P2P packet relay is allowed by default + virtual bool AllowP2PPacketRelay( bool bAllow ) = 0; + + + //////////////////////////////////////////////////////////////////////////////////////////// + // LISTEN / CONNECT style interface functions + // + // This is an older set of functions designed around the Berkeley TCP sockets model + // it's preferential that you use the above P2P functions, they're more robust + // and these older functions will be removed eventually + // + //////////////////////////////////////////////////////////////////////////////////////////// + + + // creates a socket and listens others to connect + // will trigger a SocketStatusCallback_t callback on another client connecting + // nVirtualP2PPort is the unique ID that the client will connect to, in case you have multiple ports + // this can usually just be 0 unless you want multiple sets of connections + // unIP is the local IP address to bind to + // pass in 0 if you just want the default local IP + // unPort is the port to use + // pass in 0 if you don't want users to be able to connect via IP/Port, but expect to be always peer-to-peer connections only + virtual SNetListenSocket_t CreateListenSocket( int nVirtualP2PPort, uint32 nIP, uint16 nPort, bool bAllowUseOfPacketRelay ) = 0; + + // creates a socket and begin connection to a remote destination + // can connect via a known steamID (client or game server), or directly to an IP + // on success will trigger a SocketStatusCallback_t callback + // on failure or timeout will trigger a SocketStatusCallback_t callback with a failure code in m_eSNetSocketState + virtual SNetSocket_t CreateP2PConnectionSocket( CSteamID steamIDTarget, int nVirtualPort, int nTimeoutSec, bool bAllowUseOfPacketRelay ) = 0; + virtual SNetSocket_t CreateConnectionSocket( uint32 nIP, uint16 nPort, int nTimeoutSec ) = 0; + + // disconnects the connection to the socket, if any, and invalidates the handle + // any unread data on the socket will be thrown away + // if bNotifyRemoteEnd is set, socket will not be completely destroyed until the remote end acknowledges the disconnect + virtual bool DestroySocket( SNetSocket_t hSocket, bool bNotifyRemoteEnd ) = 0; + // destroying a listen socket will automatically kill all the regular sockets generated from it + virtual bool DestroyListenSocket( SNetListenSocket_t hSocket, bool bNotifyRemoteEnd ) = 0; + + // sending data + // must be a handle to a connected socket + // data is all sent via UDP, and thus send sizes are limited to 1200 bytes; after this, many routers will start dropping packets + // use the reliable flag with caution; although the resend rate is pretty aggressive, + // it can still cause stalls in receiving data (like TCP) + virtual bool SendDataOnSocket( SNetSocket_t hSocket, void *pubData, uint32 cubData, bool bReliable ) = 0; + + // receiving data + // returns false if there is no data remaining + // fills out *pcubMsgSize with the size of the next message, in bytes + virtual bool IsDataAvailableOnSocket( SNetSocket_t hSocket, uint32 *pcubMsgSize ) = 0; + + // fills in pubDest with the contents of the message + // messages are always complete, of the same size as was sent (i.e. packetized, not streaming) + // if *pcubMsgSize < cubDest, only partial data is written + // returns false if no data is available + virtual bool RetrieveDataFromSocket( SNetSocket_t hSocket, void *pubDest, uint32 cubDest, uint32 *pcubMsgSize ) = 0; + + // checks for data from any socket that has been connected off this listen socket + // returns false if there is no data remaining + // fills out *pcubMsgSize with the size of the next message, in bytes + // fills out *phSocket with the socket that data is available on + virtual bool IsDataAvailable( SNetListenSocket_t hListenSocket, uint32 *pcubMsgSize, SNetSocket_t *phSocket ) = 0; + + // retrieves data from any socket that has been connected off this listen socket + // fills in pubDest with the contents of the message + // messages are always complete, of the same size as was sent (i.e. packetized, not streaming) + // if *pcubMsgSize < cubDest, only partial data is written + // returns false if no data is available + // fills out *phSocket with the socket that data is available on + virtual bool RetrieveData( SNetListenSocket_t hListenSocket, void *pubDest, uint32 cubDest, uint32 *pcubMsgSize, SNetSocket_t *phSocket ) = 0; + + // returns information about the specified socket, filling out the contents of the pointers + virtual bool GetSocketInfo( SNetSocket_t hSocket, CSteamID *pSteamIDRemote, int *peSocketStatus, uint32 *punIPRemote, uint16 *punPortRemote ) = 0; + + // returns which local port the listen socket is bound to + // *pnIP and *pnPort will be 0 if the socket is set to listen for P2P connections only + virtual bool GetListenSocketInfo( SNetListenSocket_t hListenSocket, uint32 *pnIP, uint16 *pnPort ) = 0; + + // returns true to describe how the socket ended up connecting + virtual ESNetSocketConnectionType GetSocketConnectionType( SNetSocket_t hSocket ) = 0; + + // max packet size, in bytes + virtual int GetMaxPacketSize( SNetSocket_t hSocket ) = 0; +}; +#define STEAMNETWORKING_INTERFACE_VERSION "SteamNetworking005" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + +// callback notification - a user wants to talk to us over the P2P channel via the SendP2PPacket() API +// in response, a call to AcceptP2PPacketsFromUser() needs to be made, if you want to talk with them +struct P2PSessionRequest_t +{ + enum { k_iCallback = k_iSteamNetworkingCallbacks + 2 }; + CSteamID m_steamIDRemote; // user who wants to talk to us +}; + + +// callback notification - packets can't get through to the specified user via the SendP2PPacket() API +// all packets queued packets unsent at this point will be dropped +// further attempts to send will retry making the connection (but will be dropped if we fail again) +struct P2PSessionConnectFail_t +{ + enum { k_iCallback = k_iSteamNetworkingCallbacks + 3 }; + CSteamID m_steamIDRemote; // user we were sending packets to + uint8 m_eP2PSessionError; // EP2PSessionError indicating why we're having trouble +}; + + +// callback notification - status of a socket has changed +// used as part of the CreateListenSocket() / CreateP2PConnectionSocket() +struct SocketStatusCallback_t +{ + enum { k_iCallback = k_iSteamNetworkingCallbacks + 1 }; + SNetSocket_t m_hSocket; // the socket used to send/receive data to the remote host + SNetListenSocket_t m_hListenSocket; // this is the server socket that we were listening on; NULL if this was an outgoing connection + CSteamID m_steamIDRemote; // remote steamID we have connected to, if it has one + int m_eSNetSocketState; // socket state, ESNetSocketState +}; + +#pragma pack( pop ) + +#endif // ISTEAMNETWORKING diff --git a/ScreenPlayWorkshop/ThirdParty/steam/isteamparentalsettings.h b/ScreenPlayWorkshop/ThirdParty/steam/isteamparentalsettings.h new file mode 100644 index 00000000..1b6ba9f8 --- /dev/null +++ b/ScreenPlayWorkshop/ThirdParty/steam/isteamparentalsettings.h @@ -0,0 +1,57 @@ +//====== Copyright � 2013-, Valve Corporation, All rights reserved. ======= +// +// Purpose: Interface to Steam parental settings (Family View) +// +//============================================================================= + +#ifndef ISTEAMPARENTALSETTINGS_H +#define ISTEAMPARENTALSETTINGS_H +#ifdef _WIN32 +#pragma once +#endif + +// Feature types for parental settings +enum EParentalFeature +{ + k_EFeatureInvalid = 0, + k_EFeatureStore = 1, + k_EFeatureCommunity = 2, + k_EFeatureProfile = 3, + k_EFeatureFriends = 4, + k_EFeatureNews = 5, + k_EFeatureTrading = 6, + k_EFeatureSettings = 7, + k_EFeatureConsole = 8, + k_EFeatureBrowser = 9, + k_EFeatureParentalSetup = 10, + k_EFeatureLibrary = 11, + k_EFeatureTest = 12, + k_EFeatureMax +}; + +class ISteamParentalSettings +{ +public: + virtual bool BIsParentalLockEnabled() = 0; + virtual bool BIsParentalLockLocked() = 0; + + virtual bool BIsAppBlocked( AppId_t nAppID ) = 0; + virtual bool BIsAppInBlockList( AppId_t nAppID ) = 0; + + virtual bool BIsFeatureBlocked( EParentalFeature eFeature ) = 0; + virtual bool BIsFeatureInBlockList( EParentalFeature eFeature ) = 0; +}; + +#define STEAMPARENTALSETTINGS_INTERFACE_VERSION "STEAMPARENTALSETTINGS_INTERFACE_VERSION001" + + +//----------------------------------------------------------------------------- +// Purpose: Callback for querying UGC +//----------------------------------------------------------------------------- +struct SteamParentalSettingsChanged_t +{ + enum { k_iCallback = k_ISteamParentalSettingsCallbacks + 1 }; +}; + + +#endif // ISTEAMPARENTALSETTINGS_H diff --git a/ScreenPlayWorkshop/ThirdParty/steam/isteamps3overlayrenderer.h b/ScreenPlayWorkshop/ThirdParty/steam/isteamps3overlayrenderer.h new file mode 100644 index 00000000..4e07d4a1 --- /dev/null +++ b/ScreenPlayWorkshop/ThirdParty/steam/isteamps3overlayrenderer.h @@ -0,0 +1,91 @@ +//====== Copyright © 1996-2010, Valve Corporation, All rights reserved. ======= +// +// Purpose: interface the game must provide Steam with on PS3 in order for the +// Steam overlay to render. +// +//============================================================================= + +#ifndef ISTEAMPS3OVERLAYRENDERER_H +#define ISTEAMPS3OVERLAYRENDERER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "cell/pad.h" + +//----------------------------------------------------------------------------- +// Purpose: Enum for supported gradient directions +//----------------------------------------------------------------------------- +enum EOverlayGradientDirection +{ + k_EOverlayGradientHorizontal = 1, + k_EOverlayGradientVertical = 2, + k_EOverlayGradientNone = 3, +}; + +// Helpers for fetching individual color components from ARGB packed DWORD colors Steam PS3 overlay renderer uses. +#define STEAM_COLOR_RED( color ) \ + (int)(((color)>>16)&0xff) + +#define STEAM_COLOR_GREEN( color ) \ + (int)(((color)>>8)&0xff) + +#define STEAM_COLOR_BLUE( color ) \ + (int)((color)&0xff) + +#define STEAM_COLOR_ALPHA( color ) \ + (int)(((color)>>24)&0xff) + + +//----------------------------------------------------------------------------- +// Purpose: Interface the game must expose to Steam for rendering +//----------------------------------------------------------------------------- +class ISteamPS3OverlayRenderHost +{ +public: + + // Interface for game engine to implement which Steam requires to render. + + // Draw a textured rect. This may use only part of the texture and will pass texture coords, it will also possibly request a gradient and will specify colors for vertexes. + virtual void DrawTexturedRect( int x0, int y0, int x1, int y1, float u0, float v0, float u1, float v1, int32 iTextureID, DWORD colorStart, DWORD colorEnd, EOverlayGradientDirection eDirection ) = 0; + + // Load a RGBA texture for Steam, or update a previously loaded one. Updates may be partial. You must not evict or remove this texture once Steam has uploaded it. + virtual void LoadOrUpdateTexture( int32 iTextureID, bool bIsFullTexture, int x0, int y0, uint32 uWidth, uint32 uHeight, int32 iBytes, char *pData ) = 0; + + // Delete a texture Steam previously uploaded + virtual void DeleteTexture( int32 iTextureID ) = 0; + + // Delete all previously uploaded textures + virtual void DeleteAllTextures() = 0; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Interface Steam exposes for the game to tell it when to render, etc. +//----------------------------------------------------------------------------- +class ISteamPS3OverlayRender +{ +public: + + // Call once at startup to initialize the Steam overlay and pass it your host interface ptr + virtual bool BHostInitialize( uint32 unScreenWidth, uint32 unScreenHeight, uint32 unRefreshRate, ISteamPS3OverlayRenderHost *pRenderHost, void *CellFontLib ) = 0; + + // Call this once a frame when you are ready for the Steam overlay to render (ie, right before flipping buffers, after all your rendering) + virtual void Render() = 0; + + // Call this everytime you read input on PS3. + // + // If this returns true, then the overlay is active and has consumed the input, your game + // should then ignore all the input until BHandleCellPadData once again returns false, which + // will mean the overlay is deactivated. + virtual bool BHandleCellPadData( const CellPadData &padData ) = 0; + + // Call this if you detect no controllers connected or that the XMB is intercepting input + // + // This is important to clear input state for the overlay, so keys left down during XMB activation + // are not continued to be processed. + virtual bool BResetInputState() = 0; +}; + + +#endif // ISTEAMPS3OVERLAYRENDERER_H \ No newline at end of file diff --git a/ScreenPlayWorkshop/ThirdParty/steam/isteamremotestorage.h b/ScreenPlayWorkshop/ThirdParty/steam/isteamremotestorage.h new file mode 100644 index 00000000..3ac28719 --- /dev/null +++ b/ScreenPlayWorkshop/ThirdParty/steam/isteamremotestorage.h @@ -0,0 +1,681 @@ +//====== Copyright � 1996-2008, Valve Corporation, All rights reserved. ======= +// +// Purpose: public interface to user remote file storage in Steam +// +//============================================================================= + +#ifndef ISTEAMREMOTESTORAGE_H +#define ISTEAMREMOTESTORAGE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isteamclient.h" + + +//----------------------------------------------------------------------------- +// Purpose: Defines the largest allowed file size. Cloud files cannot be written +// in a single chunk over 100MB (and cannot be over 200MB total.) +//----------------------------------------------------------------------------- +const uint32 k_unMaxCloudFileChunkSize = 100 * 1024 * 1024; + + +//----------------------------------------------------------------------------- +// Purpose: Structure that contains an array of const char * strings and the number of those strings +//----------------------------------------------------------------------------- +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif +struct SteamParamStringArray_t +{ + const char ** m_ppStrings; + int32 m_nNumStrings; +}; +#pragma pack( pop ) + +// A handle to a piece of user generated content +typedef uint64 UGCHandle_t; +typedef uint64 PublishedFileUpdateHandle_t; +typedef uint64 PublishedFileId_t; +const PublishedFileId_t k_PublishedFileIdInvalid = 0; +const UGCHandle_t k_UGCHandleInvalid = 0xffffffffffffffffull; +const PublishedFileUpdateHandle_t k_PublishedFileUpdateHandleInvalid = 0xffffffffffffffffull; + +// Handle for writing to Steam Cloud +typedef uint64 UGCFileWriteStreamHandle_t; +const UGCFileWriteStreamHandle_t k_UGCFileStreamHandleInvalid = 0xffffffffffffffffull; + +const uint32 k_cchPublishedDocumentTitleMax = 128 + 1; +const uint32 k_cchPublishedDocumentDescriptionMax = 8000; +const uint32 k_cchPublishedDocumentChangeDescriptionMax = 8000; +const uint32 k_unEnumeratePublishedFilesMaxResults = 50; +const uint32 k_cchTagListMax = 1024 + 1; +const uint32 k_cchFilenameMax = 260; +const uint32 k_cchPublishedFileURLMax = 256; + + +enum ERemoteStoragePlatform +{ + k_ERemoteStoragePlatformNone = 0, + k_ERemoteStoragePlatformWindows = (1 << 0), + k_ERemoteStoragePlatformOSX = (1 << 1), + k_ERemoteStoragePlatformPS3 = (1 << 2), + k_ERemoteStoragePlatformLinux = (1 << 3), + k_ERemoteStoragePlatformReserved2 = (1 << 4), + + k_ERemoteStoragePlatformAll = 0xffffffff +}; + +enum ERemoteStoragePublishedFileVisibility +{ + k_ERemoteStoragePublishedFileVisibilityPublic = 0, + k_ERemoteStoragePublishedFileVisibilityFriendsOnly = 1, + k_ERemoteStoragePublishedFileVisibilityPrivate = 2, +}; + + +enum EWorkshopFileType +{ + k_EWorkshopFileTypeFirst = 0, + + k_EWorkshopFileTypeCommunity = 0, // normal Workshop item that can be subscribed to + k_EWorkshopFileTypeMicrotransaction = 1, // Workshop item that is meant to be voted on for the purpose of selling in-game + k_EWorkshopFileTypeCollection = 2, // a collection of Workshop or Greenlight items + k_EWorkshopFileTypeArt = 3, // artwork + k_EWorkshopFileTypeVideo = 4, // external video + k_EWorkshopFileTypeScreenshot = 5, // screenshot + k_EWorkshopFileTypeGame = 6, // Greenlight game entry + k_EWorkshopFileTypeSoftware = 7, // Greenlight software entry + k_EWorkshopFileTypeConcept = 8, // Greenlight concept + k_EWorkshopFileTypeWebGuide = 9, // Steam web guide + k_EWorkshopFileTypeIntegratedGuide = 10, // application integrated guide + k_EWorkshopFileTypeMerch = 11, // Workshop merchandise meant to be voted on for the purpose of being sold + k_EWorkshopFileTypeControllerBinding = 12, // Steam Controller bindings + k_EWorkshopFileTypeSteamworksAccessInvite = 13, // internal + k_EWorkshopFileTypeSteamVideo = 14, // Steam video + k_EWorkshopFileTypeGameManagedItem = 15, // managed completely by the game, not the user, and not shown on the web + + // Update k_EWorkshopFileTypeMax if you add values. + k_EWorkshopFileTypeMax = 16 + +}; + +enum EWorkshopVote +{ + k_EWorkshopVoteUnvoted = 0, + k_EWorkshopVoteFor = 1, + k_EWorkshopVoteAgainst = 2, + k_EWorkshopVoteLater = 3, +}; + +enum EWorkshopFileAction +{ + k_EWorkshopFileActionPlayed = 0, + k_EWorkshopFileActionCompleted = 1, +}; + +enum EWorkshopEnumerationType +{ + k_EWorkshopEnumerationTypeRankedByVote = 0, + k_EWorkshopEnumerationTypeRecent = 1, + k_EWorkshopEnumerationTypeTrending = 2, + k_EWorkshopEnumerationTypeFavoritesOfFriends = 3, + k_EWorkshopEnumerationTypeVotedByFriends = 4, + k_EWorkshopEnumerationTypeContentByFriends = 5, + k_EWorkshopEnumerationTypeRecentFromFollowedUsers = 6, +}; + +enum EWorkshopVideoProvider +{ + k_EWorkshopVideoProviderNone = 0, + k_EWorkshopVideoProviderYoutube = 1 +}; + + +enum EUGCReadAction +{ + // Keeps the file handle open unless the last byte is read. You can use this when reading large files (over 100MB) in sequential chunks. + // If the last byte is read, this will behave the same as k_EUGCRead_Close. Otherwise, it behaves the same as k_EUGCRead_ContinueReading. + // This value maintains the same behavior as before the EUGCReadAction parameter was introduced. + k_EUGCRead_ContinueReadingUntilFinished = 0, + + // Keeps the file handle open. Use this when using UGCRead to seek to different parts of the file. + // When you are done seeking around the file, make a final call with k_EUGCRead_Close to close it. + k_EUGCRead_ContinueReading = 1, + + // Frees the file handle. Use this when you're done reading the content. + // To read the file from Steam again you will need to call UGCDownload again. + k_EUGCRead_Close = 2, +}; + + +//----------------------------------------------------------------------------- +// Purpose: Functions for accessing, reading and writing files stored remotely +// and cached locally +//----------------------------------------------------------------------------- +class ISteamRemoteStorage +{ + public: + // NOTE + // + // Filenames are case-insensitive, and will be converted to lowercase automatically. + // So "foo.bar" and "Foo.bar" are the same file, and if you write "Foo.bar" then + // iterate the files, the filename returned will be "foo.bar". + // + + // file operations + virtual bool FileWrite( const char *pchFile, const void *pvData, int32 cubData ) = 0; + virtual int32 FileRead( const char *pchFile, void *pvData, int32 cubDataToRead ) = 0; + + CALL_RESULT( RemoteStorageFileWriteAsyncComplete_t ) + virtual SteamAPICall_t FileWriteAsync( const char *pchFile, const void *pvData, uint32 cubData ) = 0; + + CALL_RESULT( RemoteStorageFileReadAsyncComplete_t ) + virtual SteamAPICall_t FileReadAsync( const char *pchFile, uint32 nOffset, uint32 cubToRead ) = 0; + virtual bool FileReadAsyncComplete( SteamAPICall_t hReadCall, void *pvBuffer, uint32 cubToRead ) = 0; + + virtual bool FileForget( const char *pchFile ) = 0; + virtual bool FileDelete( const char *pchFile ) = 0; + CALL_RESULT( RemoteStorageFileShareResult_t ) + virtual SteamAPICall_t FileShare( const char *pchFile ) = 0; + virtual bool SetSyncPlatforms( const char *pchFile, ERemoteStoragePlatform eRemoteStoragePlatform ) = 0; + + // file operations that cause network IO + virtual UGCFileWriteStreamHandle_t FileWriteStreamOpen( const char *pchFile ) = 0; + virtual bool FileWriteStreamWriteChunk( UGCFileWriteStreamHandle_t writeHandle, const void *pvData, int32 cubData ) = 0; + virtual bool FileWriteStreamClose( UGCFileWriteStreamHandle_t writeHandle ) = 0; + virtual bool FileWriteStreamCancel( UGCFileWriteStreamHandle_t writeHandle ) = 0; + + // file information + virtual bool FileExists( const char *pchFile ) = 0; + virtual bool FilePersisted( const char *pchFile ) = 0; + virtual int32 GetFileSize( const char *pchFile ) = 0; + virtual int64 GetFileTimestamp( const char *pchFile ) = 0; + virtual ERemoteStoragePlatform GetSyncPlatforms( const char *pchFile ) = 0; + + // iteration + virtual int32 GetFileCount() = 0; + virtual const char *GetFileNameAndSize( int iFile, int32 *pnFileSizeInBytes ) = 0; + + // configuration management + virtual bool GetQuota( uint64 *pnTotalBytes, uint64 *puAvailableBytes ) = 0; + virtual bool IsCloudEnabledForAccount() = 0; + virtual bool IsCloudEnabledForApp() = 0; + virtual void SetCloudEnabledForApp( bool bEnabled ) = 0; + + // user generated content + + // Downloads a UGC file. A priority value of 0 will download the file immediately, + // otherwise it will wait to download the file until all downloads with a lower priority + // value are completed. Downloads with equal priority will occur simultaneously. + CALL_RESULT( RemoteStorageDownloadUGCResult_t ) + virtual SteamAPICall_t UGCDownload( UGCHandle_t hContent, uint32 unPriority ) = 0; + + // Gets the amount of data downloaded so far for a piece of content. pnBytesExpected can be 0 if function returns false + // or if the transfer hasn't started yet, so be careful to check for that before dividing to get a percentage + virtual bool GetUGCDownloadProgress( UGCHandle_t hContent, int32 *pnBytesDownloaded, int32 *pnBytesExpected ) = 0; + + // Gets metadata for a file after it has been downloaded. This is the same metadata given in the RemoteStorageDownloadUGCResult_t call result + virtual bool GetUGCDetails( UGCHandle_t hContent, AppId_t *pnAppID, OUT_STRING() char **ppchName, int32 *pnFileSizeInBytes, OUT_STRUCT() CSteamID *pSteamIDOwner ) = 0; + + // After download, gets the content of the file. + // Small files can be read all at once by calling this function with an offset of 0 and cubDataToRead equal to the size of the file. + // Larger files can be read in chunks to reduce memory usage (since both sides of the IPC client and the game itself must allocate + // enough memory for each chunk). Once the last byte is read, the file is implicitly closed and further calls to UGCRead will fail + // unless UGCDownload is called again. + // For especially large files (anything over 100MB) it is a requirement that the file is read in chunks. + virtual int32 UGCRead( UGCHandle_t hContent, void *pvData, int32 cubDataToRead, uint32 cOffset, EUGCReadAction eAction ) = 0; + + // Functions to iterate through UGC that has finished downloading but has not yet been read via UGCRead() + virtual int32 GetCachedUGCCount() = 0; + virtual UGCHandle_t GetCachedUGCHandle( int32 iCachedContent ) = 0; + + // The following functions are only necessary on the Playstation 3. On PC & Mac, the Steam client will handle these operations for you + // On Playstation 3, the game controls which files are stored in the cloud, via FilePersist, FileFetch, and FileForget. + +#if defined(_PS3) || defined(_SERVER) + // Connect to Steam and get a list of files in the Cloud - results in a RemoteStorageAppSyncStatusCheck_t callback + virtual void GetFileListFromServer() = 0; + // Indicate this file should be downloaded in the next sync + virtual bool FileFetch( const char *pchFile ) = 0; + // Indicate this file should be persisted in the next sync + virtual bool FilePersist( const char *pchFile ) = 0; + // Pull any requested files down from the Cloud - results in a RemoteStorageAppSyncedClient_t callback + virtual bool SynchronizeToClient() = 0; + // Upload any requested files to the Cloud - results in a RemoteStorageAppSyncedServer_t callback + virtual bool SynchronizeToServer() = 0; + // Reset any fetch/persist/etc requests + virtual bool ResetFileRequestState() = 0; +#endif + + // publishing UGC + CALL_RESULT( RemoteStoragePublishFileProgress_t ) + virtual SteamAPICall_t PublishWorkshopFile( const char *pchFile, const char *pchPreviewFile, AppId_t nConsumerAppId, const char *pchTitle, const char *pchDescription, ERemoteStoragePublishedFileVisibility eVisibility, SteamParamStringArray_t *pTags, EWorkshopFileType eWorkshopFileType ) = 0; + virtual PublishedFileUpdateHandle_t CreatePublishedFileUpdateRequest( PublishedFileId_t unPublishedFileId ) = 0; + virtual bool UpdatePublishedFileFile( PublishedFileUpdateHandle_t updateHandle, const char *pchFile ) = 0; + virtual bool UpdatePublishedFilePreviewFile( PublishedFileUpdateHandle_t updateHandle, const char *pchPreviewFile ) = 0; + virtual bool UpdatePublishedFileTitle( PublishedFileUpdateHandle_t updateHandle, const char *pchTitle ) = 0; + virtual bool UpdatePublishedFileDescription( PublishedFileUpdateHandle_t updateHandle, const char *pchDescription ) = 0; + virtual bool UpdatePublishedFileVisibility( PublishedFileUpdateHandle_t updateHandle, ERemoteStoragePublishedFileVisibility eVisibility ) = 0; + virtual bool UpdatePublishedFileTags( PublishedFileUpdateHandle_t updateHandle, SteamParamStringArray_t *pTags ) = 0; + CALL_RESULT( RemoteStorageUpdatePublishedFileResult_t ) + virtual SteamAPICall_t CommitPublishedFileUpdate( PublishedFileUpdateHandle_t updateHandle ) = 0; + // Gets published file details for the given publishedfileid. If unMaxSecondsOld is greater than 0, + // cached data may be returned, depending on how long ago it was cached. A value of 0 will force a refresh. + // A value of k_WorkshopForceLoadPublishedFileDetailsFromCache will use cached data if it exists, no matter how old it is. + CALL_RESULT( RemoteStorageGetPublishedFileDetailsResult_t ) + virtual SteamAPICall_t GetPublishedFileDetails( PublishedFileId_t unPublishedFileId, uint32 unMaxSecondsOld ) = 0; + CALL_RESULT( RemoteStorageDeletePublishedFileResult_t ) + virtual SteamAPICall_t DeletePublishedFile( PublishedFileId_t unPublishedFileId ) = 0; + // enumerate the files that the current user published with this app + CALL_RESULT( RemoteStorageEnumerateUserPublishedFilesResult_t ) + virtual SteamAPICall_t EnumerateUserPublishedFiles( uint32 unStartIndex ) = 0; + CALL_RESULT( RemoteStorageSubscribePublishedFileResult_t ) + virtual SteamAPICall_t SubscribePublishedFile( PublishedFileId_t unPublishedFileId ) = 0; + CALL_RESULT( RemoteStorageEnumerateUserSubscribedFilesResult_t ) + virtual SteamAPICall_t EnumerateUserSubscribedFiles( uint32 unStartIndex ) = 0; + CALL_RESULT( RemoteStorageUnsubscribePublishedFileResult_t ) + virtual SteamAPICall_t UnsubscribePublishedFile( PublishedFileId_t unPublishedFileId ) = 0; + virtual bool UpdatePublishedFileSetChangeDescription( PublishedFileUpdateHandle_t updateHandle, const char *pchChangeDescription ) = 0; + CALL_RESULT( RemoteStorageGetPublishedItemVoteDetailsResult_t ) + virtual SteamAPICall_t GetPublishedItemVoteDetails( PublishedFileId_t unPublishedFileId ) = 0; + CALL_RESULT( RemoteStorageUpdateUserPublishedItemVoteResult_t ) + virtual SteamAPICall_t UpdateUserPublishedItemVote( PublishedFileId_t unPublishedFileId, bool bVoteUp ) = 0; + CALL_RESULT( RemoteStorageGetPublishedItemVoteDetailsResult_t ) + virtual SteamAPICall_t GetUserPublishedItemVoteDetails( PublishedFileId_t unPublishedFileId ) = 0; + CALL_RESULT( RemoteStorageEnumerateUserPublishedFilesResult_t ) + virtual SteamAPICall_t EnumerateUserSharedWorkshopFiles( CSteamID steamId, uint32 unStartIndex, SteamParamStringArray_t *pRequiredTags, SteamParamStringArray_t *pExcludedTags ) = 0; + CALL_RESULT( RemoteStoragePublishFileProgress_t ) + virtual SteamAPICall_t PublishVideo( EWorkshopVideoProvider eVideoProvider, const char *pchVideoAccount, const char *pchVideoIdentifier, const char *pchPreviewFile, AppId_t nConsumerAppId, const char *pchTitle, const char *pchDescription, ERemoteStoragePublishedFileVisibility eVisibility, SteamParamStringArray_t *pTags ) = 0; + CALL_RESULT( RemoteStorageSetUserPublishedFileActionResult_t ) + virtual SteamAPICall_t SetUserPublishedFileAction( PublishedFileId_t unPublishedFileId, EWorkshopFileAction eAction ) = 0; + CALL_RESULT( RemoteStorageEnumeratePublishedFilesByUserActionResult_t ) + virtual SteamAPICall_t EnumeratePublishedFilesByUserAction( EWorkshopFileAction eAction, uint32 unStartIndex ) = 0; + // this method enumerates the public view of workshop files + CALL_RESULT( RemoteStorageEnumerateWorkshopFilesResult_t ) + virtual SteamAPICall_t EnumeratePublishedWorkshopFiles( EWorkshopEnumerationType eEnumerationType, uint32 unStartIndex, uint32 unCount, uint32 unDays, SteamParamStringArray_t *pTags, SteamParamStringArray_t *pUserTags ) = 0; + + CALL_RESULT( RemoteStorageDownloadUGCResult_t ) + virtual SteamAPICall_t UGCDownloadToLocation( UGCHandle_t hContent, const char *pchLocation, uint32 unPriority ) = 0; +}; + +#define STEAMREMOTESTORAGE_INTERFACE_VERSION "STEAMREMOTESTORAGE_INTERFACE_VERSION014" + + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + +//----------------------------------------------------------------------------- +// Purpose: sent when the local file cache is fully synced with the server for an app +// That means that an application can be started and has all latest files +//----------------------------------------------------------------------------- +struct RemoteStorageAppSyncedClient_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 1 }; + AppId_t m_nAppID; + EResult m_eResult; + int m_unNumDownloads; +}; + +//----------------------------------------------------------------------------- +// Purpose: sent when the server is fully synced with the local file cache for an app +// That means that we can shutdown Steam and our data is stored on the server +//----------------------------------------------------------------------------- +struct RemoteStorageAppSyncedServer_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 2 }; + AppId_t m_nAppID; + EResult m_eResult; + int m_unNumUploads; +}; + +//----------------------------------------------------------------------------- +// Purpose: Status of up and downloads during a sync session +// +//----------------------------------------------------------------------------- +struct RemoteStorageAppSyncProgress_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 3 }; + char m_rgchCurrentFile[k_cchFilenameMax]; // Current file being transferred + AppId_t m_nAppID; // App this info relates to + uint32 m_uBytesTransferredThisChunk; // Bytes transferred this chunk + double m_dAppPercentComplete; // Percent complete that this app's transfers are + bool m_bUploading; // if false, downloading +}; + +// +// IMPORTANT! k_iClientRemoteStorageCallbacks + 4 is used, see iclientremotestorage.h +// + + +//----------------------------------------------------------------------------- +// Purpose: Sent after we've determined the list of files that are out of sync +// with the server. +//----------------------------------------------------------------------------- +struct RemoteStorageAppSyncStatusCheck_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 5 }; + AppId_t m_nAppID; + EResult m_eResult; +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to FileShare() +//----------------------------------------------------------------------------- +struct RemoteStorageFileShareResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 7 }; + EResult m_eResult; // The result of the operation + UGCHandle_t m_hFile; // The handle that can be shared with users and features + char m_rgchFilename[k_cchFilenameMax]; // The name of the file that was shared +}; + + +// k_iClientRemoteStorageCallbacks + 8 is deprecated! Do not reuse + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to PublishFile() +//----------------------------------------------------------------------------- +struct RemoteStoragePublishFileResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 9 }; + EResult m_eResult; // The result of the operation. + PublishedFileId_t m_nPublishedFileId; + bool m_bUserNeedsToAcceptWorkshopLegalAgreement; +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to DeletePublishedFile() +//----------------------------------------------------------------------------- +struct RemoteStorageDeletePublishedFileResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 11 }; + EResult m_eResult; // The result of the operation. + PublishedFileId_t m_nPublishedFileId; +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to EnumerateUserPublishedFiles() +//----------------------------------------------------------------------------- +struct RemoteStorageEnumerateUserPublishedFilesResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 12 }; + EResult m_eResult; // The result of the operation. + int32 m_nResultsReturned; + int32 m_nTotalResultCount; + PublishedFileId_t m_rgPublishedFileId[ k_unEnumeratePublishedFilesMaxResults ]; +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to SubscribePublishedFile() +//----------------------------------------------------------------------------- +struct RemoteStorageSubscribePublishedFileResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 13 }; + EResult m_eResult; // The result of the operation. + PublishedFileId_t m_nPublishedFileId; +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to EnumerateSubscribePublishedFiles() +//----------------------------------------------------------------------------- +struct RemoteStorageEnumerateUserSubscribedFilesResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 14 }; + EResult m_eResult; // The result of the operation. + int32 m_nResultsReturned; + int32 m_nTotalResultCount; + PublishedFileId_t m_rgPublishedFileId[ k_unEnumeratePublishedFilesMaxResults ]; + uint32 m_rgRTimeSubscribed[ k_unEnumeratePublishedFilesMaxResults ]; +}; + +#if defined(VALVE_CALLBACK_PACK_SMALL) + VALVE_COMPILE_TIME_ASSERT( sizeof( RemoteStorageEnumerateUserSubscribedFilesResult_t ) == (1 + 1 + 1 + 50 + 100) * 4 ); +#elif defined(VALVE_CALLBACK_PACK_LARGE) + VALVE_COMPILE_TIME_ASSERT( sizeof( RemoteStorageEnumerateUserSubscribedFilesResult_t ) == (1 + 1 + 1 + 50 + 100) * 4 + 4 ); +#else +#warning You must first include isteamclient.h +#endif + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to UnsubscribePublishedFile() +//----------------------------------------------------------------------------- +struct RemoteStorageUnsubscribePublishedFileResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 15 }; + EResult m_eResult; // The result of the operation. + PublishedFileId_t m_nPublishedFileId; +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to CommitPublishedFileUpdate() +//----------------------------------------------------------------------------- +struct RemoteStorageUpdatePublishedFileResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 16 }; + EResult m_eResult; // The result of the operation. + PublishedFileId_t m_nPublishedFileId; + bool m_bUserNeedsToAcceptWorkshopLegalAgreement; +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to UGCDownload() +//----------------------------------------------------------------------------- +struct RemoteStorageDownloadUGCResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 17 }; + EResult m_eResult; // The result of the operation. + UGCHandle_t m_hFile; // The handle to the file that was attempted to be downloaded. + AppId_t m_nAppID; // ID of the app that created this file. + int32 m_nSizeInBytes; // The size of the file that was downloaded, in bytes. + char m_pchFileName[k_cchFilenameMax]; // The name of the file that was downloaded. + uint64 m_ulSteamIDOwner; // Steam ID of the user who created this content. +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to GetPublishedFileDetails() +//----------------------------------------------------------------------------- +struct RemoteStorageGetPublishedFileDetailsResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 18 }; + EResult m_eResult; // The result of the operation. + PublishedFileId_t m_nPublishedFileId; + AppId_t m_nCreatorAppID; // ID of the app that created this file. + AppId_t m_nConsumerAppID; // ID of the app that will consume this file. + char m_rgchTitle[k_cchPublishedDocumentTitleMax]; // title of document + char m_rgchDescription[k_cchPublishedDocumentDescriptionMax]; // description of document + UGCHandle_t m_hFile; // The handle of the primary file + UGCHandle_t m_hPreviewFile; // The handle of the preview file + uint64 m_ulSteamIDOwner; // Steam ID of the user who created this content. + uint32 m_rtimeCreated; // time when the published file was created + uint32 m_rtimeUpdated; // time when the published file was last updated + ERemoteStoragePublishedFileVisibility m_eVisibility; + bool m_bBanned; + char m_rgchTags[k_cchTagListMax]; // comma separated list of all tags associated with this file + bool m_bTagsTruncated; // whether the list of tags was too long to be returned in the provided buffer + char m_pchFileName[k_cchFilenameMax]; // The name of the primary file + int32 m_nFileSize; // Size of the primary file + int32 m_nPreviewFileSize; // Size of the preview file + char m_rgchURL[k_cchPublishedFileURLMax]; // URL (for a video or a website) + EWorkshopFileType m_eFileType; // Type of the file + bool m_bAcceptedForUse; // developer has specifically flagged this item as accepted in the Workshop +}; + + +struct RemoteStorageEnumerateWorkshopFilesResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 19 }; + EResult m_eResult; + int32 m_nResultsReturned; + int32 m_nTotalResultCount; + PublishedFileId_t m_rgPublishedFileId[ k_unEnumeratePublishedFilesMaxResults ]; + float m_rgScore[ k_unEnumeratePublishedFilesMaxResults ]; + AppId_t m_nAppId; + uint32 m_unStartIndex; +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of GetPublishedItemVoteDetails +//----------------------------------------------------------------------------- +struct RemoteStorageGetPublishedItemVoteDetailsResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 20 }; + EResult m_eResult; + PublishedFileId_t m_unPublishedFileId; + int32 m_nVotesFor; + int32 m_nVotesAgainst; + int32 m_nReports; + float m_fScore; +}; + + +//----------------------------------------------------------------------------- +// Purpose: User subscribed to a file for the app (from within the app or on the web) +//----------------------------------------------------------------------------- +struct RemoteStoragePublishedFileSubscribed_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 21 }; + PublishedFileId_t m_nPublishedFileId; // The published file id + AppId_t m_nAppID; // ID of the app that will consume this file. +}; + +//----------------------------------------------------------------------------- +// Purpose: User unsubscribed from a file for the app (from within the app or on the web) +//----------------------------------------------------------------------------- +struct RemoteStoragePublishedFileUnsubscribed_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 22 }; + PublishedFileId_t m_nPublishedFileId; // The published file id + AppId_t m_nAppID; // ID of the app that will consume this file. +}; + + +//----------------------------------------------------------------------------- +// Purpose: Published file that a user owns was deleted (from within the app or the web) +//----------------------------------------------------------------------------- +struct RemoteStoragePublishedFileDeleted_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 23 }; + PublishedFileId_t m_nPublishedFileId; // The published file id + AppId_t m_nAppID; // ID of the app that will consume this file. +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to UpdateUserPublishedItemVote() +//----------------------------------------------------------------------------- +struct RemoteStorageUpdateUserPublishedItemVoteResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 24 }; + EResult m_eResult; // The result of the operation. + PublishedFileId_t m_nPublishedFileId; // The published file id +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to GetUserPublishedItemVoteDetails() +//----------------------------------------------------------------------------- +struct RemoteStorageUserVoteDetails_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 25 }; + EResult m_eResult; // The result of the operation. + PublishedFileId_t m_nPublishedFileId; // The published file id + EWorkshopVote m_eVote; // what the user voted +}; + +struct RemoteStorageEnumerateUserSharedWorkshopFilesResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 26 }; + EResult m_eResult; // The result of the operation. + int32 m_nResultsReturned; + int32 m_nTotalResultCount; + PublishedFileId_t m_rgPublishedFileId[ k_unEnumeratePublishedFilesMaxResults ]; +}; + +struct RemoteStorageSetUserPublishedFileActionResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 27 }; + EResult m_eResult; // The result of the operation. + PublishedFileId_t m_nPublishedFileId; // The published file id + EWorkshopFileAction m_eAction; // the action that was attempted +}; + +struct RemoteStorageEnumeratePublishedFilesByUserActionResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 28 }; + EResult m_eResult; // The result of the operation. + EWorkshopFileAction m_eAction; // the action that was filtered on + int32 m_nResultsReturned; + int32 m_nTotalResultCount; + PublishedFileId_t m_rgPublishedFileId[ k_unEnumeratePublishedFilesMaxResults ]; + uint32 m_rgRTimeUpdated[ k_unEnumeratePublishedFilesMaxResults ]; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Called periodically while a PublishWorkshopFile is in progress +//----------------------------------------------------------------------------- +struct RemoteStoragePublishFileProgress_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 29 }; + double m_dPercentFile; + bool m_bPreview; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Called when the content for a published file is updated +//----------------------------------------------------------------------------- +struct RemoteStoragePublishedFileUpdated_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 30 }; + PublishedFileId_t m_nPublishedFileId; // The published file id + AppId_t m_nAppID; // ID of the app that will consume this file. + uint64 m_ulUnused; // not used anymore +}; + +//----------------------------------------------------------------------------- +// Purpose: Called when a FileWriteAsync completes +//----------------------------------------------------------------------------- +struct RemoteStorageFileWriteAsyncComplete_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 31 }; + EResult m_eResult; // result +}; + +//----------------------------------------------------------------------------- +// Purpose: Called when a FileReadAsync completes +//----------------------------------------------------------------------------- +struct RemoteStorageFileReadAsyncComplete_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 32 }; + SteamAPICall_t m_hFileReadAsync; // call handle of the async read which was made + EResult m_eResult; // result + uint32 m_nOffset; // offset in the file this read was at + uint32 m_cubRead; // amount read - will the <= the amount requested +}; + +#pragma pack( pop ) + + +#endif // ISTEAMREMOTESTORAGE_H diff --git a/ScreenPlayWorkshop/ThirdParty/steam/isteamscreenshots.h b/ScreenPlayWorkshop/ThirdParty/steam/isteamscreenshots.h new file mode 100644 index 00000000..60957056 --- /dev/null +++ b/ScreenPlayWorkshop/ThirdParty/steam/isteamscreenshots.h @@ -0,0 +1,116 @@ +//====== Copyright � 1996-2008, Valve Corporation, All rights reserved. ======= +// +// Purpose: public interface to user remote file storage in Steam +// +//============================================================================= + +#ifndef ISTEAMSCREENSHOTS_H +#define ISTEAMSCREENSHOTS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isteamclient.h" + +const uint32 k_nScreenshotMaxTaggedUsers = 32; +const uint32 k_nScreenshotMaxTaggedPublishedFiles = 32; +const int k_cubUFSTagTypeMax = 255; +const int k_cubUFSTagValueMax = 255; + +// Required with of a thumbnail provided to AddScreenshotToLibrary. If you do not provide a thumbnail +// one will be generated. +const int k_ScreenshotThumbWidth = 200; + +// Handle is valid for the lifetime of your process and no longer +typedef uint32 ScreenshotHandle; +#define INVALID_SCREENSHOT_HANDLE 0 + +enum EVRScreenshotType +{ + k_EVRScreenshotType_None = 0, + k_EVRScreenshotType_Mono = 1, + k_EVRScreenshotType_Stereo = 2, + k_EVRScreenshotType_MonoCubemap = 3, + k_EVRScreenshotType_MonoPanorama = 4, + k_EVRScreenshotType_StereoPanorama = 5 +}; + +//----------------------------------------------------------------------------- +// Purpose: Functions for adding screenshots to the user's screenshot library +//----------------------------------------------------------------------------- +class ISteamScreenshots +{ +public: + // Writes a screenshot to the user's screenshot library given the raw image data, which must be in RGB format. + // The return value is a handle that is valid for the duration of the game process and can be used to apply tags. + virtual ScreenshotHandle WriteScreenshot( void *pubRGB, uint32 cubRGB, int nWidth, int nHeight ) = 0; + + // Adds a screenshot to the user's screenshot library from disk. If a thumbnail is provided, it must be 200 pixels wide and the same aspect ratio + // as the screenshot, otherwise a thumbnail will be generated if the user uploads the screenshot. The screenshots must be in either JPEG or TGA format. + // The return value is a handle that is valid for the duration of the game process and can be used to apply tags. + // JPEG, TGA, and PNG formats are supported. + virtual ScreenshotHandle AddScreenshotToLibrary( const char *pchFilename, const char *pchThumbnailFilename, int nWidth, int nHeight ) = 0; + + // Causes the Steam overlay to take a screenshot. If screenshots are being hooked by the game then a ScreenshotRequested_t callback is sent back to the game instead. + virtual void TriggerScreenshot() = 0; + + // Toggles whether the overlay handles screenshots when the user presses the screenshot hotkey, or the game handles them. If the game is hooking screenshots, + // then the ScreenshotRequested_t callback will be sent if the user presses the hotkey, and the game is expected to call WriteScreenshot or AddScreenshotToLibrary + // in response. + virtual void HookScreenshots( bool bHook ) = 0; + + // Sets metadata about a screenshot's location (for example, the name of the map) + virtual bool SetLocation( ScreenshotHandle hScreenshot, const char *pchLocation ) = 0; + + // Tags a user as being visible in the screenshot + virtual bool TagUser( ScreenshotHandle hScreenshot, CSteamID steamID ) = 0; + + // Tags a published file as being visible in the screenshot + virtual bool TagPublishedFile( ScreenshotHandle hScreenshot, PublishedFileId_t unPublishedFileID ) = 0; + + // Returns true if the app has hooked the screenshot + virtual bool IsScreenshotsHooked() = 0; + + // Adds a VR screenshot to the user's screenshot library from disk in the supported type. + // pchFilename should be the normal 2D image used in the library view + // pchVRFilename should contain the image that matches the correct type + // The return value is a handle that is valid for the duration of the game process and can be used to apply tags. + // JPEG, TGA, and PNG formats are supported. + virtual ScreenshotHandle AddVRScreenshotToLibrary( EVRScreenshotType eType, const char *pchFilename, const char *pchVRFilename ) = 0; +}; + +#define STEAMSCREENSHOTS_INTERFACE_VERSION "STEAMSCREENSHOTS_INTERFACE_VERSION003" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif +//----------------------------------------------------------------------------- +// Purpose: Screenshot successfully written or otherwise added to the library +// and can now be tagged +//----------------------------------------------------------------------------- +struct ScreenshotReady_t +{ + enum { k_iCallback = k_iSteamScreenshotsCallbacks + 1 }; + ScreenshotHandle m_hLocal; + EResult m_eResult; +}; + +//----------------------------------------------------------------------------- +// Purpose: Screenshot has been requested by the user. Only sent if +// HookScreenshots() has been called, in which case Steam will not take +// the screenshot itself. +//----------------------------------------------------------------------------- +struct ScreenshotRequested_t +{ + enum { k_iCallback = k_iSteamScreenshotsCallbacks + 2 }; +}; + +#pragma pack( pop ) + +#endif // ISTEAMSCREENSHOTS_H + diff --git a/ScreenPlayWorkshop/ThirdParty/steam/isteamugc.h b/ScreenPlayWorkshop/ThirdParty/steam/isteamugc.h new file mode 100644 index 00000000..4a7d2964 --- /dev/null +++ b/ScreenPlayWorkshop/ThirdParty/steam/isteamugc.h @@ -0,0 +1,545 @@ +//====== Copyright 1996-2013, Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to steam ugc +// +//============================================================================= + +#ifndef ISTEAMUGC_H +#define ISTEAMUGC_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isteamclient.h" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + + +typedef uint64 UGCQueryHandle_t; +typedef uint64 UGCUpdateHandle_t; + + +const UGCQueryHandle_t k_UGCQueryHandleInvalid = 0xffffffffffffffffull; +const UGCUpdateHandle_t k_UGCUpdateHandleInvalid = 0xffffffffffffffffull; + + +// Matching UGC types for queries +enum EUGCMatchingUGCType +{ + k_EUGCMatchingUGCType_Items = 0, // both mtx items and ready-to-use items + k_EUGCMatchingUGCType_Items_Mtx = 1, + k_EUGCMatchingUGCType_Items_ReadyToUse = 2, + k_EUGCMatchingUGCType_Collections = 3, + k_EUGCMatchingUGCType_Artwork = 4, + k_EUGCMatchingUGCType_Videos = 5, + k_EUGCMatchingUGCType_Screenshots = 6, + k_EUGCMatchingUGCType_AllGuides = 7, // both web guides and integrated guides + k_EUGCMatchingUGCType_WebGuides = 8, + k_EUGCMatchingUGCType_IntegratedGuides = 9, + k_EUGCMatchingUGCType_UsableInGame = 10, // ready-to-use items and integrated guides + k_EUGCMatchingUGCType_ControllerBindings = 11, + k_EUGCMatchingUGCType_GameManagedItems = 12, // game managed items (not managed by users) + k_EUGCMatchingUGCType_All = ~0, // return everything +}; + +// Different lists of published UGC for a user. +// If the current logged in user is different than the specified user, then some options may not be allowed. +enum EUserUGCList +{ + k_EUserUGCList_Published, + k_EUserUGCList_VotedOn, + k_EUserUGCList_VotedUp, + k_EUserUGCList_VotedDown, + k_EUserUGCList_WillVoteLater, + k_EUserUGCList_Favorited, + k_EUserUGCList_Subscribed, + k_EUserUGCList_UsedOrPlayed, + k_EUserUGCList_Followed, +}; + +// Sort order for user published UGC lists (defaults to creation order descending) +enum EUserUGCListSortOrder +{ + k_EUserUGCListSortOrder_CreationOrderDesc, + k_EUserUGCListSortOrder_CreationOrderAsc, + k_EUserUGCListSortOrder_TitleAsc, + k_EUserUGCListSortOrder_LastUpdatedDesc, + k_EUserUGCListSortOrder_SubscriptionDateDesc, + k_EUserUGCListSortOrder_VoteScoreDesc, + k_EUserUGCListSortOrder_ForModeration, +}; + +// Combination of sorting and filtering for queries across all UGC +enum EUGCQuery +{ + k_EUGCQuery_RankedByVote = 0, + k_EUGCQuery_RankedByPublicationDate = 1, + k_EUGCQuery_AcceptedForGameRankedByAcceptanceDate = 2, + k_EUGCQuery_RankedByTrend = 3, + k_EUGCQuery_FavoritedByFriendsRankedByPublicationDate = 4, + k_EUGCQuery_CreatedByFriendsRankedByPublicationDate = 5, + k_EUGCQuery_RankedByNumTimesReported = 6, + k_EUGCQuery_CreatedByFollowedUsersRankedByPublicationDate = 7, + k_EUGCQuery_NotYetRated = 8, + k_EUGCQuery_RankedByTotalVotesAsc = 9, + k_EUGCQuery_RankedByVotesUp = 10, + k_EUGCQuery_RankedByTextSearch = 11, + k_EUGCQuery_RankedByTotalUniqueSubscriptions = 12, + k_EUGCQuery_RankedByPlaytimeTrend = 13, + k_EUGCQuery_RankedByTotalPlaytime = 14, + k_EUGCQuery_RankedByAveragePlaytimeTrend = 15, + k_EUGCQuery_RankedByLifetimeAveragePlaytime = 16, + k_EUGCQuery_RankedByPlaytimeSessionsTrend = 17, + k_EUGCQuery_RankedByLifetimePlaytimeSessions = 18, +}; + +enum EItemUpdateStatus +{ + k_EItemUpdateStatusInvalid = 0, // The item update handle was invalid, job might be finished, listen too SubmitItemUpdateResult_t + k_EItemUpdateStatusPreparingConfig = 1, // The item update is processing configuration data + k_EItemUpdateStatusPreparingContent = 2, // The item update is reading and processing content files + k_EItemUpdateStatusUploadingContent = 3, // The item update is uploading content changes to Steam + k_EItemUpdateStatusUploadingPreviewFile = 4, // The item update is uploading new preview file image + k_EItemUpdateStatusCommittingChanges = 5 // The item update is committing all changes +}; + +enum EItemState +{ + k_EItemStateNone = 0, // item not tracked on client + k_EItemStateSubscribed = 1, // current user is subscribed to this item. Not just cached. + k_EItemStateLegacyItem = 2, // item was created with ISteamRemoteStorage + k_EItemStateInstalled = 4, // item is installed and usable (but maybe out of date) + k_EItemStateNeedsUpdate = 8, // items needs an update. Either because it's not installed yet or creator updated content + k_EItemStateDownloading = 16, // item update is currently downloading + k_EItemStateDownloadPending = 32, // DownloadItem() was called for this item, content isn't available until DownloadItemResult_t is fired +}; + +enum EItemStatistic +{ + k_EItemStatistic_NumSubscriptions = 0, + k_EItemStatistic_NumFavorites = 1, + k_EItemStatistic_NumFollowers = 2, + k_EItemStatistic_NumUniqueSubscriptions = 3, + k_EItemStatistic_NumUniqueFavorites = 4, + k_EItemStatistic_NumUniqueFollowers = 5, + k_EItemStatistic_NumUniqueWebsiteViews = 6, + k_EItemStatistic_ReportScore = 7, + k_EItemStatistic_NumSecondsPlayed = 8, + k_EItemStatistic_NumPlaytimeSessions = 9, + k_EItemStatistic_NumComments = 10, + k_EItemStatistic_NumSecondsPlayedDuringTimePeriod = 11, + k_EItemStatistic_NumPlaytimeSessionsDuringTimePeriod = 12, +}; + +enum EItemPreviewType +{ + k_EItemPreviewType_Image = 0, // standard image file expected (e.g. jpg, png, gif, etc.) + k_EItemPreviewType_YouTubeVideo = 1, // video id is stored + k_EItemPreviewType_Sketchfab = 2, // model id is stored + k_EItemPreviewType_EnvironmentMap_HorizontalCross = 3, // standard image file expected - cube map in the layout + // +---+---+-------+ + // | |Up | | + // +---+---+---+---+ + // | L | F | R | B | + // +---+---+---+---+ + // | |Dn | | + // +---+---+---+---+ + k_EItemPreviewType_EnvironmentMap_LatLong = 4, // standard image file expected + k_EItemPreviewType_ReservedMax = 255, // you can specify your own types above this value +}; + +const uint32 kNumUGCResultsPerPage = 50; +const uint32 k_cchDeveloperMetadataMax = 5000; + +// Details for a single published file/UGC +struct SteamUGCDetails_t +{ + PublishedFileId_t m_nPublishedFileId; + EResult m_eResult; // The result of the operation. + EWorkshopFileType m_eFileType; // Type of the file + AppId_t m_nCreatorAppID; // ID of the app that created this file. + AppId_t m_nConsumerAppID; // ID of the app that will consume this file. + char m_rgchTitle[k_cchPublishedDocumentTitleMax]; // title of document + char m_rgchDescription[k_cchPublishedDocumentDescriptionMax]; // description of document + uint64 m_ulSteamIDOwner; // Steam ID of the user who created this content. + uint32 m_rtimeCreated; // time when the published file was created + uint32 m_rtimeUpdated; // time when the published file was last updated + uint32 m_rtimeAddedToUserList; // time when the user added the published file to their list (not always applicable) + ERemoteStoragePublishedFileVisibility m_eVisibility; // visibility + bool m_bBanned; // whether the file was banned + bool m_bAcceptedForUse; // developer has specifically flagged this item as accepted in the Workshop + bool m_bTagsTruncated; // whether the list of tags was too long to be returned in the provided buffer + char m_rgchTags[k_cchTagListMax]; // comma separated list of all tags associated with this file + // file/url information + UGCHandle_t m_hFile; // The handle of the primary file + UGCHandle_t m_hPreviewFile; // The handle of the preview file + char m_pchFileName[k_cchFilenameMax]; // The cloud filename of the primary file + int32 m_nFileSize; // Size of the primary file + int32 m_nPreviewFileSize; // Size of the preview file + char m_rgchURL[k_cchPublishedFileURLMax]; // URL (for a video or a website) + // voting information + uint32 m_unVotesUp; // number of votes up + uint32 m_unVotesDown; // number of votes down + float m_flScore; // calculated score + // collection details + uint32 m_unNumChildren; +}; + +//----------------------------------------------------------------------------- +// Purpose: Steam UGC support API +//----------------------------------------------------------------------------- +class ISteamUGC +{ +public: + + // Query UGC associated with a user. Creator app id or consumer app id must be valid and be set to the current running app. unPage should start at 1. + virtual UGCQueryHandle_t CreateQueryUserUGCRequest( AccountID_t unAccountID, EUserUGCList eListType, EUGCMatchingUGCType eMatchingUGCType, EUserUGCListSortOrder eSortOrder, AppId_t nCreatorAppID, AppId_t nConsumerAppID, uint32 unPage ) = 0; + + // Query for all matching UGC. Creator app id or consumer app id must be valid and be set to the current running app. unPage should start at 1. + virtual UGCQueryHandle_t CreateQueryAllUGCRequest( EUGCQuery eQueryType, EUGCMatchingUGCType eMatchingeMatchingUGCTypeFileType, AppId_t nCreatorAppID, AppId_t nConsumerAppID, uint32 unPage ) = 0; + + // Query for the details of the given published file ids (the RequestUGCDetails call is deprecated and replaced with this) + virtual UGCQueryHandle_t CreateQueryUGCDetailsRequest( PublishedFileId_t *pvecPublishedFileID, uint32 unNumPublishedFileIDs ) = 0; + + // Send the query to Steam + CALL_RESULT( SteamUGCQueryCompleted_t ) + virtual SteamAPICall_t SendQueryUGCRequest( UGCQueryHandle_t handle ) = 0; + + // Retrieve an individual result after receiving the callback for querying UGC + virtual bool GetQueryUGCResult( UGCQueryHandle_t handle, uint32 index, SteamUGCDetails_t *pDetails ) = 0; + virtual bool GetQueryUGCPreviewURL( UGCQueryHandle_t handle, uint32 index, OUT_STRING_COUNT(cchURLSize) char *pchURL, uint32 cchURLSize ) = 0; + virtual bool GetQueryUGCMetadata( UGCQueryHandle_t handle, uint32 index, OUT_STRING_COUNT(cchMetadatasize) char *pchMetadata, uint32 cchMetadatasize ) = 0; + virtual bool GetQueryUGCChildren( UGCQueryHandle_t handle, uint32 index, PublishedFileId_t* pvecPublishedFileID, uint32 cMaxEntries ) = 0; + virtual bool GetQueryUGCStatistic( UGCQueryHandle_t handle, uint32 index, EItemStatistic eStatType, uint64 *pStatValue ) = 0; + virtual uint32 GetQueryUGCNumAdditionalPreviews( UGCQueryHandle_t handle, uint32 index ) = 0; + virtual bool GetQueryUGCAdditionalPreview( UGCQueryHandle_t handle, uint32 index, uint32 previewIndex, OUT_STRING_COUNT(cchURLSize) char *pchURLOrVideoID, uint32 cchURLSize, OUT_STRING_COUNT(cchURLSize) char *pchOriginalFileName, uint32 cchOriginalFileNameSize, EItemPreviewType *pPreviewType ) = 0; + virtual uint32 GetQueryUGCNumKeyValueTags( UGCQueryHandle_t handle, uint32 index ) = 0; + virtual bool GetQueryUGCKeyValueTag( UGCQueryHandle_t handle, uint32 index, uint32 keyValueTagIndex, OUT_STRING_COUNT(cchKeySize) char *pchKey, uint32 cchKeySize, OUT_STRING_COUNT(cchValueSize) char *pchValue, uint32 cchValueSize ) = 0; + + // Release the request to free up memory, after retrieving results + virtual bool ReleaseQueryUGCRequest( UGCQueryHandle_t handle ) = 0; + + // Options to set for querying UGC + virtual bool AddRequiredTag( UGCQueryHandle_t handle, const char *pTagName ) = 0; + virtual bool AddExcludedTag( UGCQueryHandle_t handle, const char *pTagName ) = 0; + virtual bool SetReturnOnlyIDs( UGCQueryHandle_t handle, bool bReturnOnlyIDs ) = 0; + virtual bool SetReturnKeyValueTags( UGCQueryHandle_t handle, bool bReturnKeyValueTags ) = 0; + virtual bool SetReturnLongDescription( UGCQueryHandle_t handle, bool bReturnLongDescription ) = 0; + virtual bool SetReturnMetadata( UGCQueryHandle_t handle, bool bReturnMetadata ) = 0; + virtual bool SetReturnChildren( UGCQueryHandle_t handle, bool bReturnChildren ) = 0; + virtual bool SetReturnAdditionalPreviews( UGCQueryHandle_t handle, bool bReturnAdditionalPreviews ) = 0; + virtual bool SetReturnTotalOnly( UGCQueryHandle_t handle, bool bReturnTotalOnly ) = 0; + virtual bool SetReturnPlaytimeStats( UGCQueryHandle_t handle, uint32 unDays ) = 0; + virtual bool SetLanguage( UGCQueryHandle_t handle, const char *pchLanguage ) = 0; + virtual bool SetAllowCachedResponse( UGCQueryHandle_t handle, uint32 unMaxAgeSeconds ) = 0; + + // Options only for querying user UGC + virtual bool SetCloudFileNameFilter( UGCQueryHandle_t handle, const char *pMatchCloudFileName ) = 0; + + // Options only for querying all UGC + virtual bool SetMatchAnyTag( UGCQueryHandle_t handle, bool bMatchAnyTag ) = 0; + virtual bool SetSearchText( UGCQueryHandle_t handle, const char *pSearchText ) = 0; + virtual bool SetRankedByTrendDays( UGCQueryHandle_t handle, uint32 unDays ) = 0; + virtual bool AddRequiredKeyValueTag( UGCQueryHandle_t handle, const char *pKey, const char *pValue ) = 0; + + // DEPRECATED - Use CreateQueryUGCDetailsRequest call above instead! + virtual SteamAPICall_t RequestUGCDetails( PublishedFileId_t nPublishedFileID, uint32 unMaxAgeSeconds ) = 0; + + // Steam Workshop Creator API + CALL_RESULT( CreateItemResult_t ) + virtual SteamAPICall_t CreateItem( AppId_t nConsumerAppId, EWorkshopFileType eFileType ) = 0; // create new item for this app with no content attached yet + + virtual UGCUpdateHandle_t StartItemUpdate( AppId_t nConsumerAppId, PublishedFileId_t nPublishedFileID ) = 0; // start an UGC item update. Set changed properties before commiting update with CommitItemUpdate() + + virtual bool SetItemTitle( UGCUpdateHandle_t handle, const char *pchTitle ) = 0; // change the title of an UGC item + virtual bool SetItemDescription( UGCUpdateHandle_t handle, const char *pchDescription ) = 0; // change the description of an UGC item + virtual bool SetItemUpdateLanguage( UGCUpdateHandle_t handle, const char *pchLanguage ) = 0; // specify the language of the title or description that will be set + virtual bool SetItemMetadata( UGCUpdateHandle_t handle, const char *pchMetaData ) = 0; // change the metadata of an UGC item (max = k_cchDeveloperMetadataMax) + virtual bool SetItemVisibility( UGCUpdateHandle_t handle, ERemoteStoragePublishedFileVisibility eVisibility ) = 0; // change the visibility of an UGC item + virtual bool SetItemTags( UGCUpdateHandle_t updateHandle, const SteamParamStringArray_t *pTags ) = 0; // change the tags of an UGC item + virtual bool SetItemContent( UGCUpdateHandle_t handle, const char *pszContentFolder ) = 0; // update item content from this local folder + virtual bool SetItemPreview( UGCUpdateHandle_t handle, const char *pszPreviewFile ) = 0; // change preview image file for this item. pszPreviewFile points to local image file, which must be under 1MB in size + virtual bool RemoveItemKeyValueTags( UGCUpdateHandle_t handle, const char *pchKey ) = 0; // remove any existing key-value tags with the specified key + virtual bool AddItemKeyValueTag( UGCUpdateHandle_t handle, const char *pchKey, const char *pchValue ) = 0; // add new key-value tags for the item. Note that there can be multiple values for a tag. + virtual bool AddItemPreviewFile( UGCUpdateHandle_t handle, const char *pszPreviewFile, EItemPreviewType type ) = 0; // add preview file for this item. pszPreviewFile points to local file, which must be under 1MB in size + virtual bool AddItemPreviewVideo( UGCUpdateHandle_t handle, const char *pszVideoID ) = 0; // add preview video for this item + virtual bool UpdateItemPreviewFile( UGCUpdateHandle_t handle, uint32 index, const char *pszPreviewFile ) = 0; // updates an existing preview file for this item. pszPreviewFile points to local file, which must be under 1MB in size + virtual bool UpdateItemPreviewVideo( UGCUpdateHandle_t handle, uint32 index, const char *pszVideoID ) = 0; // updates an existing preview video for this item + virtual bool RemoveItemPreview( UGCUpdateHandle_t handle, uint32 index ) = 0; // remove a preview by index starting at 0 (previews are sorted) + + CALL_RESULT( SubmitItemUpdateResult_t ) + virtual SteamAPICall_t SubmitItemUpdate( UGCUpdateHandle_t handle, const char *pchChangeNote ) = 0; // commit update process started with StartItemUpdate() + virtual EItemUpdateStatus GetItemUpdateProgress( UGCUpdateHandle_t handle, uint64 *punBytesProcessed, uint64* punBytesTotal ) = 0; + + // Steam Workshop Consumer API + CALL_RESULT( SetUserItemVoteResult_t ) + virtual SteamAPICall_t SetUserItemVote( PublishedFileId_t nPublishedFileID, bool bVoteUp ) = 0; + CALL_RESULT( GetUserItemVoteResult_t ) + virtual SteamAPICall_t GetUserItemVote( PublishedFileId_t nPublishedFileID ) = 0; + CALL_RESULT( UserFavoriteItemsListChanged_t ) + virtual SteamAPICall_t AddItemToFavorites( AppId_t nAppId, PublishedFileId_t nPublishedFileID ) = 0; + CALL_RESULT( UserFavoriteItemsListChanged_t ) + virtual SteamAPICall_t RemoveItemFromFavorites( AppId_t nAppId, PublishedFileId_t nPublishedFileID ) = 0; + CALL_RESULT( RemoteStorageSubscribePublishedFileResult_t ) + virtual SteamAPICall_t SubscribeItem( PublishedFileId_t nPublishedFileID ) = 0; // subscribe to this item, will be installed ASAP + CALL_RESULT( RemoteStorageUnsubscribePublishedFileResult_t ) + virtual SteamAPICall_t UnsubscribeItem( PublishedFileId_t nPublishedFileID ) = 0; // unsubscribe from this item, will be uninstalled after game quits + virtual uint32 GetNumSubscribedItems() = 0; // number of subscribed items + virtual uint32 GetSubscribedItems( PublishedFileId_t* pvecPublishedFileID, uint32 cMaxEntries ) = 0; // all subscribed item PublishFileIDs + + // get EItemState flags about item on this client + virtual uint32 GetItemState( PublishedFileId_t nPublishedFileID ) = 0; + + // get info about currently installed content on disc for items that have k_EItemStateInstalled set + // if k_EItemStateLegacyItem is set, pchFolder contains the path to the legacy file itself (not a folder) + virtual bool GetItemInstallInfo( PublishedFileId_t nPublishedFileID, uint64 *punSizeOnDisk, OUT_STRING_COUNT( cchFolderSize ) char *pchFolder, uint32 cchFolderSize, uint32 *punTimeStamp ) = 0; + + // get info about pending update for items that have k_EItemStateNeedsUpdate set. punBytesTotal will be valid after download started once + virtual bool GetItemDownloadInfo( PublishedFileId_t nPublishedFileID, uint64 *punBytesDownloaded, uint64 *punBytesTotal ) = 0; + + // download new or update already installed item. If function returns true, wait for DownloadItemResult_t. If the item is already installed, + // then files on disk should not be used until callback received. If item is not subscribed to, it will be cached for some time. + // If bHighPriority is set, any other item download will be suspended and this item downloaded ASAP. + virtual bool DownloadItem( PublishedFileId_t nPublishedFileID, bool bHighPriority ) = 0; + + // game servers can set a specific workshop folder before issuing any UGC commands. + // This is helpful if you want to support multiple game servers running out of the same install folder + virtual bool BInitWorkshopForGameServer( DepotId_t unWorkshopDepotID, const char *pszFolder ) = 0; + + // SuspendDownloads( true ) will suspend all workshop downloads until SuspendDownloads( false ) is called or the game ends + virtual void SuspendDownloads( bool bSuspend ) = 0; + + // usage tracking + CALL_RESULT( StartPlaytimeTrackingResult_t ) + virtual SteamAPICall_t StartPlaytimeTracking( PublishedFileId_t *pvecPublishedFileID, uint32 unNumPublishedFileIDs ) = 0; + CALL_RESULT( StopPlaytimeTrackingResult_t ) + virtual SteamAPICall_t StopPlaytimeTracking( PublishedFileId_t *pvecPublishedFileID, uint32 unNumPublishedFileIDs ) = 0; + CALL_RESULT( StopPlaytimeTrackingResult_t ) + virtual SteamAPICall_t StopPlaytimeTrackingForAllItems() = 0; + + // parent-child relationship or dependency management + CALL_RESULT( AddUGCDependencyResult_t ) + virtual SteamAPICall_t AddDependency( PublishedFileId_t nParentPublishedFileID, PublishedFileId_t nChildPublishedFileID ) = 0; + CALL_RESULT( RemoveUGCDependencyResult_t ) + virtual SteamAPICall_t RemoveDependency( PublishedFileId_t nParentPublishedFileID, PublishedFileId_t nChildPublishedFileID ) = 0; + + // add/remove app dependence/requirements (usually DLC) + CALL_RESULT( AddAppDependencyResult_t ) + virtual SteamAPICall_t AddAppDependency( PublishedFileId_t nPublishedFileID, AppId_t nAppID ) = 0; + CALL_RESULT( RemoveAppDependencyResult_t ) + virtual SteamAPICall_t RemoveAppDependency( PublishedFileId_t nPublishedFileID, AppId_t nAppID ) = 0; + // request app dependencies. note that whatever callback you register for GetAppDependenciesResult_t may be called multiple times + // until all app dependencies have been returned + CALL_RESULT( GetAppDependenciesResult_t ) + virtual SteamAPICall_t GetAppDependencies( PublishedFileId_t nPublishedFileID ) = 0; + + // delete the item without prompting the user + CALL_RESULT( DeleteItemResult_t ) + virtual SteamAPICall_t DeleteItem( PublishedFileId_t nPublishedFileID ) = 0; +}; + +#define STEAMUGC_INTERFACE_VERSION "STEAMUGC_INTERFACE_VERSION010" + +//----------------------------------------------------------------------------- +// Purpose: Callback for querying UGC +//----------------------------------------------------------------------------- +struct SteamUGCQueryCompleted_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 1 }; + UGCQueryHandle_t m_handle; + EResult m_eResult; + uint32 m_unNumResultsReturned; + uint32 m_unTotalMatchingResults; + bool m_bCachedData; // indicates whether this data was retrieved from the local on-disk cache +}; + + +//----------------------------------------------------------------------------- +// Purpose: Callback for requesting details on one piece of UGC +//----------------------------------------------------------------------------- +struct SteamUGCRequestUGCDetailsResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 2 }; + SteamUGCDetails_t m_details; + bool m_bCachedData; // indicates whether this data was retrieved from the local on-disk cache +}; + + +//----------------------------------------------------------------------------- +// Purpose: result for ISteamUGC::CreateItem() +//----------------------------------------------------------------------------- +struct CreateItemResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 3 }; + EResult m_eResult; + PublishedFileId_t m_nPublishedFileId; // new item got this UGC PublishFileID + bool m_bUserNeedsToAcceptWorkshopLegalAgreement; +}; + + +//----------------------------------------------------------------------------- +// Purpose: result for ISteamUGC::SubmitItemUpdate() +//----------------------------------------------------------------------------- +struct SubmitItemUpdateResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 4 }; + EResult m_eResult; + bool m_bUserNeedsToAcceptWorkshopLegalAgreement; + PublishedFileId_t m_nPublishedFileId; +}; + + +//----------------------------------------------------------------------------- +// Purpose: a Workshop item has been installed or updated +//----------------------------------------------------------------------------- +struct ItemInstalled_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 5 }; + AppId_t m_unAppID; + PublishedFileId_t m_nPublishedFileId; +}; + + +//----------------------------------------------------------------------------- +// Purpose: result of DownloadItem(), existing item files can be accessed again +//----------------------------------------------------------------------------- +struct DownloadItemResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 6 }; + AppId_t m_unAppID; + PublishedFileId_t m_nPublishedFileId; + EResult m_eResult; +}; + +//----------------------------------------------------------------------------- +// Purpose: result of AddItemToFavorites() or RemoveItemFromFavorites() +//----------------------------------------------------------------------------- +struct UserFavoriteItemsListChanged_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 7 }; + PublishedFileId_t m_nPublishedFileId; + EResult m_eResult; + bool m_bWasAddRequest; +}; + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to SetUserItemVote() +//----------------------------------------------------------------------------- +struct SetUserItemVoteResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 8 }; + PublishedFileId_t m_nPublishedFileId; + EResult m_eResult; + bool m_bVoteUp; +}; + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to GetUserItemVote() +//----------------------------------------------------------------------------- +struct GetUserItemVoteResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 9 }; + PublishedFileId_t m_nPublishedFileId; + EResult m_eResult; + bool m_bVotedUp; + bool m_bVotedDown; + bool m_bVoteSkipped; +}; + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to StartPlaytimeTracking() +//----------------------------------------------------------------------------- +struct StartPlaytimeTrackingResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 10 }; + EResult m_eResult; +}; + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to StopPlaytimeTracking() +//----------------------------------------------------------------------------- +struct StopPlaytimeTrackingResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 11 }; + EResult m_eResult; +}; + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to AddDependency +//----------------------------------------------------------------------------- +struct AddUGCDependencyResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 12 }; + EResult m_eResult; + PublishedFileId_t m_nPublishedFileId; + PublishedFileId_t m_nChildPublishedFileId; +}; + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to RemoveDependency +//----------------------------------------------------------------------------- +struct RemoveUGCDependencyResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 13 }; + EResult m_eResult; + PublishedFileId_t m_nPublishedFileId; + PublishedFileId_t m_nChildPublishedFileId; +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to AddAppDependency +//----------------------------------------------------------------------------- +struct AddAppDependencyResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 14 }; + EResult m_eResult; + PublishedFileId_t m_nPublishedFileId; + AppId_t m_nAppID; +}; + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to RemoveAppDependency +//----------------------------------------------------------------------------- +struct RemoveAppDependencyResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 15 }; + EResult m_eResult; + PublishedFileId_t m_nPublishedFileId; + AppId_t m_nAppID; +}; + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to GetAppDependencies. Callback may be called +// multiple times until all app dependencies have been returned. +//----------------------------------------------------------------------------- +struct GetAppDependenciesResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 16 }; + EResult m_eResult; + PublishedFileId_t m_nPublishedFileId; + AppId_t m_rgAppIDs[32]; + uint32 m_nNumAppDependencies; // number returned in this struct + uint32 m_nTotalNumAppDependencies; // total found +}; + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to DeleteItem +//----------------------------------------------------------------------------- +struct DeleteItemResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 17 }; + EResult m_eResult; + PublishedFileId_t m_nPublishedFileId; +}; + +#pragma pack( pop ) + +#endif // ISTEAMUGC_H diff --git a/ScreenPlayWorkshop/ThirdParty/steam/isteamunifiedmessages.h b/ScreenPlayWorkshop/ThirdParty/steam/isteamunifiedmessages.h new file mode 100644 index 00000000..684f4e87 --- /dev/null +++ b/ScreenPlayWorkshop/ThirdParty/steam/isteamunifiedmessages.h @@ -0,0 +1,63 @@ +//====== Copyright � 1996-2007, Valve Corporation, All rights reserved. ======= +// +// Purpose: Interface to unified messages client +// +// You should not need to use this interface except if your product is using a language other than C++. +// Contact your Steam Tech contact for more details. +// +//============================================================================= + +#ifndef ISTEAMUNIFIEDMESSAGES_H +#define ISTEAMUNIFIEDMESSAGES_H +#ifdef _WIN32 +#pragma once +#endif + +typedef uint64 ClientUnifiedMessageHandle; + +class ISteamUnifiedMessages +{ +public: + static const ClientUnifiedMessageHandle k_InvalidUnifiedMessageHandle = 0; + + // Sends a service method (in binary serialized form) using the Steam Client. + // Returns a unified message handle (k_InvalidUnifiedMessageHandle if could not send the message). + virtual ClientUnifiedMessageHandle SendMethod( const char *pchServiceMethod, const void *pRequestBuffer, uint32 unRequestBufferSize, uint64 unContext ) = 0; + + // Gets the size of the response and the EResult. Returns false if the response is not ready yet. + virtual bool GetMethodResponseInfo( ClientUnifiedMessageHandle hHandle, uint32 *punResponseSize, EResult *peResult ) = 0; + + // Gets a response in binary serialized form (and optionally release the corresponding allocated memory). + virtual bool GetMethodResponseData( ClientUnifiedMessageHandle hHandle, void *pResponseBuffer, uint32 unResponseBufferSize, bool bAutoRelease ) = 0; + + // Releases the message and its corresponding allocated memory. + virtual bool ReleaseMethod( ClientUnifiedMessageHandle hHandle ) = 0; + + // Sends a service notification (in binary serialized form) using the Steam Client. + // Returns true if the notification was sent successfully. + virtual bool SendNotification( const char *pchServiceNotification, const void *pNotificationBuffer, uint32 unNotificationBufferSize ) = 0; +}; + +#define STEAMUNIFIEDMESSAGES_INTERFACE_VERSION "STEAMUNIFIEDMESSAGES_INTERFACE_VERSION001" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + +struct SteamUnifiedMessagesSendMethodResult_t +{ + enum { k_iCallback = k_iClientUnifiedMessagesCallbacks + 1 }; + ClientUnifiedMessageHandle m_hHandle; // The handle returned by SendMethod(). + uint64 m_unContext; // Context provided when calling SendMethod(). + EResult m_eResult; // The result of the method call. + uint32 m_unResponseSize; // The size of the response. +}; + +#pragma pack( pop ) + +#endif // ISTEAMUNIFIEDMESSAGES_H diff --git a/ScreenPlayWorkshop/ThirdParty/steam/isteamuser.h b/ScreenPlayWorkshop/ThirdParty/steam/isteamuser.h new file mode 100644 index 00000000..0ea2bb82 --- /dev/null +++ b/ScreenPlayWorkshop/ThirdParty/steam/isteamuser.h @@ -0,0 +1,369 @@ +//====== Copyright (c) 1996-2008, Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to user account information in Steam +// +//============================================================================= + +#ifndef ISTEAMUSER_H +#define ISTEAMUSER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isteamclient.h" + +// structure that contains client callback data +// see callbacks documentation for more details +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif +struct CallbackMsg_t +{ + HSteamUser m_hSteamUser; + int m_iCallback; + uint8 *m_pubParam; + int m_cubParam; +}; +#pragma pack( pop ) + + +//----------------------------------------------------------------------------- +// Purpose: Functions for accessing and manipulating a steam account +// associated with one client instance +//----------------------------------------------------------------------------- +class ISteamUser +{ +public: + // returns the HSteamUser this interface represents + // this is only used internally by the API, and by a few select interfaces that support multi-user + virtual HSteamUser GetHSteamUser() = 0; + + // 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. + virtual bool BLoggedOn() = 0; + + // 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 + virtual CSteamID GetSteamID() = 0; + + // 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. + virtual int InitiateGameConnection( void *pAuthBlob, int cbMaxAuthBlob, CSteamID steamIDGameServer, uint32 unIPServer, uint16 usPortServer, bool bSecure ) = 0; + + // notify of disconnect + // needs to occur when the game client leaves the specified game server, needs to match with the InitiateGameConnection() call + virtual void TerminateGameConnection( uint32 unIPServer, uint16 usPortServer ) = 0; + + // Legacy functions + + // used by only a few games to track usage events + virtual void TrackAppUsageEvent( CGameID gameID, int eAppUsageEvent, const char *pchExtraInfo = "" ) = 0; + + // 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" + virtual bool GetUserDataFolder( char *pchBuffer, int cubBuffer ) = 0; + + // Starts voice recording. Once started, use GetVoice() to get the data + virtual void StartVoiceRecording( ) = 0; + + // 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 + virtual void StopVoiceRecording( ) = 0; + + // 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. + virtual EVoiceResult GetAvailableVoice( uint32 *pcbCompressed, uint32 *pcbUncompressed_Deprecated = 0, uint32 nUncompressedVoiceDesiredSampleRate_Deprecated = 0 ) = 0; + + // --------------------------------------------------------------------------- + // 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. + virtual EVoiceResult GetVoice( bool bWantCompressed, void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten, bool bWantUncompressed_Deprecated = false, void *pUncompressedDestBuffer_Deprecated = 0, uint32 cbUncompressedDestBufferSize_Deprecated = 0, uint32 *nUncompressBytesWritten_Deprecated = 0, uint32 nUncompressedVoiceDesiredSampleRate_Deprecated = 0 ) = 0; + + // 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. + virtual EVoiceResult DecompressVoice( const void *pCompressed, uint32 cbCompressed, void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten, uint32 nDesiredSampleRate ) = 0; + + // This returns the native sample rate of the Steam voice decompressor; using + // 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. + virtual uint32 GetVoiceOptimalSampleRate() = 0; + + // Retrieve ticket to be sent to the entity who wishes to authenticate you. + // pcbTicket retrieves the length of the actual ticket. + virtual HAuthTicket GetAuthSessionTicket( void *pTicket, int cbMaxTicket, uint32 *pcbTicket ) = 0; + + // 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 ) + virtual EBeginAuthSessionResult BeginAuthSession( const void *pAuthTicket, int cbAuthTicket, CSteamID steamID ) = 0; + + // Stop tracking started by BeginAuthSession - called when no longer playing game with this entity + virtual void EndAuthSession( CSteamID steamID ) = 0; + + // Cancel auth ticket from GetAuthSessionTicket, called when no longer playing game with the entity you gave the ticket to + virtual void CancelAuthTicket( HAuthTicket hAuthTicket ) = 0; + + // 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. + virtual EUserHasLicenseForAppResult UserHasLicenseForApp( CSteamID steamID, AppId_t appID ) = 0; + + // 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. + virtual bool BIsBehindNAT() = 0; + + // 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 + virtual void AdvertiseGame( CSteamID steamIDGameServer, uint32 unIPServer, uint16 usPortServer ) = 0; + + // 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 ) + CALL_RESULT( EncryptedAppTicketResponse_t ) + virtual SteamAPICall_t RequestEncryptedAppTicket( void *pDataToInclude, int cbDataToInclude ) = 0; + + // retrieve a finished ticket + virtual bool GetEncryptedAppTicket( void *pTicket, int cbMaxTicket, uint32 *pcbTicket ) = 0; + + // 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) + virtual int GetGameBadgeLevel( int nSeries, bool bFoil ) = 0; + + // gets the Steam Level of the user, as shown on their profile + virtual int GetPlayerSteamLevel() = 0; + + // 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. + CALL_RESULT( StoreAuthURLResponse_t ) + virtual SteamAPICall_t RequestStoreAuthURL( const char *pchRedirectURL ) = 0; + + // gets whether the users phone number is verified + virtual bool BIsPhoneVerified() = 0; + + // gets whether the user has two factor enabled on their account + virtual bool BIsTwoFactorEnabled() = 0; + + // gets whether the users phone number is identifying + virtual bool BIsPhoneIdentifying() = 0; + + // gets whether the users phone number is awaiting (re)verification + virtual bool BIsPhoneRequiringVerification() = 0; + +}; + +#define STEAMUSER_INTERFACE_VERSION "SteamUser019" + + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + +//----------------------------------------------------------------------------- +// Purpose: called when a connections to the Steam back-end has been established +// this means the Steam client now has a working connection to the Steam servers +// usually this will have occurred before the game has launched, and should +// only be seen if the user has dropped connection due to a networking issue +// or a Steam server update +//----------------------------------------------------------------------------- +struct SteamServersConnected_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 1 }; +}; + +//----------------------------------------------------------------------------- +// Purpose: called when a connection attempt has failed +// this will occur periodically if the Steam client is not connected, +// and has failed in it's retry to establish a connection +//----------------------------------------------------------------------------- +struct SteamServerConnectFailure_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 2 }; + EResult m_eResult; + bool m_bStillRetrying; +}; + + +//----------------------------------------------------------------------------- +// Purpose: called if the client has lost connection to the Steam servers +// real-time services will be disabled until a matching SteamServersConnected_t has been posted +//----------------------------------------------------------------------------- +struct SteamServersDisconnected_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 3 }; + EResult m_eResult; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Sent by the Steam server to the client telling it to disconnect from the specified game server, +// which it may be in the process of or already connected to. +// The game client should immediately disconnect upon receiving this message. +// This can usually occur if the user doesn't have rights to play on the game server. +//----------------------------------------------------------------------------- +struct ClientGameServerDeny_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 13 }; + + uint32 m_uAppID; + uint32 m_unGameServerIP; + uint16 m_usGameServerPort; + uint16 m_bSecure; + uint32 m_uReason; +}; + + +//----------------------------------------------------------------------------- +// Purpose: called when the callback system for this client is in an error state (and has flushed pending callbacks) +// When getting this message the client should disconnect from Steam, reset any stored Steam state and reconnect. +// This usually occurs in the rare event the Steam client has some kind of fatal error. +//----------------------------------------------------------------------------- +struct IPCFailure_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 17 }; + enum EFailureType + { + k_EFailureFlushedCallbackQueue, + k_EFailurePipeFail, + }; + uint8 m_eFailureType; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Signaled whenever licenses change +//----------------------------------------------------------------------------- +struct LicensesUpdated_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 25 }; +}; + + +//----------------------------------------------------------------------------- +// callback for BeginAuthSession +//----------------------------------------------------------------------------- +struct ValidateAuthTicketResponse_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 43 }; + CSteamID m_SteamID; + EAuthSessionResponse m_eAuthSessionResponse; + CSteamID m_OwnerSteamID; // different from m_SteamID if borrowed +}; + + +//----------------------------------------------------------------------------- +// Purpose: called when a user has responded to a microtransaction authorization request +//----------------------------------------------------------------------------- +struct MicroTxnAuthorizationResponse_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 52 }; + + uint32 m_unAppID; // AppID for this microtransaction + uint64 m_ulOrderID; // OrderID provided for the microtransaction + uint8 m_bAuthorized; // if user authorized transaction +}; + + +//----------------------------------------------------------------------------- +// Purpose: Result from RequestEncryptedAppTicket +//----------------------------------------------------------------------------- +struct EncryptedAppTicketResponse_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 54 }; + + EResult m_eResult; +}; + +//----------------------------------------------------------------------------- +// callback for GetAuthSessionTicket +//----------------------------------------------------------------------------- +struct GetAuthSessionTicketResponse_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 63 }; + HAuthTicket m_hAuthTicket; + EResult m_eResult; +}; + + +//----------------------------------------------------------------------------- +// Purpose: sent to your game in response to a steam://gamewebcallback/ command +//----------------------------------------------------------------------------- +struct GameWebCallback_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 64 }; + char m_szURL[256]; +}; + +//----------------------------------------------------------------------------- +// Purpose: sent to your game in response to ISteamUser::RequestStoreAuthURL +//----------------------------------------------------------------------------- +struct StoreAuthURLResponse_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 65 }; + char m_szURL[512]; +}; + + + +#pragma pack( pop ) + +#endif // ISTEAMUSER_H diff --git a/ScreenPlayWorkshop/ThirdParty/steam/isteamuserstats.h b/ScreenPlayWorkshop/ThirdParty/steam/isteamuserstats.h new file mode 100644 index 00000000..29ae38ba --- /dev/null +++ b/ScreenPlayWorkshop/ThirdParty/steam/isteamuserstats.h @@ -0,0 +1,476 @@ +//====== Copyright � 1996-2009, Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to stats, achievements, and leaderboards +// +//============================================================================= + +#ifndef ISTEAMUSERSTATS_H +#define ISTEAMUSERSTATS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isteamclient.h" +#include "isteamremotestorage.h" + +// size limit on stat or achievement name (UTF-8 encoded) +enum { k_cchStatNameMax = 128 }; + +// maximum number of bytes for a leaderboard name (UTF-8 encoded) +enum { k_cchLeaderboardNameMax = 128 }; + +// maximum number of details int32's storable for a single leaderboard entry +enum { k_cLeaderboardDetailsMax = 64 }; + +// handle to a single leaderboard +typedef uint64 SteamLeaderboard_t; + +// handle to a set of downloaded entries in a leaderboard +typedef uint64 SteamLeaderboardEntries_t; + +// type of data request, when downloading leaderboard entries +enum ELeaderboardDataRequest +{ + k_ELeaderboardDataRequestGlobal = 0, + k_ELeaderboardDataRequestGlobalAroundUser = 1, + k_ELeaderboardDataRequestFriends = 2, + k_ELeaderboardDataRequestUsers = 3 +}; + +// the sort order of a leaderboard +enum ELeaderboardSortMethod +{ + k_ELeaderboardSortMethodNone = 0, + k_ELeaderboardSortMethodAscending = 1, // top-score is lowest number + k_ELeaderboardSortMethodDescending = 2, // top-score is highest number +}; + +// the display type (used by the Steam Community web site) for a leaderboard +enum ELeaderboardDisplayType +{ + k_ELeaderboardDisplayTypeNone = 0, + k_ELeaderboardDisplayTypeNumeric = 1, // simple numerical score + k_ELeaderboardDisplayTypeTimeSeconds = 2, // the score represents a time, in seconds + k_ELeaderboardDisplayTypeTimeMilliSeconds = 3, // the score represents a time, in milliseconds +}; + +enum ELeaderboardUploadScoreMethod +{ + k_ELeaderboardUploadScoreMethodNone = 0, + k_ELeaderboardUploadScoreMethodKeepBest = 1, // Leaderboard will keep user's best score + k_ELeaderboardUploadScoreMethodForceUpdate = 2, // Leaderboard will always replace score with specified +}; + +// a single entry in a leaderboard, as returned by GetDownloadedLeaderboardEntry() +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + +struct LeaderboardEntry_t +{ + CSteamID m_steamIDUser; // user with the entry - use SteamFriends()->GetFriendPersonaName() & SteamFriends()->GetFriendAvatar() to get more info + int32 m_nGlobalRank; // [1..N], where N is the number of users with an entry in the leaderboard + int32 m_nScore; // score as set in the leaderboard + int32 m_cDetails; // number of int32 details available for this entry + UGCHandle_t m_hUGC; // handle for UGC attached to the entry +}; + +#pragma pack( pop ) + + +//----------------------------------------------------------------------------- +// Purpose: Functions for accessing stats, achievements, and leaderboard information +//----------------------------------------------------------------------------- +class ISteamUserStats +{ +public: + // Ask the server to send down this user's data and achievements for this game + CALL_BACK( UserStatsReceived_t ) + virtual bool RequestCurrentStats() = 0; + + // Data accessors + virtual bool GetStat( const char *pchName, int32 *pData ) = 0; + virtual bool GetStat( const char *pchName, float *pData ) = 0; + + // Set / update data + virtual bool SetStat( const char *pchName, int32 nData ) = 0; + virtual bool SetStat( const char *pchName, float fData ) = 0; + virtual bool UpdateAvgRateStat( const char *pchName, float flCountThisSession, double dSessionLength ) = 0; + + // Achievement flag accessors + virtual bool GetAchievement( const char *pchName, bool *pbAchieved ) = 0; + virtual bool SetAchievement( const char *pchName ) = 0; + virtual bool ClearAchievement( const char *pchName ) = 0; + + // 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. + virtual bool GetAchievementAndUnlockTime( const char *pchName, bool *pbAchieved, uint32 *punUnlockTime ) = 0; + + // 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. + virtual bool StoreStats() = 0; + + // 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. + virtual int GetAchievementIcon( const char *pchName ) = 0; + + // 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) + virtual const char *GetAchievementDisplayAttribute( const char *pchName, const char *pchKey ) = 0; + + // 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. + virtual bool IndicateAchievementProgress( const char *pchName, uint32 nCurProgress, uint32 nMaxProgress ) = 0; + + // Used for iterating achievements. In general games should not need these functions because they should have a + // list of existing achievements compiled into them + virtual uint32 GetNumAchievements() = 0; + // Get achievement name iAchievement in [0,GetNumAchievements) + virtual const char *GetAchievementName( uint32 iAchievement ) = 0; + + // 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 + CALL_RESULT( UserStatsReceived_t ) + virtual SteamAPICall_t RequestUserStats( CSteamID steamIDUser ) = 0; + + // requests stat information for a user, usable after a successful call to RequestUserStats() + virtual bool GetUserStat( CSteamID steamIDUser, const char *pchName, int32 *pData ) = 0; + virtual bool GetUserStat( CSteamID steamIDUser, const char *pchName, float *pData ) = 0; + virtual bool GetUserAchievement( CSteamID steamIDUser, const char *pchName, bool *pbAchieved ) = 0; + // See notes for GetAchievementAndUnlockTime above + virtual bool GetUserAchievementAndUnlockTime( CSteamID steamIDUser, const char *pchName, bool *pbAchieved, uint32 *punUnlockTime ) = 0; + + // Reset stats + virtual bool ResetAllStats( bool bAchievementsToo ) = 0; + + // 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 + CALL_RESULT(LeaderboardFindResult_t) + virtual SteamAPICall_t FindOrCreateLeaderboard( const char *pchLeaderboardName, ELeaderboardSortMethod eLeaderboardSortMethod, ELeaderboardDisplayType eLeaderboardDisplayType ) = 0; + + // as above, but won't create the leaderboard if it's not found + // This call is asynchronous, with the result returned in LeaderboardFindResult_t + CALL_RESULT( LeaderboardFindResult_t ) + virtual SteamAPICall_t FindLeaderboard( const char *pchLeaderboardName ) = 0; + + // returns the name of a leaderboard + virtual const char *GetLeaderboardName( SteamLeaderboard_t hSteamLeaderboard ) = 0; + + // returns the total number of entries in a leaderboard, as of the last request + virtual int GetLeaderboardEntryCount( SteamLeaderboard_t hSteamLeaderboard ) = 0; + + // returns the sort method of the leaderboard + virtual ELeaderboardSortMethod GetLeaderboardSortMethod( SteamLeaderboard_t hSteamLeaderboard ) = 0; + + // returns the display type of the leaderboard + virtual ELeaderboardDisplayType GetLeaderboardDisplayType( SteamLeaderboard_t hSteamLeaderboard ) = 0; + + // 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 + CALL_RESULT( LeaderboardScoresDownloaded_t ) + virtual SteamAPICall_t DownloadLeaderboardEntries( SteamLeaderboard_t hSteamLeaderboard, ELeaderboardDataRequest eLeaderboardDataRequest, int nRangeStart, int nRangeEnd ) = 0; + // 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 + METHOD_DESC(Downloads leaderboard entries for an arbitrary set of users - ELeaderboardDataRequest is k_ELeaderboardDataRequestUsers) + CALL_RESULT( LeaderboardScoresDownloaded_t ) + virtual SteamAPICall_t DownloadLeaderboardEntriesForUsers( SteamLeaderboard_t hSteamLeaderboard, + ARRAY_COUNT_D(cUsers, Array of users to retrieve) CSteamID *prgUsers, int cUsers ) = 0; + + // 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 + virtual bool GetDownloadedLeaderboardEntry( SteamLeaderboardEntries_t hSteamLeaderboardEntries, int index, LeaderboardEntry_t *pLeaderboardEntry, int32 *pDetails, int cDetailsMax ) = 0; + + // 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 + CALL_RESULT( LeaderboardScoreUploaded_t ) + virtual SteamAPICall_t UploadLeaderboardScore( SteamLeaderboard_t hSteamLeaderboard, ELeaderboardUploadScoreMethod eLeaderboardUploadScoreMethod, int32 nScore, const int32 *pScoreDetails, int cScoreDetailsCount ) = 0; + + // 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. + CALL_RESULT( LeaderboardUGCSet_t ) + virtual SteamAPICall_t AttachLeaderboardUGC( SteamLeaderboard_t hSteamLeaderboard, UGCHandle_t hUGC ) = 0; + + // Retrieves the number of players currently playing your game (online + offline) + // This call is asynchronous, with the result returned in NumberOfCurrentPlayers_t + CALL_RESULT( NumberOfCurrentPlayers_t ) + virtual SteamAPICall_t GetNumberOfCurrentPlayers() = 0; + + // 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. + CALL_RESULT( GlobalAchievementPercentagesReady_t ) + virtual SteamAPICall_t RequestGlobalAchievementPercentages() = 0; + + // 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). + virtual int GetMostAchievedAchievementInfo( char *pchName, uint32 unNameBufLen, float *pflPercent, bool *pbAchieved ) = 0; + + // 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. + virtual int GetNextMostAchievedAchievementInfo( int iIteratorPrevious, char *pchName, uint32 unNameBufLen, float *pflPercent, bool *pbAchieved ) = 0; + + // Returns the percentage of users who have achieved the specified achievement. + virtual bool GetAchievementAchievedPercent( const char *pchName, float *pflPercent ) = 0; + + // 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. + CALL_RESULT( GlobalStatsReceived_t ) + virtual SteamAPICall_t RequestGlobalStats( int nHistoryDays ) = 0; + + // Gets the lifetime totals for an aggregated stat + virtual bool GetGlobalStat( const char *pchStatName, int64 *pData ) = 0; + virtual bool GetGlobalStat( const char *pchStatName, double *pData ) = 0; + + // 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. + virtual int32 GetGlobalStatHistory( const char *pchStatName, ARRAY_COUNT(cubData) int64 *pData, uint32 cubData ) = 0; + virtual int32 GetGlobalStatHistory( const char *pchStatName, ARRAY_COUNT(cubData) double *pData, uint32 cubData ) = 0; + +#ifdef _PS3 + // Call to kick off installation of the PS3 trophies. This call is asynchronous, and the results will be returned in a PS3TrophiesInstalled_t + // callback. + virtual bool InstallPS3Trophies() = 0; + + // Returns the amount of space required at boot to install trophies. This value can be used when comparing the amount of space needed + // by the game to the available space value passed to the game at boot. The value is set during InstallPS3Trophies(). + virtual uint64 GetTrophySpaceRequiredBeforeInstall() = 0; + + // On PS3, user stats & achievement progress through Steam must be stored with the user's saved game data. + // At startup, before calling RequestCurrentStats(), you must pass the user's stats data to Steam via this method. + // If you do not have any user data, call this function with pvData = NULL and cubData = 0 + virtual bool SetUserStatsData( const void *pvData, uint32 cubData ) = 0; + + // Call to get the user's current stats data. You should retrieve this data after receiving successful UserStatsReceived_t & UserStatsStored_t + // callbacks, and store the data with the user's save game data. You can call this method with pvData = NULL and cubData = 0 to get the required + // buffer size. + virtual bool GetUserStatsData( void *pvData, uint32 cubData, uint32 *pcubWritten ) = 0; +#endif +}; + +#define STEAMUSERSTATS_INTERFACE_VERSION "STEAMUSERSTATS_INTERFACE_VERSION011" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + +//----------------------------------------------------------------------------- +// Purpose: called when the latests stats and achievements have been received +// from the server +//----------------------------------------------------------------------------- +struct UserStatsReceived_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 1 }; + uint64 m_nGameID; // Game these stats are for + EResult m_eResult; // Success / error fetching the stats + CSteamID m_steamIDUser; // The user for whom the stats are retrieved for +}; + + +//----------------------------------------------------------------------------- +// Purpose: result of a request to store the user stats for a game +//----------------------------------------------------------------------------- +struct UserStatsStored_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 2 }; + uint64 m_nGameID; // Game these stats are for + EResult m_eResult; // success / error +}; + + +//----------------------------------------------------------------------------- +// Purpose: result of a request to store the achievements for a game, or an +// "indicate progress" call. If both m_nCurProgress and m_nMaxProgress +// are zero, that means the achievement has been fully unlocked. +//----------------------------------------------------------------------------- +struct UserAchievementStored_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 3 }; + + uint64 m_nGameID; // Game this is for + bool m_bGroupAchievement; // if this is a "group" achievement + char m_rgchAchievementName[k_cchStatNameMax]; // name of the achievement + uint32 m_nCurProgress; // current progress towards the achievement + uint32 m_nMaxProgress; // "out of" this many +}; + + +//----------------------------------------------------------------------------- +// Purpose: call result for finding a leaderboard, returned as a result of FindOrCreateLeaderboard() or FindLeaderboard() +// use CCallResult<> to map this async result to a member function +//----------------------------------------------------------------------------- +struct LeaderboardFindResult_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 4 }; + SteamLeaderboard_t m_hSteamLeaderboard; // handle to the leaderboard serarched for, 0 if no leaderboard found + uint8 m_bLeaderboardFound; // 0 if no leaderboard found +}; + + +//----------------------------------------------------------------------------- +// Purpose: call result indicating scores for a leaderboard have been downloaded and are ready to be retrieved, returned as a result of DownloadLeaderboardEntries() +// use CCallResult<> to map this async result to a member function +//----------------------------------------------------------------------------- +struct LeaderboardScoresDownloaded_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 5 }; + SteamLeaderboard_t m_hSteamLeaderboard; + SteamLeaderboardEntries_t m_hSteamLeaderboardEntries; // the handle to pass into GetDownloadedLeaderboardEntries() + int m_cEntryCount; // the number of entries downloaded +}; + + +//----------------------------------------------------------------------------- +// Purpose: call result indicating scores has been uploaded, returned as a result of UploadLeaderboardScore() +// use CCallResult<> to map this async result to a member function +//----------------------------------------------------------------------------- +struct LeaderboardScoreUploaded_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 6 }; + uint8 m_bSuccess; // 1 if the call was successful + SteamLeaderboard_t m_hSteamLeaderboard; // the leaderboard handle that was + int32 m_nScore; // the score that was attempted to set + uint8 m_bScoreChanged; // true if the score in the leaderboard change, false if the existing score was better + int m_nGlobalRankNew; // the new global rank of the user in this leaderboard + int m_nGlobalRankPrevious; // the previous global rank of the user in this leaderboard; 0 if the user had no existing entry in the leaderboard +}; + +struct NumberOfCurrentPlayers_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 7 }; + uint8 m_bSuccess; // 1 if the call was successful + int32 m_cPlayers; // Number of players currently playing +}; + + + +//----------------------------------------------------------------------------- +// Purpose: Callback indicating that a user's stats have been unloaded. +// Call RequestUserStats again to access stats for this user +//----------------------------------------------------------------------------- +struct UserStatsUnloaded_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 8 }; + CSteamID m_steamIDUser; // User whose stats have been unloaded +}; + + + +//----------------------------------------------------------------------------- +// Purpose: Callback indicating that an achievement icon has been fetched +//----------------------------------------------------------------------------- +struct UserAchievementIconFetched_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 9 }; + + CGameID m_nGameID; // Game this is for + char m_rgchAchievementName[k_cchStatNameMax]; // name of the achievement + bool m_bAchieved; // Is the icon for the achieved or not achieved version? + int m_nIconHandle; // Handle to the image, which can be used in SteamUtils()->GetImageRGBA(), 0 means no image is set for the achievement +}; + + +//----------------------------------------------------------------------------- +// Purpose: Callback indicating that global achievement percentages are fetched +//----------------------------------------------------------------------------- +struct GlobalAchievementPercentagesReady_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 10 }; + + uint64 m_nGameID; // Game this is for + EResult m_eResult; // Result of the operation +}; + + +//----------------------------------------------------------------------------- +// Purpose: call result indicating UGC has been uploaded, returned as a result of SetLeaderboardUGC() +//----------------------------------------------------------------------------- +struct LeaderboardUGCSet_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 11 }; + EResult m_eResult; // The result of the operation + SteamLeaderboard_t m_hSteamLeaderboard; // the leaderboard handle that was +}; + + +//----------------------------------------------------------------------------- +// Purpose: callback indicating that PS3 trophies have been installed +//----------------------------------------------------------------------------- +struct PS3TrophiesInstalled_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 12 }; + uint64 m_nGameID; // Game these stats are for + EResult m_eResult; // The result of the operation + uint64 m_ulRequiredDiskSpace; // If m_eResult is k_EResultDiskFull, will contain the amount of space needed to install trophies + +}; + + +//----------------------------------------------------------------------------- +// Purpose: callback indicating global stats have been received. +// Returned as a result of RequestGlobalStats() +//----------------------------------------------------------------------------- +struct GlobalStatsReceived_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 12 }; + uint64 m_nGameID; // Game global stats were requested for + EResult m_eResult; // The result of the request +}; + +#pragma pack( pop ) + + +#endif // ISTEAMUSER_H diff --git a/ScreenPlayWorkshop/ThirdParty/steam/isteamutils.h b/ScreenPlayWorkshop/ThirdParty/steam/isteamutils.h new file mode 100644 index 00000000..e331fa6a --- /dev/null +++ b/ScreenPlayWorkshop/ThirdParty/steam/isteamutils.h @@ -0,0 +1,264 @@ +//====== Copyright � 1996-2008, Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to utility functions in Steam +// +//============================================================================= + +#ifndef ISTEAMUTILS_H +#define ISTEAMUTILS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isteamclient.h" + + +// Steam API call failure results +enum ESteamAPICallFailure +{ + k_ESteamAPICallFailureNone = -1, // no failure + k_ESteamAPICallFailureSteamGone = 0, // the local Steam process has gone away + k_ESteamAPICallFailureNetworkFailure = 1, // the network connection to Steam has been broken, or was already broken + // SteamServersDisconnected_t callback will be sent around the same time + // SteamServersConnected_t will be sent when the client is able to talk to the Steam servers again + k_ESteamAPICallFailureInvalidHandle = 2, // the SteamAPICall_t handle passed in no longer exists + k_ESteamAPICallFailureMismatchedCallback = 3,// GetAPICallResult() was called with the wrong callback type for this API call +}; + + +// Input modes for the Big Picture gamepad text entry +enum EGamepadTextInputMode +{ + k_EGamepadTextInputModeNormal = 0, + k_EGamepadTextInputModePassword = 1 +}; + + +// Controls number of allowed lines for the Big Picture gamepad text entry +enum EGamepadTextInputLineMode +{ + k_EGamepadTextInputLineModeSingleLine = 0, + k_EGamepadTextInputLineModeMultipleLines = 1 +}; + + +// function prototype for warning message hook +#if defined( POSIX ) +#define __cdecl +#endif +extern "C" typedef void (__cdecl *SteamAPIWarningMessageHook_t)(int, const char *); + +//----------------------------------------------------------------------------- +// Purpose: interface to user independent utility functions +//----------------------------------------------------------------------------- +class ISteamUtils +{ +public: + // return the number of seconds since the user + virtual uint32 GetSecondsSinceAppActive() = 0; + virtual uint32 GetSecondsSinceComputerActive() = 0; + + // the universe this client is connecting to + virtual EUniverse GetConnectedUniverse() = 0; + + // Steam server time. Number of seconds since January 1, 1970, GMT (i.e unix time) + virtual uint32 GetServerRealTime() = 0; + + // returns the 2 digit ISO 3166-1-alpha-2 format country code this client is running in (as looked up via an IP-to-location database) + // e.g "US" or "UK". + virtual const char *GetIPCountry() = 0; + + // returns true if the image exists, and valid sizes were filled out + virtual bool GetImageSize( int iImage, uint32 *pnWidth, uint32 *pnHeight ) = 0; + + // returns true if the image exists, and the buffer was successfully filled out + // results are returned in RGBA format + // the destination buffer size should be 4 * height * width * sizeof(char) + virtual bool GetImageRGBA( int iImage, uint8 *pubDest, int nDestBufferSize ) = 0; + + // returns the IP of the reporting server for valve - currently only used in Source engine games + virtual bool GetCSERIPPort( uint32 *unIP, uint16 *usPort ) = 0; + + // return the amount of battery power left in the current system in % [0..100], 255 for being on AC power + virtual uint8 GetCurrentBatteryPower() = 0; + + // returns the appID of the current process + virtual uint32 GetAppID() = 0; + + // Sets the position where the overlay instance for the currently calling game should show notifications. + // This position is per-game and if this function is called from outside of a game context it will do nothing. + virtual void SetOverlayNotificationPosition( ENotificationPosition eNotificationPosition ) = 0; + + // API asynchronous call results + // can be used directly, but more commonly used via the callback dispatch API (see steam_api.h) + virtual bool IsAPICallCompleted( SteamAPICall_t hSteamAPICall, bool *pbFailed ) = 0; + virtual ESteamAPICallFailure GetAPICallFailureReason( SteamAPICall_t hSteamAPICall ) = 0; + virtual bool GetAPICallResult( SteamAPICall_t hSteamAPICall, void *pCallback, int cubCallback, int iCallbackExpected, bool *pbFailed ) = 0; + + // Deprecated. Applications should use SteamAPI_RunCallbacks() instead. Game servers do not need to call this function. + STEAM_PRIVATE_API( virtual void RunFrame() = 0; ) + + // returns the number of IPC calls made since the last time this function was called + // Used for perf debugging so you can understand how many IPC calls your game makes per frame + // Every IPC call is at minimum a thread context switch if not a process one so you want to rate + // control how often you do them. + virtual uint32 GetIPCCallCount() = 0; + + // API warning handling + // 'int' is the severity; 0 for msg, 1 for warning + // 'const char *' is the text of the message + // callbacks will occur directly after the API function is called that generated the warning or message + virtual void SetWarningMessageHook( SteamAPIWarningMessageHook_t pFunction ) = 0; + + // Returns true if the overlay is running & the user can access it. The overlay process could take a few seconds to + // start & hook the game process, so this function will initially return false while the overlay is loading. + virtual bool IsOverlayEnabled() = 0; + + // Normally this call is unneeded if your game has a constantly running frame loop that calls the + // D3D Present API, or OGL SwapBuffers API every frame. + // + // However, if you have a game that only refreshes the screen on an event driven basis then that can break + // the overlay, as it uses your Present/SwapBuffers calls to drive it's internal frame loop and it may also + // need to Present() to the screen any time an even needing a notification happens or when the overlay is + // brought up over the game by a user. You can use this API to ask the overlay if it currently need a present + // in that case, and then you can check for this periodically (roughly 33hz is desirable) and make sure you + // refresh the screen with Present or SwapBuffers to allow the overlay to do it's work. + virtual bool BOverlayNeedsPresent() = 0; + + // Asynchronous call to check if an executable file has been signed using the public key set on the signing tab + // of the partner site, for example to refuse to load modified executable files. + // The result is returned in CheckFileSignature_t. + // k_ECheckFileSignatureNoSignaturesFoundForThisApp - This app has not been configured on the signing tab of the partner site to enable this function. + // k_ECheckFileSignatureNoSignaturesFoundForThisFile - This file is not listed on the signing tab for the partner site. + // k_ECheckFileSignatureFileNotFound - The file does not exist on disk. + // k_ECheckFileSignatureInvalidSignature - The file exists, and the signing tab has been set for this file, but the file is either not signed or the signature does not match. + // k_ECheckFileSignatureValidSignature - The file is signed and the signature is valid. + CALL_RESULT( CheckFileSignature_t ) + virtual SteamAPICall_t CheckFileSignature( const char *szFileName ) = 0; + + // Activates the Big Picture text input dialog which only supports gamepad input + virtual bool ShowGamepadTextInput( EGamepadTextInputMode eInputMode, EGamepadTextInputLineMode eLineInputMode, const char *pchDescription, uint32 unCharMax, const char *pchExistingText ) = 0; + + // Returns previously entered text & length + virtual uint32 GetEnteredGamepadTextLength() = 0; + virtual bool GetEnteredGamepadTextInput( char *pchText, uint32 cchText ) = 0; + + // returns the language the steam client is running in, you probably want ISteamApps::GetCurrentGameLanguage instead, this is for very special usage cases + virtual const char *GetSteamUILanguage() = 0; + + // returns true if Steam itself is running in VR mode + virtual bool IsSteamRunningInVR() = 0; + + // Sets the inset of the overlay notification from the corner specified by SetOverlayNotificationPosition. + virtual void SetOverlayNotificationInset( int nHorizontalInset, int nVerticalInset ) = 0; + + // returns true if Steam & the Steam Overlay are running in Big Picture mode + // Games much be launched through the Steam client to enable the Big Picture overlay. During development, + // a game can be added as a non-steam game to the developers library to test this feature + virtual bool IsSteamInBigPictureMode() = 0; + + // ask SteamUI to create and render its OpenVR dashboard + virtual void StartVRDashboard() = 0; + + // Returns true if the HMD content will be streamed via Steam In-Home Streaming + virtual bool IsVRHeadsetStreamingEnabled() = 0; + + // Set whether the HMD content will be streamed via Steam In-Home Streaming + // If this is set to true, then the scene in the HMD headset will be streamed, and remote input will not be allowed. + // If this is set to false, then the application window will be streamed instead, and remote input will be allowed. + // The default is true unless "VRHeadsetStreaming" "0" is in the extended appinfo for a game. + // (this is useful for games that have asymmetric multiplayer gameplay) + virtual void SetVRHeadsetStreamingEnabled( bool bEnabled ) = 0; +}; + +#define STEAMUTILS_INTERFACE_VERSION "SteamUtils009" + + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + +//----------------------------------------------------------------------------- +// Purpose: The country of the user changed +//----------------------------------------------------------------------------- +struct IPCountry_t +{ + enum { k_iCallback = k_iSteamUtilsCallbacks + 1 }; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Fired when running on a laptop and less than 10 minutes of battery is left, fires then every minute +//----------------------------------------------------------------------------- +struct LowBatteryPower_t +{ + enum { k_iCallback = k_iSteamUtilsCallbacks + 2 }; + uint8 m_nMinutesBatteryLeft; +}; + + +//----------------------------------------------------------------------------- +// Purpose: called when a SteamAsyncCall_t has completed (or failed) +//----------------------------------------------------------------------------- +struct SteamAPICallCompleted_t +{ + enum { k_iCallback = k_iSteamUtilsCallbacks + 3 }; + SteamAPICall_t m_hAsyncCall; + int m_iCallback; + uint32 m_cubParam; +}; + + +//----------------------------------------------------------------------------- +// called when Steam wants to shutdown +//----------------------------------------------------------------------------- +struct SteamShutdown_t +{ + enum { k_iCallback = k_iSteamUtilsCallbacks + 4 }; +}; + +//----------------------------------------------------------------------------- +// results for CheckFileSignature +//----------------------------------------------------------------------------- +enum ECheckFileSignature +{ + k_ECheckFileSignatureInvalidSignature = 0, + k_ECheckFileSignatureValidSignature = 1, + k_ECheckFileSignatureFileNotFound = 2, + k_ECheckFileSignatureNoSignaturesFoundForThisApp = 3, + k_ECheckFileSignatureNoSignaturesFoundForThisFile = 4, +}; + +//----------------------------------------------------------------------------- +// callback for CheckFileSignature +//----------------------------------------------------------------------------- +struct CheckFileSignature_t +{ + enum { k_iCallback = k_iSteamUtilsCallbacks + 5 }; + ECheckFileSignature m_eCheckFileSignature; +}; + + +// k_iSteamUtilsCallbacks + 13 is taken + + +//----------------------------------------------------------------------------- +// Big Picture gamepad text input has been closed +//----------------------------------------------------------------------------- +struct GamepadTextInputDismissed_t +{ + enum { k_iCallback = k_iSteamUtilsCallbacks + 14 }; + bool m_bSubmitted; // true if user entered & accepted text (Call ISteamUtils::GetEnteredGamepadTextInput() for text), false if canceled input + uint32 m_unSubmittedText; +}; + +// k_iSteamUtilsCallbacks + 15 is taken + +#pragma pack( pop ) + +#endif // ISTEAMUTILS_H diff --git a/ScreenPlayWorkshop/ThirdParty/steam/isteamvideo.h b/ScreenPlayWorkshop/ThirdParty/steam/isteamvideo.h new file mode 100644 index 00000000..32eeb594 --- /dev/null +++ b/ScreenPlayWorkshop/ThirdParty/steam/isteamvideo.h @@ -0,0 +1,71 @@ +//====== Copyright © 1996-2014 Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to Steam Video +// +//============================================================================= + +#ifndef ISTEAMVIDEO_H +#define ISTEAMVIDEO_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isteamclient.h" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + + + + +//----------------------------------------------------------------------------- +// Purpose: Steam Video API +//----------------------------------------------------------------------------- +class ISteamVideo +{ +public: + + // Get a URL suitable for streaming the given Video app ID's video + virtual void GetVideoURL( AppId_t unVideoAppID ) = 0; + + // returns true if user is uploading a live broadcast + virtual bool IsBroadcasting( int *pnNumViewers ) = 0; + + // Get the OPF Details for 360 Video Playback + CALL_BACK( GetOPFSettingsResult_t ) + virtual void GetOPFSettings( AppId_t unVideoAppID ) = 0; + virtual bool GetOPFStringForApp( AppId_t unVideoAppID, char *pchBuffer, int32 *pnBufferSize ) = 0; +}; + +#define STEAMVIDEO_INTERFACE_VERSION "STEAMVIDEO_INTERFACE_V002" + +DEFINE_CALLBACK( BroadcastUploadStart_t, k_iClientVideoCallbacks + 4 ) +END_DEFINE_CALLBACK_0() + +DEFINE_CALLBACK( BroadcastUploadStop_t, k_iClientVideoCallbacks + 5 ) + CALLBACK_MEMBER( 0, EBroadcastUploadResult, m_eResult ) +END_DEFINE_CALLBACK_1() + +DEFINE_CALLBACK( GetVideoURLResult_t, k_iClientVideoCallbacks + 11 ) + CALLBACK_MEMBER( 0, EResult, m_eResult ) + CALLBACK_MEMBER( 1, AppId_t, m_unVideoAppID ) + CALLBACK_MEMBER( 2, char, m_rgchURL[256] ) +END_DEFINE_CALLBACK_3() + + +DEFINE_CALLBACK( GetOPFSettingsResult_t, k_iClientVideoCallbacks + 24 ) + CALLBACK_MEMBER( 0, EResult, m_eResult ) + CALLBACK_MEMBER( 1, AppId_t, m_unVideoAppID ) +END_DEFINE_CALLBACK_2() + + +#pragma pack( pop ) + + +#endif // ISTEAMVIDEO_H diff --git a/ScreenPlayWorkshop/ThirdParty/steam/lib/osx32/libsdkencryptedappticket.dylib b/ScreenPlayWorkshop/ThirdParty/steam/lib/osx32/libsdkencryptedappticket.dylib new file mode 100644 index 0000000000000000000000000000000000000000..7c5c2f30aa9eb7304e054bde6cd63cd3c82b39a9 GIT binary patch literal 2127952 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

NBtEkf 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 z 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