]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/common/playerstats.qc
Updates to playerbasic, including status tracking and proper database init
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / playerstats.qc
index 476e0cb1f3ca508b84236e607f7c5ff31d049389..fb28fd5563c42b14ddaa304d5de01da8f028d540 100644 (file)
@@ -1,33 +1,3 @@
-#ifdef SVQC
-//float PS_PM_IN_DB;   // playerstats_prematch_in_db      // db for info COLLECTED at the beginning of a match
-float PS_GR_OUT_DB;  // playerstats_gamereport_out_db   // db of info SENT at the end of a match
-//float PS_GR_IN_DB;   // playerstats_gamereport_in_db    // db for info COLLECTED at the end of a match
-//float PS_B_IN_DB;    // playerstats_playerbasic_in_db   // db for info COLLECTED for basic player info (ELO)
-// http://stats.xonotic.org/player/GgXRw6piDtFIbMArMuiAi8JG4tiin8VLjZgsKB60Uds=/elo.txt -- this works, 
-// http://stats.xonotic.org/player/ENkUjf83vKMVZcNm%2F6Ao1EmXEj1apQ6XvdQTxwELvmA%3D/elo.txt -- but this doesn't?!?
-// ENkUjf83vKMVZcNm/6Ao1EmXEj1apQ6XvdQTxwELvmA=
-#endif
-
-#ifdef MENUQC
-//float PS_D_IN_DB; // playerstats_playerdetail_in_db  // db for info COLLECTED for detailed player profile display
-// http://stats.xonotic.org/player/me
-#endif
-
-#ifdef SVQC
-//string PS_PM_IN_EVL;   // playerstats_prematch_in_events_last
-string PS_GR_OUT_TL;   // playerstats_gamereport_out_teams_last
-string PS_GR_OUT_PL;   // playerstats_gamereport_out_players_las
-string PS_GR_OUT_EVL;  // playerstats_gamereport_out_events_last
-//string PS_GR_IN_PL;    // playerstats_gamereport_in_players_last
-//string PS_GR_IN_EVL;   // playerstats_gamereport_in_events_last
-//string PS_B_IN_PL;     // playerstats_playerbasic_in_players_las
-//string PS_B_IN_EVL;    // playerstats_playerbasic_in_events_last
-#endif
-
-#ifdef MENUQC
-//string PS_D_IN_EVL; // playerstats_playerdetail_in_events_last
-#endif
-
 #ifdef SVQC
 void PlayerStats_Prematch(void)
 {
@@ -424,8 +394,11 @@ void PlayerStats_GameReport_Handler(entity fh, entity pass, float status)
                        // url_fclose has finished
                        print("Player stats written\n");
                        PlayerStats_GameReport_DelayMapVote = FALSE;
-                       db_close(PS_GR_OUT_DB);
-                       PS_GR_OUT_DB = -1;
+                       if(PS_GR_OUT_DB >= 0)
+                       {
+                               db_close(PS_GR_OUT_DB);
+                               PS_GR_OUT_DB = -1;
+                       }
                        break;
                }
                
