]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/common/playerstats.qc
Merge branch 'master' into TimePath/scrollpanel
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / playerstats.qc
index 7e99bebea7480cfe32a9e32e670b3e58945f2a5e..0fcd70dfc08fd8e7afd9bdc2cd2b31c063331c79 100644 (file)
@@ -1,13 +1,14 @@
+#include "playerstats.qh"
 #if defined(CSQC)
 #elif defined(MENUQC)
 #elif defined(SVQC)
     #include "constants.qh"
     #include "util.qh"
-    #include <common/weapons/all.qh>
-    #include "../server/weapons/accuracy.qh"
+    #include <common/weapons/_all.qh>
+    #include "../server/anticheat.qh"
     #include "../server/defs.qh"
-    #include "playerstats.qh"
     #include "../server/scores.qh"
+    #include "../server/weapons/accuracy.qh"
 #endif
 
 #ifdef SVQC
@@ -21,9 +22,9 @@ void PlayerStats_GameReport_AddPlayer(entity e)
        if((PS_GR_OUT_DB < 0) || (e.playerstats_id)) { return; }
 
        // set up player identification
-       string s = string_null;
+       string s = "";
 
-       if((e.crypto_idfp != "") && (e.cvar_cl_allow_uidtracking == 1))
+       if((e.crypto_idfp != "") && (CS(e).cvar_cl_allow_uidtracking == 1))
                { s = e.crypto_idfp; }
        else if(IS_BOT_CLIENT(e))
                { s = sprintf("bot#%g#%s", skill, e.cleanname); }
@@ -92,7 +93,6 @@ void PlayerStats_GameReport_AddEvent(string event_id)
        }
 }
 
