achievements
authorhgn <hgodden00@gmail.com>
Thu, 13 Oct 2022 19:53:38 +0000 (20:53 +0100)
committerhgn <hgodden00@gmail.com>
Thu, 13 Oct 2022 19:53:38 +0000 (20:53 +0100)
highscores.h
main.c
player_physics.h
server.c
steam.h
world_info.h
world_routes.h

index 931c70897ff1b6411d828ec5ad91bb2a7893716e..494cd83fed850af6030fc1662e288e6386af4e0e 100644 (file)
@@ -92,6 +92,8 @@ static struct highscore_system
           aainfo_playerinfo;
 
    void *data, *playerinfo_data;
+
+   u32 pool_size, playerinfo_pool_size;
 }
 highscore_system;
 
@@ -154,20 +156,86 @@ static void highscores_free(void)
    vg_free( highscore_system.playerinfo_data );
 }
 
-static int highscores_init( u32 pool_size, u32 playerinfo_pool_size )
+static void highscores_create_db(void)
 {
    struct highscore_system *sys = &highscore_system;
 
-   sys->data = highscore_malloc( pool_size, sizeof(highscore_record) );
-   if( !sys->data ) return 0;
+   vg_info( "Initializing database nodes\n" );
+   memset( &sys->dbheader, 0, sizeof(highscore_database) );
+
+   sys->dbheader.pool_head = aatree_init_pool( &sys->aainfo, sys->pool_size );
+   sys->dbheader.entry_capacity = sys->pool_size;
+
+   for( int i=0; i<vg_list_size(sys->dbheader.tracks); i++ )
+   {
+      highscore_track_table *table = &sys->dbheader.tracks[i];
+      table->root_points = AATREE_PTR_NIL;
+      table->root_playerid = AATREE_PTR_NIL;
+      table->root_time = AATREE_PTR_NIL;
+      table->root_datetime = AATREE_PTR_NIL;
+   }
+
+   /* Initialize secondary db */
+   sys->dbheader.playerinfo_head = aatree_init_pool( 
+         &sys->aainfo_playerinfo,
+         sys->playerinfo_pool_size );
+   sys->dbheader.playerinfo_capacity = sys->playerinfo_pool_size;
+   sys->dbheader.playerinfo_root = AATREE_PTR_NIL;
+}
+
+static int highscores_read(void)
+{
+   struct highscore_system *sys = &highscore_system;
 
-   sys->playerinfo_data = 
-      highscore_malloc( playerinfo_pool_size, sizeof(highscore_playerinfo));
-   if( !sys->playerinfo_data ) 
+   FILE *fp = fopen( ".aadb", "rb" );
+   if( fp )
    {
-      vg_free( sys->data );
+      vg_info( "Loading existing database\n" );
+      
+      u64 count = fread( &sys->dbheader, sizeof(highscore_database), 1, fp );
+
+      if( count != 1 )
+      {
+         vg_error( "Unexpected EOF reading database header\n" );
+         return 0;
+      }
+
+      count = fread( sys->data, sizeof(highscore_record), sys->pool_size, fp );
+      if( count != sys->pool_size )
+      {
+         vg_error( "Unexpected EOF reading database contents;"
+                   " %lu records of %u were read\n", count, sys->pool_size );
+         return 0;
+      }
+
+      count = fread( sys->playerinfo_data, sizeof(highscore_playerinfo),
+                     sys->playerinfo_pool_size, fp );
+
+      if( count != sys->playerinfo_pool_size )
+      {
+         vg_error( "Unexpected EOF reading playerinfo contents;"
+                   " %lu records of %u were read\n", count, 
+                   sys->playerinfo_pool_size );
+         return 0;
+      }
+
+      fclose( fp );
+      return 1;
+   }
+   else
+   {
+      vg_low( "No existing database found (.aadb)\n" );
       return 0;
    }
+}
+
+static void highscores_init( u32 pool_size, u32 playerinfo_pool_size )
+{
+   struct highscore_system *sys = &highscore_system;
+
+   sys->data = highscore_malloc( pool_size, sizeof(highscore_record) );
+   sys->playerinfo_data = highscore_malloc( playerinfo_pool_size, 
+                                            sizeof(highscore_playerinfo));
 
    /* This is ugly.. too bad! */
    sys->aainfo.base = highscore_system.data;
@@ -206,72 +274,8 @@ static int highscores_init( u32 pool_size, u32 playerinfo_pool_size )
    sys->aainfo_playerinfo.offset = offsetof(highscore_playerinfo,aapn);
    sys->aainfo_playerinfo.p_cmp = NULL;
 
-   FILE *fp = fopen( ".aadb", "rb" );
-   if( fp )
-   {
-      vg_info( "Loading existing database\n" );
-      
-      u64 count = fread( &sys->dbheader, sizeof(highscore_database), 1, fp );
-
-      if( count != 1 )
-      {
-         vg_error( "Unexpected EOF reading database header\n" );
-         
-         highscores_free();
-         return 0;
-      }
-
-      count = fread( sys->data, sizeof(highscore_record), pool_size, fp );
-      if( count != pool_size )
-      {
-         vg_error( "Unexpected EOF reading database contents;"
-                   " %lu records of %u were read\n", count, pool_size );
-
-         highscores_free();
-         return 0;
-      }
-
-      count = fread( sys->playerinfo_data, sizeof(highscore_playerinfo),
-                     playerinfo_pool_size, fp );
-      if( count != playerinfo_pool_size )
-      {
-         vg_error( "Unexpected EOF reading playerinfo contents;"
-                   " %lu records of %u were read\n", count, 
-                   playerinfo_pool_size );
-         
-         highscores_free();
-         return 0;
-      }
-
-      fclose( fp );
-   }
-   else
-   {
-      vg_low( "No existing database found (.aadb)\n" );
-      vg_info( "Initializing database nodes\n" );
-      memset( &sys->dbheader, 0, sizeof(highscore_database) );
-
-      sys->dbheader.pool_head = aatree_init_pool( &sys->aainfo, pool_size );
-      sys->dbheader.entry_capacity = pool_size;
-
-      for( int i=0; i<vg_list_size(sys->dbheader.tracks); i++ )
-      {
-         highscore_track_table *table = &sys->dbheader.tracks[i];
-         table->root_points = AATREE_PTR_NIL;
-         table->root_playerid = AATREE_PTR_NIL;
-         table->root_time = AATREE_PTR_NIL;
-         table->root_datetime = AATREE_PTR_NIL;
-      }
-
-      /* Initialize secondary db */
-      sys->dbheader.playerinfo_head = aatree_init_pool( 
-            &sys->aainfo_playerinfo,
-            playerinfo_pool_size );
-      sys->dbheader.playerinfo_capacity = playerinfo_pool_size;
-      sys->dbheader.playerinfo_root = AATREE_PTR_NIL;
-   }
-
-   return 1;
+   sys->playerinfo_pool_size = playerinfo_pool_size;
+   sys->pool_size = pool_size;
 }
 
 static int highscores_serialize_all(void)