@@ -446,33 +419,61 @@ void PlayerStats_GameReport_Handler(entity fh, entity pass, float status)
 
 void PlayerStats_PlayerBasic()
 {
-       entity player;
-       //PS_D_IN_DB = -1;
-       //PS_D_IN_DB = db_create();
+       if(autocvar_g_playerstats_playerbasic_uri != "")
+       {
+               entity player;
+               
+               // create the database if it doesn't already exist
+               if(PS_B_IN_DB < 0)
+               {
+                       PS_B_IN_DB = -1;
+                       PS_B_IN_DB = db_create();
+               }
+
+               FOR_EACH_REALCLIENT(player)
+               {
+                       string uri = autocvar_g_playerstats_playerbasic_uri;
+                       if((uri != "") && (player.crypto_idfp != ""))
+                       {
+                               uri = strcat(uri, "/player/", uri_escape(uri_escape(player.crypto_idfp)), "/elo.txt");
+                               print("Retrieving playerstats from URL: ", uri, "\n");
+                               url_single_fopen(
+                                       uri,
+                                       FILE_APPEND,
+                                       PlayerStats_PlayerBasic_Handler,
+                                       player
+                               );
+                       }
 
-       //if(PS_D_IN_DB < 0) { return; }
+                       /*p.crypto_idfp != "")
+                       {
+                               uri = strcat(uri, "/elo/", uri_escape(p.crypto_idfp));
+                               print("Retrieving playerstats from URL: ", uri, "\n");
+                               url_single_fopen(uri, FILE_READ, PlayerInfo_ready, p);
+                       }*/
+               }
 
-       FOR_EACH_REALCLIENT(player)
+               if(PlayerStats_PlayerBasic_Status == PS_B_STATUS_RECEIVED)
+               {
+                       // database still contains useful information, so don't clear it of a useful status
+                       PlayerStats_PlayerBasic_Status = PS_B_STATUS_UPDATING;
+               }
+               else
+               {
+                       // database was previously empty or never hit received status for some reason
+                       PlayerStats_PlayerBasic_Status = PS_B_STATUS_WAITING;
+               }
+       }
+       else
        {
-               string uri = autocvar_g_playerstats_playerbasic_uri;
-               if((uri != "") && (player.crypto_idfp != ""))
+               // player has this disabled, kill the DB and set status to idle
+               if(PS_B_IN_DB >= 0)
                {
-                       uri = strcat(uri, "/player/", uri_escape(player.crypto_idfp), "/elo.txt");
-                       print("Retrieving playerstats from URL: ", uri, "\n");
-                       url_single_fopen(
-                               uri,
-                               FILE_APPEND,
-                               PlayerStats_PlayerBasic_Handler,
-                               player
-                       );
+                       db_close(PS_B_IN_DB);
+                       PS_B_IN_DB = -1;
                }
 
-               /*p.crypto_idfp != "")
-               {
-                       uri = strcat(uri, "/elo/", uri_escape(p.crypto_idfp));
-                       print("Retrieving playerstats from URL: ", uri, "\n");
-                       url_single_fopen(uri, FILE_READ, PlayerInfo_ready, p);
-               }*/
+               PlayerStats_PlayerBasic_Status = PS_B_STATUS_IDLE;
        }
 }
 
@@ -577,15 +578,51 @@ void PlayerStats_PlayerBasic_Handler(entity fh, entity p, float status)
 #endif // SVQC
 
 #ifdef MENUQC
-void PlayerStats_PlayerDetail()
+
+
+#if 0 // reading the entire DB at once
+       string e = "", en = "";
+       float i = 0;
+       for(e = PS_D_IN_EVL; (en = db_get(PS_D_IN_DB, e)) != ""; e = en)
+       {
+               print(sprintf("%d:%s:%s\n", i, e, db_get(PS_D_IN_DB, sprintf("#%s", e))));
+               ++i;
+       }
+#endif
+
+void PlayerStats_PlayerDetail_AddItem(string event, string data)
 {
-       //PS_D_IN_DB = -1;
-       //PS_D_IN_DB = db_create();
+       if(PS_D_IN_DB < 0) { return; }
 
-       //if(PS_D_IN_DB < 0) { return; }
+       // create a marker for the event so that we can access it later
+       string marker = sprintf("%s", event);
+       if(db_get(PS_D_IN_DB, marker) == "")
+       {
+               if(PS_D_IN_EVL)
+               {
+                       db_put(PS_D_IN_DB, marker, PS_D_IN_EVL);
+                       strunzone(PS_D_IN_EVL);
+               }
+               else { db_put(PS_D_IN_DB, marker, "#"); } 
+               PS_D_IN_EVL = strzone(marker);
+       }
+
+       // now actually set the event data
+       db_put(PS_D_IN_DB, sprintf("#%s", event), data);
+       print("Added item ", sprintf("#%s", event), "=", data, " to PS_D_IN_DB\n");
+}
 
+void PlayerStats_PlayerDetail(void)
+{
        if((autocvar_g_playerstats_playerdetail_uri != "") && (crypto_getmyidstatus(0) > 0))
        {
+               // create the database if it doesn't already exist
+               if(PS_D_IN_DB < 0)
+               {
+                       PS_D_IN_DB = -1;
+                       PS_D_IN_DB = db_create();
+               }
+
                //uri = strcat(uri, "/player/", uri_escape(crypto_getmyidfp(0)));
                print("Retrieving playerstats from URL: ", autocvar_g_playerstats_playerdetail_uri, "\n");
                url_single_fopen(
@@ -594,103 +631,174 @@ void PlayerStats_PlayerDetail()
                        PlayerStats_PlayerDetail_Handler,
                        world
                );
+
+               PlayerStats_PlayerDetail_Status = PS_D_STATUS_WAITING;
+       }
+       else
+       {
+               // player has this disabled, kill the DB and set status to idle
+               if(PS_D_IN_DB >= 0)
+               {
+                       db_close(PS_D_IN_DB);
+                       PS_D_IN_DB = -1;
+               }
+
+               PlayerStats_PlayerDetail_Status = PS_D_STATUS_IDLE;
        }
 }
 