-// referred to by PS_GR_P_ADDVAL and PS_GR_T_ADDVAL
 float PlayerStats_GameReport_Event(string prefix, string event_id, float value)
 {
        if((prefix == "") || PS_GR_OUT_DB < 0) { return 0; }
@@ -107,7 +107,8 @@ float PlayerStats_GameReport_Event(string prefix, string event_id, float value)
 void PlayerStats_GameReport_Accuracy(entity p)
 {
        #define ACCMAC(suffix, field) \
-               PS_GR_P_ADDVAL(p, sprintf("acc-%s-%s", it.netname, suffix), p.accuracy.(field[i-1]));
+               PlayerStats_GameReport_Event_Player(p, \
+                       sprintf("acc-%s-%s", it.netname, suffix), CS(p).accuracy.(field[i-1]));
        FOREACH(Weapons, it != WEP_Null, {
                ACCMAC("hit", accuracy_hit)
                ACCMAC("fired", accuracy_fired)
@@ -125,29 +126,31 @@ void PlayerStats_GameReport_FinalizePlayer(entity p)
        // add global info!
        if(p.alivetime)
        {
-               PS_GR_P_ADDVAL(p, PLAYERSTATS_ALIVETIME, time - p.alivetime);
+               PlayerStats_GameReport_Event_Player(p, PLAYERSTATS_ALIVETIME, time - p.alivetime);
                p.alivetime = 0;
        }
 
        db_put(PS_GR_OUT_DB, sprintf("%s:_playerid", p.playerstats_id), ftos(p.playerid));
 
-       if(p.cvar_cl_allow_uid2name == 1 || IS_BOT_CLIENT(p))
-               db_put(PS_GR_OUT_DB, sprintf("%s:_netname", p.playerstats_id), p.netname);
+       if(CS(p).cvar_cl_allow_uid2name == 1 || IS_BOT_CLIENT(p))
+               db_put(PS_GR_OUT_DB, sprintf("%s:_netname", p.playerstats_id), playername(p, false));
 
        if(teamplay)
                db_put(PS_GR_OUT_DB, sprintf("%s:_team", p.playerstats_id), ftos(p.team));
 
        if(stof(db_get(PS_GR_OUT_DB, sprintf("%s:%s", p.playerstats_id, PLAYERSTATS_ALIVETIME))) > 0)
-               PS_GR_P_ADDVAL(p, PLAYERSTATS_JOINS, 1);
+               PlayerStats_GameReport_Event_Player(p, PLAYERSTATS_JOINS, 1);
 
        PlayerStats_GameReport_Accuracy(p);
+       anticheat_report_to_playerstats(p);
 
        if(IS_REAL_CLIENT(p))
        {
-               if(p.latency_cnt)
+               if(CS(p).latency_cnt)
                {
-                       float latency = (p.latency_sum / p.latency_cnt);
-                       if(latency) { PS_GR_P_ADDVAL(p, PLAYERSTATS_AVGLATENCY, latency); }
+                       float latency = (CS(p).latency_sum / CS(p).latency_cnt);
+                       if(latency)
+                               PlayerStats_GameReport_Event_Player(p, PLAYERSTATS_AVGLATENCY, latency);
                }
        }
 
@@ -165,16 +168,16 @@ void PlayerStats_GameReport(float finished)
 
        FOREACH_CLIENT(true, {
                // add personal score rank
-               PS_GR_P_ADDVAL(it, PLAYERSTATS_RANK, it.score_dummyfield);
+               PlayerStats_GameReport_Event_Player(it, PLAYERSTATS_RANK, it.score_dummyfield);
 
                // scoreboard data
                if(it.scoreboard_pos)
                {
                        // scoreboard is valid!
-                       PS_GR_P_ADDVAL(it, PLAYERSTATS_SCOREBOARD_VALID, 1);
+                       PlayerStats_GameReport_Event_Player(it, PLAYERSTATS_SCOREBOARD_VALID, 1);
 
                        // add scoreboard position
-                       PS_GR_P_ADDVAL(it, PLAYERSTATS_SCOREBOARD_POS, it.scoreboard_pos);
+                       PlayerStats_GameReport_Event_Player(it, PLAYERSTATS_SCOREBOARD_POS, it.scoreboard_pos);
 
                        // add scoreboard data
                        PlayerScore_PlayerStats(it);
@@ -182,8 +185,8 @@ void PlayerStats_GameReport(float finished)
                        // if the match ended normally, add winning info
                        if(finished)
                        {
-                               PS_GR_P_ADDVAL(it, PLAYERSTATS_WINS, it.winning);
-                               PS_GR_P_ADDVAL(it, PLAYERSTATS_MATCHES, 1);
+                               PlayerStats_GameReport_Event_Player(it, PLAYERSTATS_WINS, it.winning);
+                               PlayerStats_GameReport_Event_Player(it, PLAYERSTATS_MATCHES, 1);
                        }
                }
 
@@ -249,10 +252,26 @@ void PlayerStats_GameReport_Init() // initiated before InitGameplayMode so that
                PlayerStats_GameReport_AddEvent(PLAYERSTATS_ACHIEVEMENT_BOTLIKE);
                PlayerStats_GameReport_AddEvent(PLAYERSTATS_ACHIEVEMENT_FIRSTBLOOD);
                PlayerStats_GameReport_AddEvent(PLAYERSTATS_ACHIEVEMENT_FIRSTVICTIM);
+
+               anticheat_register_to_playerstats();
        }
        else { PlayerStats_GameReport_DelayMapVote = false; }
 }
 
+// this... is a hack, a temporary one until we get a proper duel gametype
+string PlayerStats_GetGametype()
+{
+       if(IS_GAMETYPE(DEATHMATCH) && autocvar_g_maxplayers == 2)
+       {
+               // probably duel, but let's make sure
+               int plcount = 0;
+               FOREACH_CLIENT(IS_PLAYER(it), ++plcount);
+               if(plcount <= 2)
+                       return "duel";
+       }
+       return GetGametype();
+}
+
 void PlayerStats_GameReport_Handler(entity fh, entity pass, float status)
 {
        string t, tn;
@@ -309,7 +328,7 @@ void PlayerStats_GameReport_Handler(entity fh, entity pass, float status)
                        #ifdef WATERMARK
                        url_fputs(fh, sprintf("R %s\n", WATERMARK));
                        #endif
-                       url_fputs(fh, sprintf("G %s\n", GetGametype()));
+                       url_fputs(fh, sprintf("G %s\n", PlayerStats_GetGametype()));
                        url_fputs(fh, sprintf("O %s\n", modname));
                        url_fputs(fh, sprintf("M %s\n", GetMapname()));
                        url_fputs(fh, sprintf("I %s\n", matchid));
@@ -379,9 +398,9 @@ void PlayerStats_GameReport_Handler(entity fh, entity pass, float status)
                {
                        // url_fclose is processing, we got a response for writing the data
                        // this must come from HTTP
-                       LOG_TRACE("Got response from player stats server:\n");
-                       while((s = url_fgets(fh))) { LOG_TRACE("  ", s, "\n"); }
-                       LOG_TRACE("End of response.\n");
+                       LOG_TRACE("Got response from player stats server:");
+                       while((s = url_fgets(fh))) { LOG_TRACE("  ", s); }
+                       LOG_TRACE("End of response.");
                        url_fclose(fh);
                        break;
                }
@@ -389,7 +408,7 @@ void PlayerStats_GameReport_Handler(entity fh, entity pass, float status)
                case URL_READY_CLOSED:
                {
                        // url_fclose has finished
-                       LOG_TRACE("Player stats written\n");
+                       LOG_TRACE("Player stats written");
                        PlayerStats_GameReport_DelayMapVote = false;
                        if(PS_GR_OUT_DB >= 0)
                        {
@@ -402,7 +421,7 @@ void PlayerStats_GameReport_Handler(entity fh, entity pass, float status)
                case URL_READY_ERROR:
                default:
                {
-                       LOG_INFO("Player stats writing failed: ", ftos(status), "\n");
+                       LOG_INFO("Player stats writing failed: ", ftos(status));
                        PlayerStats_GameReport_DelayMapVote = false;
                        if(PS_GR_OUT_DB >= 0)
                        {
@@ -416,19 +435,21 @@ void PlayerStats_GameReport_Handler(entity fh, entity pass, float status)
 
 void PlayerStats_PlayerBasic(entity joiningplayer, float newrequest)
 {
+       GameRules_scoring_add(joiningplayer, ELO, -1);
        // http://stats.xonotic.org/player/GgXRw6piDtFIbMArMuiAi8JG4tiin8VLjZgsKB60Uds=/elo.txt
        if(autocvar_g_playerstats_playerbasic_uri != "")
        {
                string uri = autocvar_g_playerstats_playerbasic_uri;
-               if(joiningplayer.crypto_idfp != "")
-               {
+               if (joiningplayer.crypto_idfp == "") {
+                       GameRules_scoring_add(joiningplayer, ELO, -1);
+               } else {
                        // create the database if it doesn't already exist
                        if(PS_B_IN_DB < 0)
                                PS_B_IN_DB = db_create();
 
                        // now request the information
                        uri = strcat(uri, "/player/", uri_escape(uri_escape(uri_escape(joiningplayer.crypto_idfp))), "/elo.txt");
-                       LOG_TRACE("Retrieving playerstats from URL: ", uri, "\n");
+                       LOG_TRACE("Retrieving playerstats from URL: ", uri);
                        url_single_fopen(
                                uri,
                                FILE_APPEND,
@@ -452,6 +473,7 @@ void PlayerStats_PlayerBasic(entity joiningplayer, float newrequest)
        else
        {
                // server has this disabled, kill the DB and set status to idle
+               GameRules_scoring_add(joiningplayer, ELO, -1);
                if(PS_B_IN_DB >= 0)
                {
                        db_close(PS_B_IN_DB);
@@ -466,12 +488,10 @@ void PlayerStats_PlayerBasic_CheckUpdate(entity joiningplayer)
 {
        // determine whether we should retrieve playerbasic information again
 
-       #if 0
-       LOG_INFOF("PlayerStats_PlayerBasic_CheckUpdate('%s'): %f\n",
+       LOG_TRACEF("PlayerStats_PlayerBasic_CheckUpdate('%s'): %f",
                joiningplayer.netname,
                time
        );
-       #endif
 
        // TODO: check to see if this playerid is inside the database already somehow...
        // for now we'll just check the field, but this won't work for players who disconnect and reconnect properly
@@ -491,7 +511,7 @@ void PlayerStats_PlayerBasic_Handler(entity fh, entity p, float status)
        {
                case URL_READY_CANWRITE:
                {
-                       LOG_TRACE("-- Sending data to player stats server\n");
+                       LOG_TRACE("-- Sending data to player stats server");
                        /*url_fputs(fh, "V 1\n");
                        #ifdef WATERMARK
                        url_fputs(fh, sprintf("R %s\n", WATERMARK));
@@ -503,85 +523,86 @@ void PlayerStats_PlayerBasic_Handler(entity fh, entity p, float status)
                        url_fputs(fh, sprintf("m %s %s\n", cvar_string("_cl_playermodel"), cvar_string("_cl_playerskin"))); // model/skin
                        */url_fputs(fh, "\n");
                        url_fclose(fh);
-                       break;
+                       return;
                }
 
                case URL_READY_CANREAD:
                {
-                       string s = "";
-                       LOG_TRACE("-- Got response from player stats server:\n");
-                       //string gametype = string_null;
-                       while((s = url_fgets(fh)))
-                       {
-                               LOG_TRACE("  ", s, "\n");
-                               /*
+                       bool handled = false;
+                       string gt = string_null;
+                       for (string s = ""; (s = url_fgets(fh)); ) {
+                               int n = tokenizebyseparator(s, " "); // key value? data
+                               if (n == 1) continue;
                                string key = "", value = "", data = "";
-
-                               n = tokenizebyseparator(s, " "); // key (value) data
-                               if (n == 1)
-                                       continue;
-                               else if (n == 2)
-                               {
-                               key = argv(0);
-                               data = argv(1);
-                               }
-                               else if (n >= 3)
-                               {
-                                                               key = argv(0);
-                                                               value = argv(1);
-                                                               data = argv(2);
-                               }
-
-                               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 != "")
-                               {
-                               if (gametype == "")
-                               PlayerInfo_AddItem(p, value, data);
-                               else
-                               PlayerInfo_AddItem(p, sprintf("%s/%s", gametype, value), data);
+                               if (n == 2) {
+                    key = argv(0);
+                    data = argv(1);
+                               } else if (n >= 3) {
+                    key = argv(0);
+                    value = argv(1);
+                    data = argv(2);
                                }
-                               else
-                               continue;
-                               */
+                switch (key) {
+                    case "V":
+                        // PlayerInfo_AddItem(p, "_version", data);
+                        break;
+                    case "R":
+                        // PlayerInfo_AddItem(p, "_release", data);
+                        break;
+                    case "T":
+                        // PlayerInfo_AddItem(p, "_time", data);
+                        break;
+                    case "S":
+                        // PlayerInfo_AddItem(p, "_statsurl", data);
+                        break;
+                    case "P":
+                        // PlayerInfo_AddItem(p, "_hashkey", data);
+                        break;
+                    case "n":
+                        // PlayerInfo_AddItem(p, "_playernick", data);
+                        break;
+                    case "i":
+                        // PlayerInfo_AddItem(p, "_playerid", data);
+                        // p.xonstat_id = stof(data);
+                        break;
+                    case "G":
+                        gt = data;
+                        break;
+                    case "e":
+                        LOG_TRACE("G: ", gt);
+                        LOG_TRACE("e: ", data);
+                        if (gt == PlayerStats_GetGametype()) {
+                            handled = true;
+                            float e = stof(data);
+                            GameRules_scoring_add(p, ELO, +1 + e);
+                        }
+                        if (gt == "") {
+                            // PlayerInfo_AddItem(p, value, data);
+                        } else {
+                            // PlayerInfo_AddItem(p, sprintf("%s/%s", gt, value), data);
+                        }
+                        break;
+                }
                        }
-                       LOG_TRACE("-- End of response.\n");
                        url_fclose(fh);
+                       if (handled) return;
                        break;
                }
                case URL_READY_CLOSED:
                {
                        // url_fclose has finished
-                       LOG_INFO("Player stats synchronized with server\n");
-                       break;
+                       LOG_INFO("Player stats synchronized with server");
+                       return;
                }
 
                case URL_READY_ERROR:
                default:
                {
-                       LOG_INFO("Receiving player stats failed: ", ftos(status), "\n");
+                       LOG_INFO("Receiving player stats failed: ", ftos(status));
                        break;
                }
        }
+       GameRules_scoring_add(p, ELO, -1);
 }
 #endif // SVQC
 
@@ -593,7 +614,7 @@ void PlayerStats_PlayerBasic_Handler(entity fh, entity p, float status)
        float i = 0;
        for(e = PS_D_IN_EVL; (en = db_get(PS_D_IN_DB, e)) != ""; e = en)
        {
-               LOG_INFO(sprintf("%d:%s:%s\n", i, e, db_get(PS_D_IN_DB, sprintf("#%s", e))));
+               LOG_INFOF("%d:%s:%s", i, e, db_get(PS_D_IN_DB, sprintf("#%s", e)));
                ++i;
        }
 #endif
@@ -617,7 +638,7 @@ void PlayerStats_PlayerDetail_AddItem(string event, string data)
 
        // now actually set the event data
        db_put(PS_D_IN_DB, sprintf("#%s", event), data);
-       LOG_TRACE("Added item ", sprintf("#%s", event), "=", data, " to PS_D_IN_DB\n");
+       LOG_TRACE("Added item ", sprintf("#%s", event), "=", data, " to PS_D_IN_DB");
 }
 
 void PlayerStats_PlayerDetail()
@@ -630,7 +651,7 @@ void PlayerStats_PlayerDetail()
                        PS_D_IN_DB = db_create();
 
                //uri = strcat(uri, "/player/", uri_escape(crypto_getmyidfp(0)));
-               LOG_TRACE("Retrieving playerstats from URL: ", autocvar_g_playerstats_playerdetail_uri, "\n");
+               LOG_TRACE("Retrieving playerstats from URL: ", autocvar_g_playerstats_playerdetail_uri);
                url_single_fopen(
                        autocvar_g_playerstats_playerdetail_uri,
                        FILE_APPEND,
@@ -659,7 +680,7 @@ void PlayerStats_PlayerDetail_CheckUpdate()
        float gamecount = cvar("cl_matchcount");
 
        #if 0
-       LOG_INFOF("PlayerStats_PlayerDetail_CheckUpdate(): %f >= %f, %d > %d\n",
+       LOG_INFOF("PlayerStats_PlayerDetail_CheckUpdate(): %f >= %f, %d > %d",
                time,
                PS_D_NEXTUPDATETIME,
                PS_D_LASTGAMECOUNT,
@@ -685,7 +706,7 @@ void PlayerStats_PlayerDetail_Handler(entity fh, entity unused, float status)
        {
                case URL_READY_CANWRITE:
                {
-                       LOG_TRACE("PlayerStats_PlayerDetail_Handler(): Sending data to player stats server...\n");
+                       LOG_TRACE("PlayerStats_PlayerDetail_Handler(): Sending data to player stats server...");
                        url_fputs(fh, "V 1\n");
                        #ifdef WATERMARK
                        url_fputs(fh, sprintf("R %s\n", WATERMARK));
@@ -762,7 +783,7 @@ void PlayerStats_PlayerDetail_Handler(entity fh, entity unused, float status)
                                                        "PlayerStats_PlayerDetail_Handler(): ERROR: "
                                                        "Key went unhandled? Is our version outdated?\n"
                                                        "PlayerStats_PlayerDetail_Handler(): "
-                                                       "Key '%s', Event '%s', Data '%s'\n",
+                                                       "Key '%s', Event '%s', Data '%s'",
                                                        key,
                                                        event,
                                                        data
@@ -772,13 +793,13 @@ void PlayerStats_PlayerDetail_Handler(entity fh, entity unused, float status)
                                }
 
                                #if 0
-                               LOG_INFO(sprintf(
+                               LOG_INFOF(
                                        "PlayerStats_PlayerDetail_Handler(): "
-                                       "Key '%s', Event '%s', Data '%s'\n",
+                                       "Key '%s', Event '%s', Data '%s'",
                                        key,
                                        event,
                                        data
-                               ));
+                               );
                                #endif
                        }
                        //print("PlayerStats_PlayerDetail_Handler(): End of response.\n");
@@ -791,14 +812,14 @@ void PlayerStats_PlayerDetail_Handler(entity fh, entity unused, float status)
                case URL_READY_CLOSED:
                {
                        // url_fclose has finished
-                       LOG_INFO("PlayerStats_PlayerDetail_Handler(): Player stats synchronized with server.\n");
+                       LOG_INFO("PlayerStats_PlayerDetail_Handler(): Player stats synchronized with server.");
                        break;
                }
 
                case URL_READY_ERROR:
                default:
                {
-                       LOG_INFO("PlayerStats_PlayerDetail_Handler(): Receiving player stats failed: ", ftos(status), "\n");
+                       LOG_INFO("PlayerStats_PlayerDetail_Handler(): Receiving player stats failed: ", ftos(status));
                        PlayerStats_PlayerDetail_Status = PS_D_STATUS_ERROR;
                        if(PS_D_IN_DB >= 0)
                        {