diff --git a/main.c b/main.c
index 6e61fa25cbf6b5f259f08c116270b84f2bed491c..2ac5e20bdddbe140c3d20e114baa4823bd4d7dbe 100644 (file)
--- a/main.c
+++ b/main.c
@@ -61,6 +61,9 @@ vg_info("            '        ' '--' [] '----- '----- '     ' '---'  "
         "SOFTWARE\n" );
 
    highscores_init( 2000, 50 );
+   if( !highscores_read() )
+      highscores_create_db();
+
    vg_loader_highwater( NULL, highscores_save_at_exit, NULL );
 
    vg_sleep_ms(200);
index 5d1843305adec22610548dbf833d714aa8ea9ce4..8d0b5b88ad3262f61da46b71804c3eaa9f616ec2 100644 (file)
@@ -717,9 +717,6 @@ static void player_mouseview(void)
       v2_muladds( view_vel, delta, 0.06f*vg.time_delta, view_vel );
    }
    
-   v2_muladds( view_vel, (v2f){ vg_get_axis("h1"), vg_get_axis("v1") }, 
-                         3.0f * vg.time_delta, view_vel );
-
    v2_muls( view_vel, 1.0f-4.2f*vg.time_delta, view_vel );
    v2_add( view_vel, player.angles, player.angles );
    player.angles[1] = vg_clampf( player.angles[1], -VG_PIf*0.5f, VG_PIf*0.5f );
