]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/playerstats.qc
Merge branch 'master' into mirceakitsune/hud_postprocessing
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / playerstats.qc
1 float playerstats_db;
2 string playerstats_last;
3 string events_last;
4 .float playerstats_addedglobalinfo;
5 float playerstats_requested;
6 .string playerstats_id;
7
8 void PlayerStats_Init()
9 {
10         string uri;
11         playerstats_db = -1;
12         playerstats_waitforme = TRUE;
13         uri = autocvar_g_playerstats_uri;
14         if(uri == "")
15                 return;
16         playerstats_db = db_create();
17         if(playerstats_db >= 0)
18                 playerstats_waitforme = FALSE; // must wait for it at match end
19         
20         PlayerStats_AddEvent(PLAYERSTATS_ALIVETIME);
21         PlayerStats_AddEvent(PLAYERSTATS_WINS);
22         PlayerStats_AddEvent(PLAYERSTATS_MATCHES);
23         PlayerStats_AddEvent(PLAYERSTATS_JOINS);
24         PlayerStats_AddEvent(PLAYERSTATS_SCOREBOARD_VALID);
25
26         PlayerStats_AddEvent(PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_3);
27         PlayerStats_AddEvent(PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_5);
28         PlayerStats_AddEvent(PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_10);
29         PlayerStats_AddEvent(PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_15);
30         PlayerStats_AddEvent(PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_20);
31         PlayerStats_AddEvent(PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_25);
32         PlayerStats_AddEvent(PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_30);
33         PlayerStats_AddEvent(PLAYERSTATS_ACHIEVEMENT_BOTLIKE);
34         PlayerStats_AddEvent(PLAYERSTATS_ACHIEVEMENT_FIRSTBLOOD);
35         PlayerStats_AddEvent(PLAYERSTATS_ACHIEVEMENT_FIRSTVICTIM);
36 }
37
38 void PlayerStats_AddPlayer(entity e)
39 {
40         if(playerstats_db < 0)
41                 return;
42         if(e.playerstats_id)
43                 return;
44
45         if(e.crypto_idfp != "" && e.cvar_cl_allow_uidtracking == 1)
46                 e.playerstats_id = strzone(e.crypto_idfp);
47         else if(clienttype(e) == CLIENTTYPE_BOT)
48                 e.playerstats_id = strzone(sprintf("bot#%d", e.playerid));
49         else
50                 e.playerstats_id = strzone(sprintf("player#%d", e.playerid));
51         
52         string key;
53         key = sprintf("%s:*", e.playerstats_id);
54         
55         string p;
56         p = db_get(playerstats_db, key);
57         if(p == "")
58         {
59                 if(playerstats_last)
60                 {
61                         db_put(playerstats_db, key, playerstats_last);
62                         strunzone(playerstats_last);
63                 }
64                 else
65                         db_put(playerstats_db, key, "#");
66                 playerstats_last = strzone(e.playerstats_id);
67         }
68 }
69
70 void PlayerStats_AddTeam(float t)
71 {
72         if(playerstats_db < 0)
73                 return;
74
75         string key;
76         key = sprintf("team#%d:*", t);
77         
78         string p;
79         p = db_get(playerstats_db, key);
80         if(p == "")
81         {
82                 if(playerstats_last)
83                 {
84                         db_put(playerstats_db, key, playerstats_last);
85                         strunzone(playerstats_last);
86                 }
87                 else
88                         db_put(playerstats_db, key, "#");
89                 playerstats_last = strzone(sprintf("team%d", t));
90         }
91 }
92
93 void PlayerStats_AddEvent(string event_id)
94 {
95         if(playerstats_db < 0)
96                 return;
97         
98         string key;
99         key = sprintf("*:%s", event_id);
100         
101         string p;
102         p = db_get(playerstats_db, key);
103         if(p == "")
104         {
105                 if(events_last)
106                 {
107                         db_put(playerstats_db, key, events_last);
108                         strunzone(events_last);
109                 }
110                 else
111                         db_put(playerstats_db, key, "#");
112                 events_last = strzone(event_id);
113         }
114 }
115
116 void PlayerStats_Event(entity e, string event_id, float value)
117 {
118         if(!e.playerstats_id || playerstats_db < 0)
119                 return;
120         
121         string key;
122         float val;
123         key = sprintf("%s:%s", e.playerstats_id, event_id);
124         val = stof(db_get(playerstats_db, key));
125         val += value;
126         db_put(playerstats_db, key, ftos(val));
127 }
128
129 void PlayerStats_TeamScore(float t, string event_id, float value)
130 {
131         string key;
132         float val;
133         key = sprintf("team#%d:%s", t, event_id);
134         val = stof(db_get(playerstats_db, key));
135         val += value;
136         db_put(playerstats_db, key, ftos(val));
137 }
138
139 void PlayerStats_Sent_URI_Get_Callback(float id, float status, string data)
140 {
141         if(playerstats_requested)
142                 playerstats_waitforme = TRUE;
143 }
144
145 /*
146         format spec:
147
148         A collection of lines of the format <key> SPACE <value> NEWLINE, where
149         <key> is always a single character.
150
151         The following keys are defined:
152
153         V: format version (always 1) - this MUST be the first line!
154         #: comment (MUST be ignored by any parser)
155         R: release information on the server
156         T: time at which the game ended
157         G: game type
158         M: map name
159         S: "hostname" of the server
160         C: number of "unpure" cvar changes
161         P: player ID of an existing player; this also sets the owner for all following "n" and "e" lines (lower case!)
162         n: nickname of the player (optional)
163         e: followed by an event name, a space, and the event count/score
164                 event names can be:
165                         alivetime: total playing time of the player
166                         wins: number of games won (can only be set if matches is set)
167                         matches: number of matches played to the end (not aborted by map switch)
168                         joins: number of matches joined (always 1 unless player never played during the match)
169                         scoreboardvalid: set to 1 if the player was there at the end of the match
170                         total-<scoreboardname>: total score of that scoreboard item
171                         scoreboard-<scoreboardname>: end-of-game score of that scoreboard item (can differ in non-team games)
172                         achievement-<achievementname>: achievement counters
173 */
174
175 //#NO AUTOCVARS START
176 void PlayerStats_Shutdown()
177 {
178         string p, pn;
179         string e, en;
180         string nn;
181         float b;
182         float i;
183         string uri;
184
185         if(playerstats_db < 0)
186                 return;
187
188         uri = autocvar_g_playerstats_uri;
189         if(uri != "")
190         {
191                 b = buf_create();
192                 i = 0;
193
194                 db_dump(playerstats_db, "foo.db");
195
196                 bufstr_set(b, i++, "V 1");
197 #ifdef WATERMARK
198                 bufstr_set(b, i++, sprintf("R %s", WATERMARK()));
199 #endif
200                 bufstr_set(b, i++, sprintf("T %s.%06d", strftime(FALSE, "%s"), floor(random() * 1000000)));
201                 bufstr_set(b, i++, sprintf("G %s", GetGametype()));
202                 bufstr_set(b, i++, sprintf("M %s", GetMapname()));
203                 bufstr_set(b, i++, sprintf("S %s", cvar_string("hostname")));
204                 bufstr_set(b, i++, sprintf("C %d", cvar_purechanges_count));
205                 for(p = playerstats_last; (pn = db_get(playerstats_db, sprintf("%s:*", p))) != ""; p = pn)
206                 {
207                         bufstr_set(b, i++, sprintf("P %s", p));
208                         nn = db_get(playerstats_db, sprintf("%s:_netname", p));
209                         if(nn != "")
210                                 bufstr_set(b, i++, sprintf("n %s", nn));
211                         for(e = events_last; (en = db_get(playerstats_db, sprintf("*:%s", e))) != ""; e = en)
212                         {
213                                 float v;
214                                 v = stof(db_get(playerstats_db, sprintf("%s:%s", p, e)));
215                                 if(v != 0)
216                                         bufstr_set(b, i++, sprintf("e %s %g", e, v));
217                         }
218                 }
219                 bufstr_set(b, i++, "");
220
221                 if(autocvar_g_playerstats_debug)
222                 {
223                         for(i = 0; i < buf_getsize(b); ++i)
224                                 print(bufstr_get(b, i), "\n");
225                 }
226
227                 if(crypto_uri_postbuf(uri, URI_GET_PLAYERSTATS_SENT, "text/plain", "\n", b, 0))
228                         playerstats_requested = TRUE;
229                 else
230                         playerstats_waitforme = TRUE; // if posting fails, we must continue anyway
231
232                 buf_del(b);
233         }
234         else
235                 playerstats_waitforme = TRUE;
236
237         db_close(playerstats_db);
238         playerstats_db = -1;
239 }
240 //#NO AUTOCVARS END
241
242 void PlayerStats_AddGlobalInfo(entity p)
243 {
244         if(playerstats_db < 0)
245                 return;
246         if(!p.playerstats_id || playerstats_db < 0)
247                 return;
248         p.playerstats_addedglobalinfo = TRUE;
249
250         // add global info!
251         if(p.alivetime)
252                 PlayerStats_Event(p, PLAYERSTATS_ALIVETIME, time - p.alivetime);
253
254         if(p.alivetime)
255                 PlayerStats_Event(p, PLAYERSTATS_ALIVETIME, time - p.alivetime);
256         
257         if(p.cvar_cl_allow_uid2name == 1 || clienttype(p) == CLIENTTYPE_BOT)
258                 db_put(playerstats_db, sprintf("%s:_netname", p.playerstats_id), p.netname);
259
260         if(p.alivetime > 0)
261                 PlayerStats_Event(p, PLAYERSTATS_JOINS, 1);
262
263         strunzone(p.playerstats_id);
264         p.playerstats_id = string_null;
265 }
266
267 void PlayerStats_EndMatch(float finished)
268 {
269         entity p;
270         FOR_EACH_PLAYER(p)
271         {
272                 PlayerScore_PlayerStats(p);
273                 PlayerStats_Event(p, PLAYERSTATS_SCOREBOARD_VALID, 1);
274                 if(finished)
275                 {
276                         PlayerStats_Event(p, PLAYERSTATS_WINS, p.winning);
277                         PlayerStats_Event(p, PLAYERSTATS_MATCHES, 1);
278                 }
279         }
280 }