cross compile build script
[fishladder.git] / vg / vg_steamworks.h
index d4b797bacfea4c9663fb6205954e47f39a7ad1ad..c0baba54bcca3dea04b42f4e9e0a411c913f4bdc 100644 (file)
@@ -301,6 +301,17 @@ typedef struct GameID_t
 
 #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;
@@ -534,6 +545,16 @@ void               SteamAPI_ReleaseCurrentThreadMemory();
 
 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 );
@@ -547,6 +568,18 @@ int SteamAPI_ISteamUserStats_GetDownloadedLeaderboardEntry( ISteamUserStats* sel
 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();
 
@@ -556,20 +589,138 @@ struct
        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)
@@ -604,8 +755,9 @@ static int sw_init(void)
        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();
@@ -619,6 +771,10 @@ static int sw_init(void)
        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 );
@@ -626,10 +782,12 @@ static void sw_event_loop(void)
        
        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;
                        
@@ -644,6 +802,37 @@ static void sw_event_loop(void)
                        {
                                // 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 );
@@ -652,9 +841,6 @@ static void sw_event_loop(void)
                {
                        // 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 )