index 8225c6ecf988cd2071114e6b7617266a47cb7902..d5d5d91f10291c708a6faa28c75ae27573a36f49 100644 (file)
--- a/server.c
+++ b/server.c
@@ -332,8 +332,12 @@ int main( int argc, char *argv[] )
 {
    signal( SIGINT, inthandler );
    signal( SIGQUIT, inthandler );
+   
+   /* TODO: Options to override, ammend, remove etc */
 
    highscores_init( 250000, 10000 );
+   if( !highscores_read() )
+      highscores_create_db();
 
    steamworks_ensure_txt( "2103940" );
    if( !vg_load_steam_symetric_key( "application_key", steam_symetric_key ) )
diff --git a/steam.h b/steam.h
index 0be3ff64045ee3efadd110eb7b6ac8549c325d52..fbb4f8a5b7dce0a1a8f3ba5ed58d333d5b972ab7 100644 (file)
--- a/steam.h
+++ b/steam.h
@@ -12,6 +12,7 @@
 #include "vg/vg_steam_auth.h"
 #include "vg/vg_steam_http.h"
 #include "vg/vg_steam_friends.h"
+#include "vg/vg_steam_user_stats.h"
 
 /*
  * We only want to use steamworks if building for the networked version,
@@ -34,12 +35,145 @@ static void recv_steam_warning( int severity, const char *msg )
       vg_info( "%s\n", msg );
 }
 
-static int steam_ready = 0;
+static int steam_ready = 0,
+           steam_stats_ready = 0;
+
 static void *hSteamNetworkingSockets,
             *hSteamUser;
 
+static ISteamUserStats *hSteamUserStats;
 static HSteamPipe hSteamClientPipe;
 
+static const char *steam_achievement_names[] = 
+{
+   "ALBERT", "MARC", 
+   "ROUTE_MPY", "ROUTE_MPG", "ROUTE_MPB", "ROUTE_MPR",
+   "ROUTE_TO", "ROUTE_TC"
+};
+
+static void steam_store_achievements(void)
+{
+   SteamAPI_ISteamUserStats_StoreStats( hSteamUserStats );
+}
+
+static void steam_set_achievement( const char *name )
+{
+   if( steam_ready && steam_stats_ready )
+   {
+      if( SteamAPI_ISteamUserStats_SetAchievement( hSteamUserStats, name ) )
+      {
+         vg_success( "Achievement set! '%s'\n", name );
+      }
+      else
+      {
+         vg_warn( "Failed to set achievement: %s\n", name );
+      }
+   }
+   else
+   {
+      vg_warn( "Failed to set achievement (steam not ready): %s\n", name );
+   }
+}
+
+static void steam_clear_achievement( const char *name )
+{
+   if( steam_ready && steam_stats_ready )
+   {
+      if( SteamAPI_ISteamUserStats_ClearAchievement( hSteamUserStats, name ) )
+      {
+         vg_info( "Achievement cleared: '%s'\n", name );
+      }
+      else
+      {
+         vg_warn( "Failed to clear achievement: %s\n", name );
+      }
+   }
+   else
+   {
+      vg_warn( "Failed to clear achievement (steam not ready): %s\n", name );
+   }
+}
+
+
+static int steam_list_achievements( int argc, char const *argv[] )
+{
+   vg_info( "Achievements: \n" );
+
+   if( steam_ready && steam_stats_ready )
+   {
+      for( int i=0; i<vg_list_size(steam_achievement_names); i++ )
+      {
+         int set = 0;
+         const char *name = steam_achievement_names[i];
+
+         if( SteamAPI_ISteamUserStats_GetAchievement( 
+                  hSteamUserStats, name, &set ) )
+         {
+            vg_info( "  %s %s\n", (set? "[YES]": "[   ]"), name );
+         }
+         else
+         {
+            vg_warn( "  Error while fetching achievement status '%s'\n", name );
+         }
+      }
+   }
+   else
+   {
+      vg_warn( "  Steam is not initialized, no results\n" );
+   }
+
+   return 0;
+}
+
+static int steam_clear_all_achievements( int argc, char const *argv[] )
+{
+   if( steam_ready && steam_stats_ready )
+   {
+      for( int i=0; i<vg_list_size(steam_achievement_names); i++ )
+      {
+         steam_clear_achievement( steam_achievement_names[i] );
+      }
+      
+      steam_store_achievements();
+   }
+   else
+   {
+      vg_warn( "steam is not initialized, cannot clear\n" );
+   }
+
+   return 0;
+}
+
+static int steam_set_achievemnt_test( int argc, char const *argv[] )
+{
+   if( argc < 2 )
+      return 0;
+
+   if( strcmp( argv[0], "monkey_island" ) )
+      return 0;
+
+   steam_set_achievement( argv[1] );
+   steam_store_achievements();
+
+   return 0;
+}
+
+static void steam_on_recieve_current_stats( CallbackMsg_t *msg )
+{
+   UserStatsReceived_t *rec = (UserStatsReceived_t *)msg->m_pubParam;
+
+   if( rec->m_eResult == k_EResultOK )
+   {
+      vg_info( "Recieved stats for: %lu (user: %lu)\n", rec->m_nGameID,
+                                                        rec->m_steamIDUser );
+      steam_stats_ready = 1;
+   }
+   else
+   {
+      vg_error( "Error recieveing stats for user (%u)\n", rec->m_eResult );
+   }
+}
+
 static int steam_init(void)
 {
    const char *username = NULL;
@@ -71,6 +205,38 @@ static int steam_init(void)
 
    ISteamFriends *hSteamFriends = SteamAPI_SteamFriends();
    username = SteamAPI_ISteamFriends_GetPersonaName( hSteamFriends );
+
+   /*
+    * Request stats
+    * --------------------------------------------------------
+    */
+   hSteamUserStats = SteamAPI_SteamUserStats();
+
+   steam_register_callback( k_iUserStatsReceived,
+                            steam_on_recieve_current_stats );
+
+   if( !SteamAPI_ISteamUserStats_RequestCurrentStats( hSteamUserStats ) )
+      vg_warn( "No Steam Logon: Cannot request stats\n" );
+
+
+       vg_function_push( (struct vg_cmd)
+   {
+               .name = "ach_list",
+               .function = steam_list_achievements
+       });
+
+       vg_function_push( (struct vg_cmd)
+   {
+               .name = "ach_clear_all",
+               .function = steam_clear_all_achievements
+       });
+
+       vg_function_push( (struct vg_cmd)
+   {
+               .name = "ach_set",
+               .function = steam_set_achievemnt_test
+       });
+
 #endif
 
    /* TODO: On username update callback */
index c8b3e2833e43890e91c0ecc34f4c506fd481f0b8..143fb70c6cba56997e0f8f1d12ec6c3b086aebbf 100644 (file)
@@ -18,33 +18,40 @@ world_info;
 
 static struct track_info
 {
-   const char *name;
+   const char *name, 
+              *achievement_id;
    int push;
 }
 track_infos[] = 
 {
    {
       .name = "Megapark Green",
+      .achievement_id = "ROUTE_MPG",
       .push = 1
    },
    {
       .name = "Megapark Blue",
+      .achievement_id = "ROUTE_MPB",
       .push = 1
    },
    {
       .name = "Megapark Yellow",
+      .achievement_id = "ROUTE_MPY",
       .push = 1
    },
    {
       .name = "Megapark Red",
+      .achievement_id = "ROUTE_MPR",
       .push = 1
    },
    {
       .name = "Coastal Run",
+      .achievement_id = "ROUTE_TC",
       .push = 1
    },
    {
       .name = "Docks Jumps",
+      .achievement_id = "ROUTE_TO",
       .push = 1
    }
 };
index 480f70504a9b714861b0c0e8c3ef0bbfb1752f45..d8d36d210efcccc7dfd8747c7148f039af0664e5 100644 (file)
@@ -496,7 +496,15 @@ static void world_routes_local_set_record( u32 route, double lap_time )
       temp.time     = time_centiseconds;
 
       highscores_push_record( &temp );
-      track_infos[ pr->track_id ].push = 1;
+
+      struct track_info *pti = &track_infos[ pr->track_id ];
+      pti->push = 1;
+      
+      if( pti->achievement_id )
+      {
+         steam_set_achievement( pti->achievement_id );
+         steam_store_achievements();
+      }
    }
    else
    {