20 REPLICATE(cvar_cl_allow_uid2name,
int,
"cl_allow_uid2name");
21 REPLICATE(cvar_cl_allow_uidranking,
bool,
"cl_allow_uidranking");
22 REPLICATE(cvar_cl_allow_uidtracking,
int,
"cl_allow_uidtracking");
30 void PlayerStats_Prematch()
36 void PlayerStats_GameReport_Reset_All()
42 if (PS_GR_OUT_DB >= 0)
44 PlayerStats_GameReport_Init();
48 for (
int i = 0; i < 16; i++)
50 PlayerStats_GameReport_AddTeam(i + 1);
55 PlayerStats_GameReport_AddEvent(sprintf(
"kills-%d", it.playerid));
56 PlayerStats_GameReport_AddPlayer(it);
62 PlayerStats_GameReport_AddEvent(
strcat(PLAYERSTATS_TOTAL, label));
63 PlayerStats_GameReport_AddEvent(
strcat(PLAYERSTATS_SCOREBOARD, label));
70 PlayerStats_GameReport_AddEvent(
strcat(PLAYERSTATS_TOTAL, label));
71 PlayerStats_GameReport_AddEvent(
strcat(PLAYERSTATS_SCOREBOARD, label));
75 void PlayerStats_GameReport_AddPlayer(
entity e)
77 if((PS_GR_OUT_DB < 0) || (e.playerstats_id)) {
return; }
82 if((e.crypto_idfp !=
"") && (
CS_CVAR(e).cvar_cl_allow_uidtracking == 1))
83 { s = e.crypto_idfp; }
85 { s = sprintf(
"bot#%g#%s",
skill, e.cleanname); }
87 if((s ==
"") ||
find(
NULL, playerstats_id, s))
90 { s = sprintf(
"bot#%d", e.playerid); }
92 { s = sprintf(
"player#%d", e.playerid); }
98 string key = sprintf(
"%s:*", e.playerstats_id);
99 string p =
db_get(PS_GR_OUT_DB, key);
105 db_put(PS_GR_OUT_DB, key, PS_GR_OUT_PL);
108 else {
db_put(PS_GR_OUT_DB, key,
"#"); }
109 PS_GR_OUT_PL =
strzone(e.playerstats_id);
113 void PlayerStats_GameReport_AddTeam(
int t)
115 if(PS_GR_OUT_DB < 0) {
return; }
117 string key = sprintf(
"%d", t);
118 string p =
db_get(PS_GR_OUT_DB, key);
124 db_put(PS_GR_OUT_DB, key, PS_GR_OUT_TL);
127 else {
db_put(PS_GR_OUT_DB, key,
"#"); }
132 void PlayerStats_GameReport_AddEvent(
string event_id)
134 if(PS_GR_OUT_DB < 0) {
return; }
136 string key = sprintf(
"*:%s", event_id);
137 string p =
db_get(PS_GR_OUT_DB, key);
143 db_put(PS_GR_OUT_DB, key, PS_GR_OUT_EVL);
146 else {
db_put(PS_GR_OUT_DB, key,
"#"); }
147 PS_GR_OUT_EVL =
strzone(event_id);
151 float PlayerStats_GameReport_Event(
string prefix,
string event_id,
float value)
153 if((prefix ==
"") || PS_GR_OUT_DB < 0) {
return 0; }
155 string key = sprintf(
"%s:%s", prefix, event_id);
162 void PlayerStats_GameReport_Accuracy(
entity p)
164 #define ACCMAC(suffix, field) \ 165 PlayerStats_GameReport_Event_Player(p, \ 166 sprintf("acc-%s-%s", it.netname, suffix), CS(p).accuracy.(field[i-1])); 167 FOREACH(Weapons, it != WEP_Null, {
177 void PlayerStats_GameReport_FinalizePlayer(
entity p)
179 if((p.playerstats_id ==
"") || PS_GR_OUT_DB < 0) {
return; }
184 PlayerStats_GameReport_Event_Player(p, PLAYERSTATS_ALIVETIME,
time - p.alivetime);
188 db_put(PS_GR_OUT_DB, sprintf(
"%s:_playerid", p.playerstats_id),
ftos(p.playerid));
191 db_put(PS_GR_OUT_DB, sprintf(
"%s:_netname", p.playerstats_id), playername(p.netname, p.team,
false));
194 db_put(PS_GR_OUT_DB, sprintf(
"%s:_team", p.playerstats_id),
ftos(p.team));
196 if(
stof(
db_get(PS_GR_OUT_DB, sprintf(
"%s:%s", p.playerstats_id, PLAYERSTATS_ALIVETIME))) > 0)
197 PlayerStats_GameReport_Event_Player(p, PLAYERSTATS_JOINS, 1);
199 PlayerStats_GameReport_Accuracy(p);
206 float latency = (
CS(p).latency_sum /
CS(p).latency_cnt);
208 PlayerStats_GameReport_Event_Player(p, PLAYERSTATS_AVGLATENCY, latency);
211 db_put(PS_GR_OUT_DB, sprintf(
"%s:_ranked", p.playerstats_id),
ftos(
CS_CVAR(p).cvar_cl_allow_uidranking));
217 void PlayerStats_GameReport(
bool finished)
219 if(PS_GR_OUT_DB < 0) {
return; }
227 PlayerStats_GameReport_Event_Player(it, PLAYERSTATS_RANK, it.score_dummyfield);
230 if(it.scoreboard_pos)
233 PlayerStats_GameReport_Event_Player(it, PLAYERSTATS_SCOREBOARD_VALID, 1);
236 PlayerStats_GameReport_Event_Player(it, PLAYERSTATS_SCOREBOARD_POS, it.scoreboard_pos);
244 PlayerStats_GameReport_Event_Player(it, PLAYERSTATS_WINS, it.winning);
245 PlayerStats_GameReport_Event_Player(it, PLAYERSTATS_MATCHES, 1);
250 PlayerStats_GameReport_FinalizePlayer(it);
253 if(autocvar_g_playerstats_gamereport_uri !=
"")
255 PlayerStats_GameReport_DelayMapVote =
true;
257 autocvar_g_playerstats_gamereport_uri,
259 PlayerStats_GameReport_Handler,
265 PlayerStats_GameReport_DelayMapVote =
false;
271 void PlayerStats_GameReport_Init()
273 if(autocvar_g_playerstats_gamereport_uri ==
"") {
return; }
277 if(PS_GR_OUT_DB >= 0)
279 PlayerStats_GameReport_DelayMapVote =
true;
282 if(autocvar_g_playerstats_gamereport_uri !=
cvar_defstring(
"g_playerstats_gamereport_uri"))
287 PlayerStats_GameReport_AddEvent(PLAYERSTATS_ALIVETIME);
288 PlayerStats_GameReport_AddEvent(PLAYERSTATS_AVGLATENCY);
289 PlayerStats_GameReport_AddEvent(PLAYERSTATS_WINS);
290 PlayerStats_GameReport_AddEvent(PLAYERSTATS_MATCHES);
291 PlayerStats_GameReport_AddEvent(PLAYERSTATS_JOINS);
292 PlayerStats_GameReport_AddEvent(PLAYERSTATS_SCOREBOARD_VALID);
293 PlayerStats_GameReport_AddEvent(PLAYERSTATS_SCOREBOARD_POS);
294 PlayerStats_GameReport_AddEvent(PLAYERSTATS_RANK);
297 FOREACH(Weapons, it != WEP_Null, {
298 PlayerStats_GameReport_AddEvent(
strcat(
"acc-", it.netname,
"-hit"));
299 PlayerStats_GameReport_AddEvent(
strcat(
"acc-", it.netname,
"-fired"));
300 PlayerStats_GameReport_AddEvent(
strcat(
"acc-", it.netname,
"-cnt-hit"));
301 PlayerStats_GameReport_AddEvent(
strcat(
"acc-", it.netname,
"-cnt-fired"));
302 PlayerStats_GameReport_AddEvent(
strcat(
"acc-", it.netname,
"-frags"));
305 PlayerStats_GameReport_AddEvent(PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_3);
306 PlayerStats_GameReport_AddEvent(PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_5);
307 PlayerStats_GameReport_AddEvent(PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_10);
308 PlayerStats_GameReport_AddEvent(PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_15);
309 PlayerStats_GameReport_AddEvent(PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_20);
310 PlayerStats_GameReport_AddEvent(PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_25);
311 PlayerStats_GameReport_AddEvent(PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_30);
312 PlayerStats_GameReport_AddEvent(PLAYERSTATS_ACHIEVEMENT_BOTLIKE);
313 PlayerStats_GameReport_AddEvent(PLAYERSTATS_ACHIEVEMENT_FIRSTBLOOD);
314 PlayerStats_GameReport_AddEvent(PLAYERSTATS_ACHIEVEMENT_FIRSTVICTIM);
318 else { PlayerStats_GameReport_DelayMapVote =
false; }
323 string PlayerStats_GetGametype()
390 url_fputs(fh, sprintf(
"R %s\n", WATERMARK));
392 url_fputs(fh, sprintf(
"G %s\n", PlayerStats_GetGametype()));
400 url_fputs(fh, sprintf(
"L %s\n", autocvar_g_playerstats_gamereport_ladder));
405 for(t = PS_GR_OUT_TL; (tn =
db_get(PS_GR_OUT_DB, sprintf(
"%d",
stof(t)))) !=
""; t = tn)
408 url_fputs(fh, sprintf(
"Q team#%s\n", t));
411 for(e = PS_GR_OUT_EVL; (en =
db_get(PS_GR_OUT_DB, sprintf(
"*:%s", e))) !=
""; e = en)
413 float v =
stof(
db_get(PS_GR_OUT_DB, sprintf(
"team#%d:%s",
stof(t), e)));
414 if(v != 0) {
url_fputs(fh, sprintf(
"e %s %g\n", e, v)); }
420 for(p = PS_GR_OUT_PL; (pn =
db_get(PS_GR_OUT_DB, sprintf(
"%s:*", p))) !=
""; p = pn)
426 nn =
db_get(PS_GR_OUT_DB, sprintf(
"%s:_playerid", p));
427 if(nn !=
"") {
url_fputs(fh, sprintf(
"i %s\n", nn)); }
430 nn =
db_get(PS_GR_OUT_DB, sprintf(
"%s:_netname", p));
431 if(nn !=
"") {
url_fputs(fh, sprintf(
"n %s\n", nn)); }
436 tt =
db_get(PS_GR_OUT_DB, sprintf(
"%s:_team", p));
441 nn =
db_get(PS_GR_OUT_DB, sprintf(
"%s:_ranked", p));
442 if(nn !=
"") {
url_fputs(fh, sprintf(
"r %s\n", nn)); }
445 for(e = PS_GR_OUT_EVL; (en =
db_get(PS_GR_OUT_DB, sprintf(
"*:%s", e))) !=
""; e = en)
447 float v =
stof(
db_get(PS_GR_OUT_DB, sprintf(
"%s:%s", p, e)));
448 if(v != 0) {
url_fputs(fh, sprintf(
"e %s %g\n", e, v)); }
466 LOG_DEBUG(
"Got response from player stats server:");
477 PlayerStats_GameReport_DelayMapVote =
false;
478 if(PS_GR_OUT_DB >= 0)
489 LOG_INFO(
"Player stats writing failed: ",
ftos(status));
490 PlayerStats_GameReport_DelayMapVote =
false;
491 if(PS_GR_OUT_DB >= 0)
501 void PlayerStats_PlayerBasic(
entity joiningplayer,
float newrequest)
505 if(autocvar_g_playerstats_playerbasic_uri !=
"")
507 string uri = autocvar_g_playerstats_playerbasic_uri;
508 if (joiningplayer.crypto_idfp ==
"") {
516 uri =
strcat(uri,
"/player/", uri_escape(uri_escape(uri_escape(joiningplayer.crypto_idfp))),
"/elo.txt");
517 LOG_DEBUG(
"Retrieving playerstats from URL: ", uri);
521 PlayerStats_PlayerBasic_Handler,
529 joiningplayer.playerstats_basicstatus = PS_B_STATUS_WAITING;
534 joiningplayer.playerstats_basicstatus = PS_B_STATUS_UPDATING;
552 SHUTDOWN(PlayerStats_PlayerBasic_Shutdown)
560 if(PS_GR_OUT_DB >= 0)
567 void PlayerStats_PlayerBasic_CheckUpdate(
entity joiningplayer)
571 LOG_DEBUGF(
"PlayerStats_PlayerBasic_CheckUpdate('%s'): %f",
572 joiningplayer.netname,
579 if(!joiningplayer.playerstats_basicstatus)
581 PlayerStats_PlayerBasic(
583 (joiningplayer.playerstats_basicstatus == PS_B_STATUS_RECEIVED)
588 void PlayerStats_PlayerBasic_Handler(
entity fh,
entity p,
float status)
594 LOG_DEBUG(
"-- Sending data to player stats server");
610 bool handled =
false;
612 for (
string s =
""; (s =
url_fgets(fh)); ) {
614 if (n == 1)
continue;
615 string key =
"", value =
"", data =
"";
653 if (gt == PlayerStats_GetGametype()) {
655 float e =
stof(data);
673 LOG_INFO(
"Player stats synchronized with server");
680 LOG_INFO(
"Receiving player stats failed: ",
ftos(status));
691 #if 0 // reading the entire DB at once 692 string e =
"", en =
"";
694 for(e = PS_D_IN_EVL; (en =
db_get(PS_D_IN_DB, e)) !=
""; e = en)
701 void PlayerStats_PlayerDetail_AddItem(
string event,
string data)
703 if(PS_D_IN_DB < 0) {
return; }
706 string marker = sprintf(
"%s", event);
707 if(
db_get(PS_D_IN_DB, marker) ==
"")
711 db_put(PS_D_IN_DB, marker, PS_D_IN_EVL);
714 else {
db_put(PS_D_IN_DB, marker,
"#"); }
719 db_put(PS_D_IN_DB, sprintf(
"#%s", event), data);
720 LOG_DEBUG(
"Added item ", sprintf(
"#%s", event),
"=", data,
" to PS_D_IN_DB");
723 void PlayerStats_PlayerDetail()
726 if((autocvar_g_playerstats_playerdetail_uri !=
"") && (crypto_getmyidstatus(0) > 0))
733 LOG_DEBUG(
"Retrieving playerstats from URL: ", autocvar_g_playerstats_playerdetail_uri);
735 autocvar_g_playerstats_playerdetail_uri,
737 PlayerStats_PlayerDetail_Handler,
741 PlayerStats_PlayerDetail_Status = PS_D_STATUS_WAITING;
752 PlayerStats_PlayerDetail_Status = PS_D_STATUS_IDLE;
756 void PlayerStats_PlayerDetail_CheckUpdate()
759 float gamecount =
cvar(
"cl_matchcount");
762 LOG_INFOF(
"PlayerStats_PlayerDetail_CheckUpdate(): %f >= %f, %d > %d",
771 (
time >= PS_D_NEXTUPDATETIME)
773 (gamecount > PS_D_LASTGAMECOUNT)
776 PlayerStats_PlayerDetail();
777 PS_D_NEXTUPDATETIME = (
time + autocvar_g_playerstats_playerdetail_autoupdatetime);
778 PS_D_LASTGAMECOUNT = gamecount;
782 void PlayerStats_PlayerDetail_Handler(
entity fh,
entity unused,
float status)
788 LOG_DEBUG(
"PlayerStats_PlayerDetail_Handler(): Sending data to player stats server...");
791 url_fputs(fh, sprintf(
"R %s\n", WATERMARK));
810 string key =
"",
event =
"", data =
"";
812 if(
argv(0) ==
"#") {
continue; }
830 case "V": PlayerStats_PlayerDetail_AddItem(
"version", data);
break;
831 case "R": PlayerStats_PlayerDetail_AddItem(
"release", data);
break;
832 case "T": PlayerStats_PlayerDetail_AddItem(
"time", data);
break;
835 case "S": PlayerStats_PlayerDetail_AddItem(
"statsurl", data);
break;
836 case "P": PlayerStats_PlayerDetail_AddItem(
"hashkey", data);
break;
837 case "n": PlayerStats_PlayerDetail_AddItem(
"playernick", data);
break;
838 case "i": PlayerStats_PlayerDetail_AddItem(
"playerid", data);
break;
841 case "G": gametype = data;
break;
844 if(event !=
"" && data !=
"")
846 PlayerStats_PlayerDetail_AddItem(
861 "PlayerStats_PlayerDetail_Handler(): ERROR: " 862 "Key went unhandled? Is our version outdated?\n" 863 "PlayerStats_PlayerDetail_Handler(): " 864 "Key '%s', Event '%s', Data '%s'",
875 "PlayerStats_PlayerDetail_Handler(): " 876 "Key '%s', Event '%s', Data '%s'",
885 PlayerStats_PlayerDetail_Status = PS_D_STATUS_RECEIVED;
893 LOG_INFO(
"PlayerStats_PlayerDetail_Handler(): Player stats synchronized with server.");
900 LOG_INFO(
"PlayerStats_PlayerDetail_Handler(): Receiving player stats failed: ",
ftos(status));
901 PlayerStats_PlayerDetail_Status = PS_D_STATUS_ERROR;
ERASEABLE int db_create()
ERASEABLE void db_put(int db, string key, string value)
const float URL_READY_CANREAD
const float URL_READY_CLOSED
void anticheat_report_to_playerstats(entity this)
const float URL_READY_CANWRITE
entity teamscorekeepers[16]
ClientState CS(Client this)
#define FOREACH_CLIENT(cond, body)
#define GameRules_scoring_add(client, fld, value)
REPLICATE(cvar_cl_casings, bool, "cl_casings")
ERASEABLE void db_close(int db)
float accuracy_frags[REGISTRY_MAX(Weapons)]
const int SERVERFLAG_PLAYERSTATS
const int SERVERFLAG_PLAYERSTATS_CUSTOM
#define IS_REAL_CLIENT(v)
void PlayerScore_PlayerStats(entity p)
#define teamscores_label(i)
void PlayerScore_TeamStats()
float cvar_purechanges_count
spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 f1 s1 strcat(_("Level %s: "), "^BG%s\3\, _("^BGPress ^F2%s^BG to enter the game"))
ERASEABLE void url_fputs(entity e, string s)
ERASEABLE void url_fclose(entity e)
#define IS_GAMETYPE(NAME)
float accuracy_cnt_hit[REGISTRY_MAX(Weapons)]
REPLICATE_APPLYCHANGE("cl_weaponpriority", for(int slot=0;slot< MAX_WEAPONSLOTS;++slot) { .entity weaponentity=weaponentities[slot];if(this.(weaponentity) &&(this.(weaponentity).m_weapon !=WEP_Null||slot==0)) this.(weaponentity).m_switchweapon=w_getbestweapon(this, weaponentity);})
void anticheat_register_to_playerstats()
#define SHUTDOWN(func)
before shutdown
ERASEABLE string db_get(int db, string key)
entity PlayerScore_Sort(.float field, int teams, bool strict, bool nospectators)
Sorts the players and stores their place in the given field, starting with.
ERASEABLE void url_single_fopen(string url, int mode, url_ready_func rdy, entity pass)
#define scores_label(this)
#define tokenizebyseparator
#define IS_BOT_CLIENT(v)
want: (IS_CLIENT(v) && !IS_REAL_CLIENT(v))
const float URL_READY_ERROR
float accuracy_fired[REGISTRY_MAX(Weapons)]
float accuracy_cnt_fired[REGISTRY_MAX(Weapons)]
float accuracy_hit[REGISTRY_MAX(Weapons)]
ERASEABLE void url_multi_fopen(string url, int mode, url_ready_func rdy, entity pass)
int autocvar_g_maxplayers
#define pass(name, colormin, colormax)
#define FOREACH(list, cond, body)
ERASEABLE string url_fgets(entity e)