-void PlayerStats_PlayerDetail_Handler(entity fh, entity p, float status)
+void PlayerStats_PlayerDetail_CheckUpdate(void)
+{
+       // determine whether we should retrieve playerdetail information again
+       float gamecount = cvar("cl_matchcount");
+
+       #if 0
+       printf("PlayerStats_PlayerDetail_CheckUpdate(): %f >= %f, %d > %d\n",
+               time,
+               PS_D_NEXTUPDATETIME,
+               PS_D_LASTGAMECOUNT,
+               gamecount
+       );
+       #endif
+
+       if(
+               (time >= PS_D_NEXTUPDATETIME)
+               ||
+               (gamecount > PS_D_LASTGAMECOUNT)
+       )
+       {
+               PlayerStats_PlayerDetail();
+               PS_D_NEXTUPDATETIME = (time + autocvar_g_playerstats_playerdetail_autoupdatetime);
+               PS_D_LASTGAMECOUNT = gamecount;
+       }
+}
+
+void PlayerStats_PlayerDetail_Handler(entity fh, entity unused, float status)
 {
        switch(status)
        {
                case URL_READY_CANWRITE:
                {
-                       print("-- Sending data to player stats server\n");
-                       /*url_fputs(fh, "V 1\n");
+                       print("PlayerStats_PlayerDetail_Handler(): Sending data to player stats server...\n");
+                       url_fputs(fh, "V 1\n");
                        #ifdef WATERMARK
                        url_fputs(fh, sprintf("R %s\n", WATERMARK));
                        #endif
                        url_fputs(fh, sprintf("l %s\n", cvar_string("_menu_prvm_language"))); // language
-                       url_fputs(fh, sprintf("c %s\n", cvar_string("_menu_prvm_country"))); // country
-                       url_fputs(fh, sprintf("g %s\n", cvar_string("_menu_prvm_gender"))); // gender
+                       //url_fputs(fh, sprintf("c %s\n", cvar_string("_cl_country"))); // country
+                       //url_fputs(fh, sprintf("g %s\n", cvar_string("_cl_gender"))); // gender
                        url_fputs(fh, sprintf("n %s\n", cvar_string("_cl_name"))); // name
                        url_fputs(fh, sprintf("m %s %s\n", cvar_string("_cl_playermodel"), cvar_string("_cl_playerskin"))); // model/skin
-                       */url_fputs(fh, "\n");
+                       url_fputs(fh, "\n");
                        url_fclose(fh);
                        break;
                }
                
                case URL_READY_CANREAD:
                {
-                       string s = "";
-                       print("-- Got response from player stats server:\n");
-                       //string gametype = string_null;
-                       while((s = url_fgets(fh)))
+                       //print("PlayerStats_PlayerDetail_Handler(): Got response from player stats server:\n");
+                       string input = "";
+                       string gametype = "overall";
+                       while((input = url_fgets(fh)))
                        {
-                               print("  ", s, "\n");
-                               /*
-                               string key = "", value = "", data = "";
+                               float count = tokenizebyseparator(input, " ");
+                               string key = "", event = "", data = "";
 
-                               n = tokenizebyseparator(s, " "); // key (value) data
-                               if (n == 1)
-                                       continue;
-                               else if (n == 2)
+                               if(argv(0) == "#") { continue; }
+                               
+                               if(count == 2)
                                {
-                               key = argv(0);
-                               data = argv(1);
+                                       key = argv(0);
+                                       data = substring(input, argv_start_index(1), strlen(input) - argv_start_index(1));
                                }
-                               else if (n >= 3)
+                               else if(count >= 3)
                                {
-                                                               key = argv(0);
-                                                               value = argv(1);
-                                                               data = argv(2);
+                                       key = argv(0);
+                                       event = argv(1);
+                                       data = substring(input, argv_start_index(2), strlen(input) - argv_start_index(2));
                                }
+                               else { continue; }
 
-                               if (data == "")
-                               continue;
-
-                               if (key == "#")
-                               continue;
-                               else if (key == "V")
-                               PlayerInfo_AddItem(p, "_version", data);
-                               else if (key == "R")
-                               PlayerInfo_AddItem(p, "_release", data);
-                               else if (key == "T")
-                               PlayerInfo_AddItem(p, "_time", data);
-                               else if (key == "S")
-                               PlayerInfo_AddItem(p, "_statsurl", data);
-                               else if (key == "P")
-                               PlayerInfo_AddItem(p, "_hashkey", data);
-                               else if (key == "n")
-                               PlayerInfo_AddItem(p, "_playernick", data);
-                               else if (key == "i")
-                               PlayerInfo_AddItem(p, "_playerid", data);
-                               else if (key == "G")
-                               gametype = data;
-                               else if (key == "e" && value != "")
+                               switch(key)
                                {
-                               if (gametype == "")
-                               PlayerInfo_AddItem(p, value, data);
-                               else
-                               PlayerInfo_AddItem(p, sprintf("%s/%s", gametype, value), data);
+                                       // general info
+                                       case "V": PlayerStats_PlayerDetail_AddItem("version", data); break;
+                                       case "R": PlayerStats_PlayerDetail_AddItem("release", data); break;
+                                       case "T": PlayerStats_PlayerDetail_AddItem("time", data); break;
+
+                                       // player info
+                                       case "S": PlayerStats_PlayerDetail_AddItem("statsurl", data); break;
+                                       case "P": PlayerStats_PlayerDetail_AddItem("hashkey", data); break;
+                                       case "n": PlayerStats_PlayerDetail_AddItem("playernick", data); break;
+                                       case "i": PlayerStats_PlayerDetail_AddItem("playerid", data); break;
+
+                                       // other/event info
+                                       case "G": gametype = data; break;
+                                       case "e":
+                                       {
+                                               if(event != "" && data != "")
+                                               {
+                                                       PlayerStats_PlayerDetail_AddItem(
+                                                               sprintf(
+                                                                       "%s/%s",
+                                                                       gametype,
+                                                                       event
+                                                               ),
+                                                               data
+                                                       );
+                                               }
+                                               break;
+                                       }
+                                       
+                                       default:
+                                       {
+                                               print(sprintf(
+                                                       "PlayerStats_PlayerDetail_Handler(): ERROR: "
+                                                       "Key went unhandled? Is our version outdated?\n"
+                                                       "PlayerStats_PlayerDetail_Handler(): "
+                                                       "Key '%s', Event '%s', Data '%s'\n",
+                                                       key,
+                                                       event,
+                                                       data
+                                               ));
+                                               break;
+                                       }
                                }
-                               else
-                               continue;
-                               */
+
+                               #if 0
+                               print(sprintf(
+                                       "PlayerStats_PlayerDetail_Handler(): "
+                                       "Key '%s', Event '%s', Data '%s'\n",
+                                       key,
+                                       event,
+                                       data
+                               ));
+                               #endif
                        }
-                       print("-- End of response.\n");
+                       //print("PlayerStats_PlayerDetail_Handler(): End of response.\n");
                        url_fclose(fh);
+                       PlayerStats_PlayerDetail_Status = PS_D_STATUS_RECEIVED;
+                       statslist.getStats(statslist);
                        break;
                }
+
                case URL_READY_CLOSED:
                {
                        // url_fclose has finished
-                       print("Player stats synchronized with server\n");
+                       print("PlayerStats_PlayerDetail_Handler(): Player stats synchronized with server.\n");
                        break;
                }
-               
+
                case URL_READY_ERROR:
                default:
                {
-                       print("Receiving player stats failed: ", ftos(status), "\n");
+                       print("PlayerStats_PlayerDetail_Handler(): Receiving player stats failed: ", ftos(status), "\n");
+                       PlayerStats_PlayerDetail_Status = PS_D_STATUS_ERROR;
+                       if(PS_D_IN_DB >= 0)
+                       {
+                               db_close(PS_D_IN_DB);
+                               PS_D_IN_DB = -1;
+                       }
                        break;
                }
        }