· 6 years ago · Dec 02, 2019, 05:16 AM
1// **** Be aware that I use '\' as a control char instead of '^'
2#pragma ctrlchar '\'
3
4// **** DO NOT EDIT THE QUERIES UNLESS YOU KNOW WHAT YOU'RE DOING!
5// **** YOU HAVE BEEN WARNED
6
7#include <amxmodx>
8#include <amxmisc>
9#include <sqlx>
10#include <fakemeta>
11
12// Do not touch unless you know.
13#define MAX_DATA_ARRAY_SIZE 5
14
15#if AMXX_VERSION_NUM < 183
16 #include <colorchat>
17 #define print_team_default Blue
18 #define print_team_red Red
19 #define print_team_grey Grey
20 #define print_team_blue Blue
21
22 #define MAX_NAME_LENGTH 32
23 #define client_disconnected client_disconnect
24#endif
25
26#define SQLITE 0
27#define MYSQL 1
28
29/***** Stuff that you can Edit *****/
30/* Explanation of stuff inside:
31ADMIN_ACCESS_LETTER -> Access flag for the admin command that checks the time of a player
32USE_NAME -> Will make the plugin use the name of the player as the saving identifier. If a player changes his name, his time will reset.
33 To disable: comment the line by adding // infront of #define
34 making it //#define
35 To Enable: Un comment the line by removing '//'
36SAVE_TYPE -> Decides which method should the plugin use to save data:
37 Valid Values: 0 for SQLite (save locally in the server files), 1 for MySQL (must have an external server)
38PREPARE_TOP_MOTD -> If you're using an external MySQL server (or if you have a huge amount of players, you might actually want to use this
39 This allows you to prepare the top motd as soon as the map starts instead of actually making it each time a player
40 submits a command; however, it does not give up to date results.
41 (TLDR: Good for servers with a huge load or amount of players,
42 does not give up to date results though, and will disable /top#_time command.)
43 Enable/Disable: Same method as USE_NAME
44PREFIX -> The prefix of the chat messages. Should be easy to edit. Does not need any more explanation.
45GET_TIME_INSTANT_QUERY ->
46TOP_DEFAULT_NUMBER -> Number of entries in Top MOTD when using /toptime commands and if using PREPARE_TOP_MOTD
47GET_TIME_INSTANT_QUERY -> This will force the plugin to not use threaded queries, only enable if you know what you're doing.
48 I do not recomment using this on distant servers (for example, your game server is in one end
49 while your sql server is at the other end of the world)
50DO_NOT_LOG -> Do not let the plugin to log queries.
51 (Logging is useful for debuging, but if you don't want to, disable it by removing //)
52 PS: Do not expect support from me if you have logging disabled.
53*/
54
55// Editables
56#define SAVE_TYPE 1
57#define ADMIN_ACCESS_LETTER "e"
58#define TOP_DEFAULT_NUMBER 15
59
60// Enabled, Disabled
61//#define USE_NAME
62//#define PREPARE_TOP_MOTD
63//#define GET_TIME_INSTANT_QUERY
64//#define DO_NOT_LOG
65
66new const PREFIX[] = "\x04[Played-Time]";
67
68new const g_szTimeCheckChatCommands[][] = {
69 "/mt",
70 "mt",
71 "/my_time",
72 "my_time",
73 "/mytime",
74 "mytime"
75};
76
77new const g_szTopTimeChatCommands[][] = {
78 "/timetop",
79 "/time15",
80 "/toptime",
81 "/time10"
82};
83
84#if SAVE_TYPE == MYSQL
85new const SQL_CONNECT_DATA[][] = {
86 "127.0.0.1",
87 "root",
88 "",
89 "played_time"
90};
91#endif
92
93new const LOG_FILE_PLAYED_TIME[] = "addons/amxmodx/logs/played_time_log.txt";
94/************************************/
95/***** End *****/
96/************************************/
97#define IDENTIFIER_MAX_LENGTH 35
98#define NOT_RETRIEVED -1
99
100new Handle:g_hSqlHandle, g_szQuery[512];
101new g_iPlayedTime[33] = NOT_RETRIEVED;
102
103#if defined PREPARE_TOP_MOTD
104new bool:g_bTopMotdNoData = false;
105#endif
106
107new g_szTopMotd[1536];
108
109new g_szOldName[33][MAX_NAME_LENGTH];
110new g_iQueryNumber;
111new g_iMaxPlayers;
112new g_hGetTimeForward, g_hSaveTimeForward;
113
114public plugin_natives()
115{
116 register_library("played_time");
117
118 register_native("pt_get_user_played_time", "native_get_user_played_time", 0);
119 register_native("pt_set_user_played_time", "native_set_user_played_time", 0);
120
121 // Compatibility with other older plugins;
122 register_native("get_user_playedtime", "native_get_user_played_time", 0);
123 register_native("set_user_playedtime", "native_set_user_played_time", 0);
124 register_native("get_user_played_time", "native_get_user_played_time", 0);
125 register_native("set_user_played_time", "native_set_user_played_time", 0);
126
127 register_native("pt_get_save_type", "native_get_save_type", 0)
128
129 g_hGetTimeForward = CreateMultiForward("pt_client_get_time", ET_IGNORE, FP_CELL, FP_CELL);
130 g_hSaveTimeForward = CreateMultiForward("pt_client_save_time", ET_IGNORE, FP_CELL, FP_CELL);
131}
132
133public plugin_end()
134{
135 SQL_FreeHandle(g_hSqlHandle);
136 DestroyForward(g_hGetTimeForward);
137 DestroyForward(g_hSaveTimeForward);
138}
139
140public plugin_init()
141{
142 // Why? Because it looks cool.
143 register_plugin(.plugin_name = "Played Time: Extended", .author = "Khalid", .version = "1.0b");
144
145 new szMapName[32]; get_mapname(szMapName, charsmax(szMapName));
146 log_to_file(LOG_FILE_PLAYED_TIME, "---- Map changed to: %s ----", szMapName);
147
148 new ADMIN_ACCESS = read_flags(ADMIN_ACCESS_LETTER);
149
150 // Filter chat to hook chat commands
151 for(new i, szCommand[32]; i < sizeof g_szTimeCheckChatCommands; i++)
152 {
153 formatex(szCommand, charsmax(szCommand), "say %s", g_szTimeCheckChatCommands[i]);
154 register_clcmd(szCommand, "ClCmdSay_CheckTime");
155 formatex(szCommand, charsmax(szCommand), "say_team %s", g_szTimeCheckChatCommands[i]);
156 register_clcmd(szCommand, "ClCmdSay_CheckTime");
157 }
158
159 for(new i, szCommand[32]; i < sizeof g_szTopTimeChatCommands; i++)
160 {
161 formatex(szCommand, charsmax(szCommand), "say %s", g_szTopTimeChatCommands[i]);
162 register_clcmd(szCommand, "ClCmdSay_TopTime");
163 formatex(szCommand, charsmax(szCommand), "say_team %s", g_szTopTimeChatCommands[i]);
164 register_clcmd(szCommand, "ClCmdSay_TopTime");
165 }
166
167 register_clcmd("say", "ClCmdSay_TopNumberCommand");
168 register_clcmd("say_team", "ClCmdSay_TopNumberCommand");
169
170 // Command to allow admins to check other players played time
171 register_concmd("amx_playedtime", "AdminCmd_ShowPlayerTime", ADMIN_ACCESS," <name - #userid - steamid> - Show total and current time played by a specific player.");
172 register_concmd("amx_show_played_time", "AdminCmd_ShowPlayerTime", ADMIN_ACCESS," <name - #userid - steamid> - Show total and current time played by a specific player.");
173 register_concmd("amx_played_time", "AdminCmd_ShowPlayerTime", ADMIN_ACCESS," <name - #userid - steamid> - Show total and current time played by a specific player.");
174
175 register_forward(FM_ClientUserInfoChanged, "FMCallback_InfoChanged_Post", 1)
176
177 CreateTableInDB();
178 g_iMaxPlayers = get_maxplayers();
179}
180
181public AdminCmd_ShowPlayerTime(id, level, cid)
182{
183 if(!cmd_access(id, level, cid, 1))
184 return PLUGIN_HANDLED
185
186 new szName[32], iPlayer
187 if(read_argc() == 1)
188 {
189 console_print(id, "Showing players times of all connected players")
190 new iPlayers[32], iNum, iPlayer, szName[32]
191 get_players(iPlayers, iNum, "h")
192
193 console_print(id, "%d. %-32s %-22s", "#", "Name", "Time Played");
194 for(new i; i < iNum; i++)
195 {
196 iPlayer = iPlayers[i]
197 get_user_name(iPlayer, szName, 31)
198
199 console_print(id, "%d. %-32s %-22d", i + 1, szName, (g_iPlayedTime[iPlayer] + get_user_time(iPlayer)) / 60)
200 }
201 }
202
203 else
204 {
205 new szArg[32]
206 read_argv(1, szArg, charsmax(szArg))
207
208 iPlayer = cmd_target(id, szArg, CMDTARGET_OBEY_IMMUNITY)
209
210 if(iPlayer)
211 {
212 get_user_name(iPlayer, szName, charsmax(szName))
213 console_print(id, "%s total played time is %d minute(s)", szName, ( g_iPlayedTime[iPlayer] + get_user_time(iPlayer) ) / 60);
214 return PLUGIN_HANDLED;
215 }
216
217 if(szArg[0] == '@')
218 {
219 new iPlayers[32], iNum
220 if( equali(szArg, "@TERRORIST") || equali(szArg, "@T") || equal(szArg, "@TERR") )
221 {
222 console_print(id, "Showing players times for team Terrorist");
223 get_players(iPlayers, iNum, "eh", "TERRORIST");
224 }
225
226 else if( equali(szArg, "@COUNTERTERRORIST") || equali(szArg, "@CT") || equali(szArg, "@COUNTER") )
227 {
228 console_print(id, "Showing players times for team Counter-Terrorist");
229 get_players(iPlayers, iNum, "eh", "CT");
230 }
231
232 else
233 {
234 console_print(id, "That's not a correct team");
235 return PLUGIN_HANDLED
236 }
237
238 for(new i; i < iNum; i++)
239 {
240 iPlayer = iPlayers[i]
241 get_user_name(iPlayer, szName, 31)
242 console_print(id, "%d. %s %22.22d", i + 1, szName, ( g_iPlayedTime[iPlayer] + get_user_time(iPlayer) ) / 60)
243 }
244 }
245 }
246
247 return PLUGIN_HANDLED
248}
249
250public ClCmdSay_CheckTime(id)
251{
252 new iAdditionalTime = get_user_time(id);
253
254 client_print_color(id, print_team_default, "\x04-------------------------------#Played Time#-----------------------------------")
255 if(g_iPlayedTime[id] != NOT_RETRIEVED)
256 {
257 client_print_color(id, print_team_grey, "%s \x03You have been playing on this server for \x03%d minute%s", PREFIX, iAdditionalTime / 60, iAdditionalTime / 60 == 1? "" : "s");
258 client_print_color(id, print_team_grey, "%s \x03Your total played time on the server: \x03%d minute%s.", PREFIX, (iAdditionalTime + g_iPlayedTime[id]) / 60, ( (iAdditionalTime + g_iPlayedTime[id]) / 60 ) == 1 ? "" : "s");
259 }
260
261 else
262 {
263 client_print_color(id, print_team_grey, "%s \x03Your total time is not retrieved yet.");
264 }
265
266 client_print_color(id, print_team_default, "\x04-------------------------------------------------------------------------------")
267
268 return PLUGIN_CONTINUE;
269}
270
271public ClCmdSay_TopTime(id)
272{
273 #if defined PREPARE_TOP_MOTD
274 if(g_bTopMotdNoData)
275 {
276 client_print_color(id, print_team_default, "%s \x03No data to do the top list yet.");
277 return;
278 }
279
280 show_motd(id, g_szTopMotd, "Time Top List");
281 #else
282 FormatTop(id, TOP_DEFAULT_NUMBER);
283 #endif
284}
285
286public ClCmdSay_TopNumberCommand(id)
287{
288 #if defined PREPARE_TOP_MOTD
289 ClCmdSay_TopTime(id)
290 #else
291 new szSaid[25]
292 read_argv(1, szSaid, charsmax(szSaid))
293
294 if( containi(szSaid, "/top") != -1 && ( containi(szSaid, "_time") != -1 || containi(szSaid, "time") != -1) )
295 {
296 replace(szSaid, charsmax(szSaid), "/top", ""); replace(szSaid, charsmax(szSaid), "_time", "");
297 replace(szSaid, charsmax(szSaid), "time", "");
298
299 if(!is_str_num(szSaid)) // If it has more other words than /top*_time
300 {
301 return PLUGIN_CONTINUE // stop plugin and continue to show the words
302 }
303
304 new iNum = str_to_num(szSaid)
305 FormatTop(id, iNum);
306 }
307 #endif
308
309 return PLUGIN_CONTINUE;
310}
311
312stock FormatTop(id, iTopNumber)
313{
314 new iData[MAX_DATA_ARRAY_SIZE];
315 iData[0] = id; iData[1] = iTopNumber;
316
317 FormatQuery(g_szQuery, charsmax(g_szQuery),
318 "SELECT `_name_field_`, `_time_field_` FROM `_table_name_` ORDER BY `_time_field_` DESC LIMIT %d", iTopNumber);
319 SQL_SendThreadedQuery("FormatTop", g_hSqlHandle,"QueryHandler_FormatTopList", g_szQuery, iData);
320}
321
322public QueryHandler_FormatTopList(FailState, Handle:hQuery, szError[], iError, Data[], iDataSize)
323{
324 if(FailState)
325 {
326 PluginLog_SQLCallback("QueryHandler_FormatTopList", Data[iDataSize - 1], iError, FailState, szError);
327 return;
328 }
329
330 if(iError)
331 {
332 PluginLog_SQLCallback("QueryHandler_FormatTopList", Data[iDataSize - 1], iError, FailState, szError);
333 return;
334 }
335
336 #if !defined PREPARE_TOP_MOTD
337 if(!is_user_connected(Data[0]))
338 {
339 return;
340 }
341 #endif
342
343 new iLen, szName[32], iPlace, iTime;
344 iLen = formatex(g_szTopMotd, charsmax(g_szTopMotd), "<body bgcolor=#000000><font color=#FFB00><pre>");
345 iLen += format(g_szTopMotd[iLen], charsmax(g_szTopMotd) - iLen,"%s %-22.22s %3s\n", "#", "Name", "Time in minutes");
346
347 new iCount;
348
349 if(!SQL_NumResults(hQuery))
350 {
351 #if defined PREPARE_TOP_MOTD
352 g_bTopMotdNoData = true;
353 #else
354 client_print_color(Data[0], print_team_default, "%s \x03No top time motd as there is no data.");
355 #endif
356
357 return;
358 }
359
360 while(SQL_MoreResults(hQuery))
361 {
362 SQL_ReadResult(hQuery, 0, szName, charsmax(szName));
363 iTime = SQL_ReadResult(hQuery, 1);
364
365 replace_all(szName, charsmax(szName), "<", "<");
366 replace_all(szName, charsmax(szName), ">", ">");
367
368 iLen += formatex(g_szTopMotd[iLen], charsmax(g_szTopMotd) - iLen, "%d %-22.22s %d\n", ++iPlace, szName, iTime / 60);
369 SQL_NextRow(hQuery)
370 iCount++;
371 }
372
373 if(iCount)
374 {
375 iLen += formatex(g_szTopMotd[iLen], charsmax(g_szTopMotd) - iLen, "</pre></font></body>");
376
377 new szTitle[25];
378 formatex(szTitle, charsmax(szTitle), "Time Top%d", Data[1]);
379
380 if(Data[0] > 0)
381 {
382 show_motd(Data[0], g_szTopMotd, szTitle);
383 }
384 }
385
386 else
387 {
388 client_print_color(Data[0], print_team_default, "%s \x01No data in database yet..", PREFIX);
389 }
390}
391
392public client_disconnected(id)
393{
394 if(is_user_bot(id))
395 {
396 return;
397 }
398
399 if(g_iPlayedTime[id] != NOT_RETRIEVED)
400 {
401 SavePlayedTime(id, true);
402 g_iPlayedTime[id] = NOT_RETRIEVED;
403 }
404}
405
406public client_authorized(id)
407{
408 if(is_user_bot(id))
409 {
410 return;
411 }
412
413 g_iPlayedTime[id] = NOT_RETRIEVED;
414 #if !defined GET_TIME_INSTANT_QUERY
415 GetClientPlayedTime(id, true);
416 #else
417 g_iPlayedTime[id] = GetClientPlayedTime(id, true);
418 #endif
419}
420
421public client_infochanged(id)
422{
423 if(!is_user_connected(id))
424 {
425 return;
426 }
427
428 get_user_name(id, g_szOldName[id], charsmax(g_szOldName[]));
429}
430
431public FMCallback_InfoChanged_Post(id)
432{
433 if(!is_user_connected(id))
434 {
435 return;
436 }
437
438 new szNewName[32];
439 get_user_name(id, szNewName, charsmax(szNewName));
440
441 if(!equal(g_szOldName[id], szNewName))
442 {
443 #if defined USE_NAME;
444 g_iPlayedTime[id] = NOT_RETRIEVED;
445 GetClientPlayedTime(id, false); // Get new played time for the new name.
446 #else
447 CleanString(szNewName, charsmax(szNewName))
448 UpdateNameInDatabase(id, szNewName);
449 #endif
450 }
451}
452
453#if !defined USE_NAME
454stock UpdateNameInDatabase(id, szNewName[])
455{
456 if(g_iPlayedTime[id] == NOT_RETRIEVED)
457 {
458 return;
459 }
460
461 new szAuthId[33]; get_user_authid(id, szAuthId, charsmax(szAuthId));
462 FormatQuery(g_szQuery, charsmax(g_szQuery), "UPDATE `_table_name_` SET `_name_field_` = '%s' WHERE `_identifier_field_` = '%s'", szNewName, szAuthId);
463 SQL_ThreadQuery(g_hSqlHandle, "QueryHandler_Dump", g_szQuery);
464}
465#endif
466
467stock SavePlayedTime(id, bool:bIsDisconnect)
468{
469 new szIdentifier[IDENTIFIER_MAX_LENGTH];
470
471 new iRet
472 ExecuteForward(g_hSaveTimeForward, iRet, id, bIsDisconnect);
473
474 #if defined USE_NAME
475 get_user_name(id, szIdentifier, charsmax(szIdentifier));
476 CleanString(szIdentifier, charsmax(szIdentifier));
477 #else
478 get_user_authid(id, szIdentifier, charsmax(szIdentifier));
479 #endif
480
481 #if defined USE_NAME
482 FormatQuery(g_szQuery, charsmax(g_szQuery), "UPDATE _table_name_ SET `_time_field_` = '%d' WHERE `_name_field_` ='%s'", g_iPlayedTime[id] + get_user_time(id), szIdentifier);
483 #else
484 FormatQuery(g_szQuery, charsmax(g_szQuery), "UPDATE _table_name_ SET `_time_field_` = '%d' WHERE `_identifier_field_` ='%s'", g_iPlayedTime[id] + get_user_time(id), szIdentifier);
485 #endif
486
487 SQL_SendThreadedQuery("SavePlayedTime", g_hSqlHandle, "QueryHandler_Dump", g_szQuery);
488}
489
490#if !defined GET_TIME_INSTANT_QUERY
491stock GetClientPlayedTime(id, bool:bConnect = true)
492{
493 new szIdentifier[MAX_NAME_LENGTH + 3];
494 #if defined USE_NAME
495 get_user_name(id, szIdentifier, charsmax(szIdentifier));
496 CleanString(szIdentifier, charsmax(szIdentifier));
497 #else
498 get_user_authid(id, szIdentifier, charsmax(szIdentifier));
499 #endif
500
501 #if defined USE_NAME
502 FormatQuery(g_szQuery, charsmax(g_szQuery), "SELECT `_time_field_` FROM `_table_name_` WHERE `_name_field_` ='%s'", szIdentifier);
503 #else
504 new szName[MAX_NAME_LENGTH]; get_user_name(id, szName, charsmax(szName));
505 FormatQuery(g_szQuery, charsmax(g_szQuery), "SELECT `_time_field_`, `_name_field_` FROM `_table_name_` WHERE `_identifier_field_` ='%s'", szIdentifier);
506 #endif
507
508 new Data[MAX_DATA_ARRAY_SIZE];
509 Data[0] = id; Data[1] = _:bConnect;
510 SQL_SendThreadedQuery("QueryHandler_GetPlayedTime", g_hSqlHandle, "QueryHandler_GetPlayedTime", g_szQuery, Data);
511}
512
513public QueryHandler_GetPlayedTime(FailState, Handle:hQuery, szError[], iError, Data[], iDataSize)
514{
515 PluginLog_SQLCallback("QueryHandler_GetPlayedTime", Data[iDataSize - 1], iError, FailState, szError);
516
517 if(iError)
518 {
519 return;
520 }
521
522 new szName[MAX_NAME_LENGTH];
523
524 #if !defined USE_NAME
525 new szIdentifier[IDENTIFIER_MAX_LENGTH]; get_user_authid(Data[0], szIdentifier, charsmax(szIdentifier));
526 #endif
527
528 new id = Data[0];
529 if(!SQL_MoreResults(hQuery))
530 {
531 get_user_name(id, szName, charsmax(szName));
532
533 #if defined USE_NAME
534 FormatQuery(g_szQuery, charsmax(g_szQuery), "INSERT INTO `_table_name_` (`_name_field_`, `_time_field_`) VALUES ('%s', '0')", szName);
535 #else
536 FormatQuery(g_szQuery, charsmax(g_szQuery), "INSERT INTO `_table_name_` (`_identifier_field_`, `_name_field_`, `_time_field_`) VALUES ('%s', '%s', '0')", szIdentifier, szName);
537 #endif
538
539 g_iPlayedTime[id] = 0;
540 SQL_SendThreadedQuery("QueryHandler_GetPlayedTime", g_hSqlHandle, "QueryHandler_Dump", g_szQuery);
541 return;
542 }
543
544 g_iPlayedTime[id] = SQL_ReadResult(hQuery, 0);
545
546 new iRet;
547 ExecuteForward(g_hGetTimeForward, iRet, id, Data[1]);
548
549 get_user_name(id, szName, charsmax(szName));
550 PluginLog("Got %d minutes (%d sec) for %s", g_iPlayedTime[id] / 60, g_iPlayedTime[id], szName);
551
552 #if !defined USE_NAME
553 new szOldSavedName[MAX_NAME_LENGTH];
554
555 //get_user_name(id, szName, charsmax(szName));
556 SQL_ReadResult(hQuery, 1, szOldSavedName, charsmax(szOldSavedName))
557
558 CleanString(szName, charsmax(szName));
559
560 if(!equal(szName, szOldSavedName))
561 {
562 FormatQuery(g_szQuery, charsmax(g_szQuery),
563 "UPDATE `_table_name_` SET `_name_field_` = '%s' WHERE `_identifier_field_` = '%s'",
564 szName, szIdentifier);
565 SQL_SendThreadedQuery("QueryHandler_GetPlayedTime", g_hSqlHandle, "QueryHandler_Dump", g_szQuery);
566 }
567 #endif
568}
569#else
570
571stock GetClientPlayedTime(id, bool:bConnect = true)
572{
573 new szIdentifier[MAX_NAME_LENGTH + 3];
574 new szName[MAX_NAME_LENGTH]; get_user_name(id, szName, charsmax(szName));
575
576 #if defined USE_NAME
577 get_user_name(id, szIdentifier, charsmax(szIdentifier));
578 CleanString(szIdentifier, charsmax(szIdentifier));
579 #else
580 get_user_authid(id, szIdentifier, charsmax(szIdentifier));
581 #endif
582
583 #if defined USE_NAME
584 FormatQuery(g_szQuery, charsmax(g_szQuery), "SELECT `_time_field_` FROM `_table_name_` WHERE `_name_field_` ='%s'", szIdentifier);
585 #else
586 FormatQuery(g_szQuery, charsmax(g_szQuery), "SELECT `_time_field_`, `_name_field_` FROM `_table_name_` WHERE `_identifier_field_` ='%s'", szIdentifier);
587 #endif
588
589 //SQL_SendThreadedQuery("QueryHandler_GetPlayedTime", g_hSqlHandle, "QueryHandler_GetPlayedTime", g_szQuery, Data);
590
591 PluginLog_Query("GetClientPlayedTime", g_szQuery);
592
593 new Handle:hQuery, Handle:hConnection;
594 new iError, szError[256];
595 hConnection = SQL_Connect(g_hSqlHandle, iError, szError, charsmax(szError));
596 ++g_iQueryNumber
597
598 if(iError)
599 {
600 SQL_FreeHandle(hConnection);
601 PluginLog_SQLCallback("GetClientPlayedTime #1", g_iQueryNumber, iError, 0, szError);
602
603 return;
604 }
605
606 hQuery = SQL_PrepareQuery(g_hSqlHandle, g_szQuery);
607
608 if(!SQL_Execute(hQuery))
609 {
610 SQL_QueryError(hQuery, szError, charsmax(szError));
611 PluginLog_SQLCallback("GetClientPlayedTime #2", g_iQueryNumber, 0, 0, szError);
612
613 SQL_FreeHandle(hQuery);
614 SQL_FreeHandle(hConnection);
615 return;
616 }
617
618 if(!SQL_MoreResults(hQuery))
619 {
620 SQL_FreeHandle(hQuery);
621 SQL_FreeHandle(hConnection);
622
623 get_user_name(id, szName, charsmax(szName));
624
625 #if defined USE_NAME
626 FormatQuery(g_szQuery, charsmax(g_szQuery), "INSERT INTO `_table_name_` (`_name_field_`, `_time_field_`) VALUES ('%s', '0')", szName);
627 #else
628 FormatQuery(g_szQuery, charsmax(g_szQuery), "INSERT INTO `_table_name_` (`_identifier_field_`, `_name_field_`, `_time_field_`) VALUES ('%s', '%s', '0')", szIdentifier, szName);
629 #endif
630
631 g_iPlayedTime[id] = 0;
632 SQL_SendThreadedQuery("GetClientPlayedTime #3", g_hSqlHandle, "QueryHandler_Dump", g_szQuery);
633 return;
634 }
635
636 new iRet;
637 ExecuteForward(g_hGetTimeForward, iRet, id, bConnect);
638
639 get_user_name(id, szName, charsmax(szName));
640 PluginLog("Got %d minutes (%d sec) for %s", g_iPlayedTime[id] / 60, g_iPlayedTime[id], szName);
641
642 #if !defined USE_NAME
643 new szOldSavedName[MAX_NAME_LENGTH];
644
645 //get_user_name(id, szName, charsmax(szName));
646 SQL_ReadResult(hQuery, 1, szOldSavedName, charsmax(szOldSavedName))
647
648 CleanString(szName, charsmax(szName));
649
650 if(!equal(szName, szOldSavedName))
651 {
652 FormatQuery(g_szQuery, charsmax(g_szQuery),
653 "UPDATE `_table_name_` SET `_name_field_` = '%s' WHERE `_identifier_field_` = '%s'",
654 szName, szIdentifier);
655 SQL_SendThreadedQuery("GetClientPlayedTime #3", g_hSqlHandle, "QueryHandler_Dump", g_szQuery);
656 }
657 #endif
658
659 g_iPlayedTime[id] = SQL_ReadResult(hQuery, 0);
660
661 SQL_FreeHandle(hQuery);
662 SQL_FreeHandle(hConnection);
663}
664#endif
665
666
667public QueryHandler_Dump(FailState, Handle:Query, szError[], iError, Data[], iDataSize)
668{
669 PluginLog_SQLCallback("QueryHandler_Dump", Data[iDataSize - 1], iError, FailState, szError);
670}
671
672CreateTableInDB()
673{
674 #if SAVE_TYPE == SQLITE
675 SQL_SetAffinity("sqlite");
676 g_hSqlHandle = SQL_MakeDbTuple("", "", "", "played_time_database");
677 #endif
678
679 #if SAVE_TYPE == MYSQL
680 SQL_SetAffinity("mysql");
681 g_hSqlHandle = SQL_MakeDbTuple(SQL_CONNECT_DATA[0], SQL_CONNECT_DATA[1], SQL_CONNECT_DATA[2], SQL_CONNECT_DATA[3]);
682 #endif
683
684 if(g_hSqlHandle == Empty_Handle)
685 {
686 set_fail_state("Could not connect to the SQL Database.");
687 }
688
689 #if SAVE_TYPE == SQLITE
690 #if defined USE_NAME
691 FormatQuery(g_szQuery, charsmax(g_szQuery),"CREATE TABLE IF NOT EXISTS `_table_name_` (`id` INTEGER PRIMARY KEY, `_name_field_` CHAR(32) UNIQUE, `_time_field_` INTEGER");
692 #else
693 FormatQuery(g_szQuery, charsmax(g_szQuery),"CREATE TABLE IF NOT EXISTS `_table_name_` (`id` INTEGER PRIMARY KEY, `_identifier_field_` CHAR(35) UNIQUE, `_name_field_` CHAR(32), _time_field_ INTEGER)");
694 #endif
695 #endif
696 #if SAVE_TYPE == MYSQL
697 #if defined USE_NAME
698 FormatQuery(g_szQuery, charsmax(g_szQuery), "CREATE TABLE IF NOT EXISTS `_table_name_` (`_name_field_` VARCHAR(35) UNIQUE, `_time_field_` INT, `date_created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP)");
699 #else
700 FormatQuery(g_szQuery, charsmax(g_szQuery), "CREATE TABLE IF NOT EXISTS `_table_name_` (`_identifier_field_` VARCHAR(35) UNIQUE, `_name_field_` VARCHAR(32), `_time_field_` INT, `date_created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP)");
701 #endif
702 #endif
703
704 SQL_SendThreadedQuery("CreateTableInDB", g_hSqlHandle, "QueryHandler_Initialize", g_szQuery);
705}
706
707public QueryHandler_Initialize(FailState, Handle:Query, szError[], iError, Data[], iDataSize)
708{
709 if(FailState || iError)
710 {
711 PluginLog_SQLCallback("QueryHandler_Initialize", Data[iDataSize - 1], iError, FailState, szError);
712 #if AMXX_VERSION_NUM < 183
713 new szFailStateMessage[256];
714 formatex(szFailStateMessage, charsmax(szFailStateMessage), "FailState %d %d: %s", FailState, iError, szError);
715 set_fail_state(szFailStateMessage);
716 #else
717 set_fail_state("FailState %d %d: %s", FailState, iError, szError);
718 #endif
719 }
720
721 else
722 {
723 PluginLog("(QueryHandler_Initialize) [Query #: %d]: StartUp Query executed Successfully.", Data[iDataSize - 1]);
724 }
725
726 #if defined PREPARE_TOP_MOTD
727 FormatTop(-1, TOP_DEFAULT_NUMBER);
728 #endif
729}
730
731// NATIVES
732public native_get_user_played_time(plugin_id, argc)
733{
734 new id = get_param(1);
735 if(!IsValidPlayer_Native(id))
736 {
737 return -1
738 }
739
740 return g_iPlayedTime[id];
741}
742
743public native_set_user_played_time(plugin_id, argc)
744{
745 new id = get_param(1);
746 new iNewTime = get_param(2);
747
748 if(!IsValidPlayer_Native(id))
749 {
750 return 0
751 }
752
753 g_iPlayedTime[id] = iNewTime;
754 return 1;
755}
756
757public native_get_save_type(plugin_id, argc)
758{
759 return SAVE_TYPE;
760}
761
762stock IsValidPlayer_Native(id)
763{
764 if(!is_user_connected(id))
765 {
766 log_error(AMX_ERR_NATIVE, "Client %d is NOT connected", id);
767 return 0;
768 }
769
770 if(is_user_bot(id))
771 {
772 log_error(AMX_ERR_NATIVE, "Client %d is a BOT", id);
773 return 0;
774 }
775
776 if(is_user_hltv(id))
777 {
778 log_error(AMX_ERR_NATIVE, "HLTV client %d", id);
779 return 0;
780 }
781
782 if( !( 1 <= id <= g_iMaxPlayers ) )
783 {
784 log_error(AMX_ERR_NATIVE, "Index out of bounds %d", id);
785 return 0
786 }
787
788 return 1;
789}
790
791stock CleanString(szName[], iSize)
792{
793 replace_all(szName, iSize, "\"", "");
794 replace_all(szName, iSize, "'", "");
795}
796
797stock FormatQuery(szQueryStorage[], iSize, szQuery[], any:...)
798{
799 vformat(szQueryStorage, iSize, szQuery, 4);
800
801 replace_all(szQueryStorage, iSize, "_identifier_field_", "steamid");
802 replace_all(szQueryStorage, iSize, "_name_field_", "name");
803 replace_all(szQueryStorage, iSize, "_time_field_", "time_played");
804 replace_all(szQueryStorage, iSize, "_table_name_", "played_time");
805}
806
807stock SQL_SendThreadedQuery(szPosition[], Handle:hSql, szQueryCallback[], szQuery[], Data[MAX_DATA_ARRAY_SIZE] = "")
808{
809 new ModifiedData[MAX_DATA_ARRAY_SIZE + 1];
810
811 // Must be before, as this is where the increment happen.
812 PluginLog_Query(szPosition, szQuery);
813 for(new i; i < MAX_DATA_ARRAY_SIZE; i++)
814 {
815 ModifiedData[i] = Data[i];
816 }
817
818 ModifiedData[MAX_DATA_ARRAY_SIZE] = g_iQueryNumber;
819
820 SQL_ThreadQuery(hSql, szQueryCallback, szQuery, ModifiedData, MAX_DATA_ARRAY_SIZE + 1);
821}
822
823stock PluginLog(szString[], any:...)
824{
825 #if !defined DO_NOT_LOG
826 new szLog[1024]
827 vformat(szLog, charsmax(szLog), szString, 2);
828
829 log_to_file(LOG_FILE_PLAYED_TIME, szLog);
830 //log_amx("[Played Time] %s", szLog);
831 #endif
832}
833
834stock PluginLog_Query(szPosition[], szQuery[])
835{
836 #if !defined DO_NOT_LOG
837 log_to_file(LOG_FILE_PLAYED_TIME, "(%s) Query Executed (#%d): \n\t\t\t\t%s", szPosition, ++g_iQueryNumber, szQuery);
838 //log_amx("[Played Time] (%s) Query Executed (#%d): \n\t\t%s", szPosition, g_iQueryNumber, szQuery);
839 #endif
840}
841
842stock PluginLog_SQLCallback(szPosition[], iQueryNumber, iError, FailState, szError[])
843{
844 #if !defined DO_NOT_LOG
845 if(iError || FailState)
846 {
847 log_to_file(LOG_FILE_PLAYED_TIME, "(%s) [Query#: %d] [Error# :%d] [FailState: %d]: %s", szPosition, iQueryNumber, iError, FailState, szError);
848 }
849
850 else if(!iError && !FailState)
851 {
852 log_to_file(LOG_FILE_PLAYED_TIME, "(%s) [Query#: %d] executed successfully", szPosition, iQueryNumber);
853 }
854 #endif
855}