#define SW_CBID_SteamAPICallCompleted (k_iSteamUtilsCallbacks + 3)
+typedef 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
+} ESteamAPICallFailure;
+
typedef u64 UGCHandle_t;
typedef u64 PublishedFileUpdateHandle_t;
typedef u64 PublishedFileId_t;
int SteamAPI_ISteamUserStats_SetAchievement( ISteamUserStats *self, const char *pchName );
+ESteamAPICallFailure SteamAPI_ISteamUtils_GetAPICallFailureReason( ISteamUtils* self, SteamAPICall_t hSteamAPICall );
+
+// Friends
+char *SteamAPI_ISteamFriends_GetPersonaName( ISteamFriends *self );
+const char *SteamAPI_ISteamFriends_GetFriendPersonaName( ISteamFriends *self, u64_steamid steamIDFriend );
+u64_steamid SteamAPI_ISteamUser_GetSteamID( ISteamUser *self );
+int SteamAPI_ISteamFriends_GetSmallFriendAvatar( ISteamFriends *self, u64_steamid steamIDFriend ); // 32x32
+int SteamAPI_ISteamUtils_GetImageSize( ISteamUtils *self, int iImage, u32 *pnWidth, u32 *pnHeight );
+int SteamAPI_ISteamUtils_GetImageRGBA( ISteamUtils *self, int iImage, u8 *pubDest, int nDestBufferSize );
+
// Leaderboards
SteamAPICall_t SteamAPI_ISteamUserStats_FindOrCreateLeaderboard( ISteamUserStats* self, const char * pchLeaderboardName, ELeaderboardSortMethod eLeaderboardSortMethod, ELeaderboardDisplayType eLeaderboardDisplayType );
SteamAPICall_t SteamAPI_ISteamUserStats_FindLeaderboard( ISteamUserStats* self, const char * pchLeaderboardName );
SteamAPICall_t SteamAPI_ISteamUserStats_UploadLeaderboardScore( ISteamUserStats* self, SteamLeaderboard_t hSteamLeaderboard, ELeaderboardUploadScoreMethod eLeaderboardUploadScoreMethod, i32 nScore, const i32 * pScoreDetails, int cScoreDetailsCount );
SteamAPICall_t SteamAPI_ISteamUserStats_AttachLeaderboardUGC( ISteamUserStats* self, SteamLeaderboard_t hSteamLeaderboard, UGCHandle_t hUGC );
+#define sw_get_image_size(...) SteamAPI_ISteamUtils_GetImageSize( steam_api_classes.utils, __VA_ARGS__ )
+#define sw_get_image_rgba(...) SteamAPI_ISteamUtils_GetImageRGBA( steam_api_classes.utils, __VA_ARGS__ )
+#define sw_get_small_friend_avatar(...) SteamAPI_ISteamFriends_GetSmallFriendAvatar( steam_api_classes.friends, __VA_ARGS__ )
+#define sw_get_steamid() SteamAPI_ISteamUser_GetSteamID( steam_api_classes.friends )
+#define sw_get_friend_persona_name(...) SteamAPI_ISteamFriends_GetFriendPersonaName( steam_api_classes.friends, __VA_ARGS__ )
+#define sw_get_persona_name() SteamAPI_ISteamFriends_GetPersonaName( steam_api_classes.friends )
+#define sw_find_leaderboard(...) SteamAPI_ISteamUserStats_FindLeaderboard( steam_api_classes.stats, __VA_ARGS__ );
+#define sw_get_leaderboard_name(...) SteamAPI_ISteamUserStats_GetLeaderboardName( steam_api_classes.stats, __VA_ARGS__ )
+#define sw_download_leaderboard_entries(...) SteamAPI_ISteamUserStats_DownloadLeaderboardEntries( steam_api_classes.stats, __VA_ARGS__ )
+#define sw_get_downloaded_entry(...) SteamAPI_ISteamUserStats_GetDownloadedLeaderboardEntry( steam_api_classes.stats, __VA_ARGS__ )
+#define sw_upload_leaderboard_score(...) SteamAPI_ISteamUserStats_UploadLeaderboardScore( steam_api_classes.stats, __VA_ARGS__ )
+
HSteamPipe SteamAPI_GetHSteamPipe();
HSteamUser SteamAPI_GetHSteamUser();
ISteamUser *user;
ISteamUserStats *stats;
ISteamNetworking *net;
+ ISteamUtils *utils;
HSteamPipe pipe;
+
+ struct cached_player
+ {
+ u64_steamid id;
+ GLuint avatar_texture; // tex_unkown.name
+
+ struct cached_player *l, *r;
+ }
+ cached_players[20];
+
+ struct cached_player *cache_head, *cache_tail;
+
+ u32 cache_count;
+
} steam_api_classes;
+static void _sw_cache_push( struct cached_player *player )
+{
+ player->l = NULL;
+ player->r = steam_api_classes.cache_head;
+ if( steam_api_classes.cache_head ) steam_api_classes.cache_head->l = player;
+ if( !steam_api_classes.cache_tail ) steam_api_classes.cache_tail = player;
+ steam_api_classes.cache_head = player;
+ steam_api_classes.cache_count ++;
+}
+
+static void _sw_cache_evict( struct cached_player *player )
+{
+ if( player == steam_api_classes.cache_tail ) steam_api_classes.cache_tail = player->l;
+ if( player == steam_api_classes.cache_head ) steam_api_classes.cache_head = player->r;
+ if( player->l ) player->l->r = player->r;
+ if( player->r ) player->r->l = player->l;
+ steam_api_classes.cache_count --;
+}
+
+static void _sw_access_cache( struct cached_player *player )
+{
+ _sw_cache_evict( player );
+ _sw_cache_push( player );
+}
+
+static GLuint sw_get_player_image( u64_steamid usr )
+{
+ // Look for player in cache
+ for( int i = 0; i < steam_api_classes.cache_count; i ++ )
+ {
+ struct cached_player *player = &steam_api_classes.cached_players[i];
+
+ if( player->id == usr )
+ {
+ _sw_access_cache( player );
+ return player->avatar_texture;
+ }
+ }
+
+ struct cached_player *dest;
+
+ if( steam_api_classes.cache_count == vg_list_size( steam_api_classes.cached_players ) )
+ {
+ dest = steam_api_classes.cache_tail;
+ _sw_access_cache( dest );
+
+ // Delete previous before creating a new one
+ glDeleteTextures( 1, &dest->avatar_texture );
+ }
+ else
+ {
+ dest = &steam_api_classes.cached_players[ steam_api_classes.cache_count ];
+ _sw_cache_push( dest );
+ }
+
+ dest->id = usr;
+ dest->avatar_texture = 0;
+
+ // Upload new image
+ u32 x = 32, y = 32;
+ int steam_image;
+
+ steam_image = sw_get_small_friend_avatar( usr );
+ if( !steam_image )
+ return 0;
+
+ if( !sw_get_image_size( steam_image, &x, &y ) )
+ return 0;
+
+ u8 * img_buf = (u8 *)malloc( x * y * 4 );
+
+ if( !sw_get_image_rgba(steam_image, img_buf, x * y * 4) )
+ {
+ free( img_buf );
+ return 0;
+ }
+
+ glGenTextures( 1, &dest->avatar_texture );
+ glBindTexture( GL_TEXTURE_2D, dest->avatar_texture );
+
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, img_buf );
+ glGenerateMipmap( GL_TEXTURE_2D );
+
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+
+ free( img_buf );
+
+ return dest->avatar_texture;
+}
+
ISteamFriends *SteamAPI_SteamFriends_v017();
ISteamUser *SteamAPI_SteamUser_v021();
ISteamUserStats *SteamAPI_SteamUserStats_v012();
ISteamNetworking *SteamAPI_SteamNetworking_v006();
+ISteamUtils *SteamAPI_SteamUtils_v010();
static void sw_exit(void)
{
SteamAPI_Shutdown();
}
+// Needs to be manually called by client unfortunately
+static void sw_free_opengl(void)
+{
+ for( int i = 0; i < steam_api_classes.cache_count; i ++ )
+ if( steam_api_classes.cached_players[i].avatar_texture )
+ glDeleteTextures( 1, &steam_api_classes.cached_players[i].avatar_texture );
+}
+
static int sw_init(void)
{
#if defined(VALVE_CALLBACK_PACK_SMALL)
steam_api_classes.user = SteamAPI_SteamUser_v021();
steam_api_classes.stats = SteamAPI_SteamUserStats_v012();
steam_api_classes.net = SteamAPI_SteamNetworking_v006();
+ steam_api_classes.utils = SteamAPI_SteamUtils_v010();
- if( !steam_api_classes.friends || !steam_api_classes.user || !steam_api_classes.stats || !steam_api_classes.net )
+ if( !steam_api_classes.friends || !steam_api_classes.user || !steam_api_classes.stats || !steam_api_classes.net || !steam_api_classes.utils )
{
vg_error( "Steamworks interface pointers failed. Steamworks DLL may be old\n" );
SteamAPI_Shutdown();
return 1;
}
+
+void (*sw_leaderboard_found)( LeaderboardFindResult_t *pCallback );
+void (*sw_leaderboard_downloaded)( LeaderboardScoresDownloaded_t *pCallback );
+
static void sw_event_loop(void)
{
SteamAPI_ManualDispatch_RunFrame( steam_api_classes.pipe );
while( SteamAPI_ManualDispatch_GetNextCallback( steam_api_classes.pipe, &callback ) )
{
+ vg_info( "steamworks_event::callback( %i )\n", callback.m_iCallback );
+
// Check for dispatching API call results
if( callback.m_iCallback == SW_CBID_SteamAPICallCompleted ){
- SteamAPICallCompleted_t *pCallCompleted = (SteamAPICallCompleted_t *)&callback;
+ SteamAPICallCompleted_t *pCallCompleted = (SteamAPICallCompleted_t *)callback.m_pubParam;
void *pTmpCallResult = malloc( pCallCompleted->m_cubParam );
int bFailed;
{
// Dispatch the call result to the registered handler(s) for the
// call identified by pCallCompleted->m_hAsyncCall
+
+ vg_info( "steamworks_event::api_call_completed( %lu )\n", pCallCompleted->m_hAsyncCall );
+
+ switch( pCallCompleted->m_iCallback )
+ {
+ case SW_CBID_LeaderboardFindResult:
+ if( sw_leaderboard_found ) sw_leaderboard_found( (LeaderboardFindResult_t*)pTmpCallResult );
+ break;
+ case SW_CBID_LeaderboardScoresDownloaded:
+ if( sw_leaderboard_downloaded ) sw_leaderboard_downloaded( (LeaderboardScoresDownloaded_t*)pTmpCallResult );
+ break;
+ default:break;
+ }
+ }
+ else
+ {
+ typedef 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
+ } ESteamAPICallFailure;
+
+ ESteamAPICallFailure fail_why =
+ SteamAPI_ISteamUtils_GetAPICallFailureReason( steam_api_classes.utils, pCallCompleted->m_hAsyncCall );
+
+ vg_error( "steamworks_event: error getting call result on %lu (code %d)\n", pCallCompleted->m_hAsyncCall, fail_why );
}
free( pTmpCallResult );
{
// Look at callback.m_iCallback to see what kind of callback it is,
// and dispatch to appropriate handler(s)
-
- vg_info( "steamworks_event::callback( %i )\n", callback.m_iCallback );
-
//void *data = callback.m_pubParam;
switch( callback.m_iCallback )