· 6 years ago · Dec 02, 2019, 02:12 PM
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 else if( equali(szArg, "@SPECTATOR") || equali(szArg, "@SPEC") || equali(szArg, "@SPECTATOR") )
232 {
233 console_print(id, "Showing players times for team Spectators");
234 get_players(iPlayers, iNum, "eh", "SPEC");
235 }
236
237 else
238 {
239 console_print(id, "That's not a correct team");
240 return PLUGIN_HANDLED
241 }
242
243 for(new i; i < iNum; i++)
244 {
245 iPlayer = iPlayers[i]
246 get_user_name(iPlayer, szName, 31)
247 console_print(id, "%d. %s %22.22d", i + 1, szName, ( g_iPlayedTime[iPlayer] + get_user_time(iPlayer) ) / 60)
248 }
249 }
250 }
251
252 return PLUGIN_HANDLED
253}
254
255public ClCmdSay_CheckTime(id)
256{
257 new iAdditionalTime = get_user_time(id);
258
259 client_print_color(id, print_team_default, "\x04-------------------------------#Played Time#-----------------------------------")
260 if(g_iPlayedTime[id] != NOT_RETRIEVED)
261 {
262 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");
263 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");
264 }
265
266 else
267 {
268 client_print_color(id, print_team_grey, "%s \x03Your total time is not retrieved yet.");
269 }
270
271 client_print_color(id, print_team_default, "\x04-------------------------------------------------------------------------------")
272
273 return PLUGIN_CONTINUE;
274}
275
276public ClCmdSay_TopTime(id)
277{
278 #if defined PREPARE_TOP_MOTD
279 if(g_bTopMotdNoData)
280 {
281 client_print_color(id, print_team_default, "%s \x03No data to do the top list yet.");
282 return;
283 }
284
285 show_motd(id, g_szTopMotd, "Time Top List");
286 #else
287 FormatTop(id, TOP_DEFAULT_NUMBER);
288 #endif
289}
290
291public ClCmdSay_TopNumberCommand(id)
292{
293 #if defined PREPARE_TOP_MOTD
294 ClCmdSay_TopTime(id)
295 #else
296 new szSaid[25]
297 read_argv(1, szSaid, charsmax(szSaid))
298
299 if( containi(szSaid, "/top") != -1 && ( containi(szSaid, "_time") != -1 || containi(szSaid, "time") != -1) )
300 {
301 replace(szSaid, charsmax(szSaid), "/top", ""); replace(szSaid, charsmax(szSaid), "_time", "");
302 replace(szSaid, charsmax(szSaid), "time", "");
303
304 if(!is_str_num(szSaid)) // If it has more other words than /top*_time
305 {
306 return PLUGIN_CONTINUE // stop plugin and continue to show the words
307 }
308
309 new iNum = str_to_num(szSaid)
310 FormatTop(id, iNum);
311 }
312 #endif
313
314 return PLUGIN_CONTINUE;
315}
316
317stock FormatTop(id, iTopNumber)
318{
319 new iData[MAX_DATA_ARRAY_SIZE];
320 iData[0] = id; iData[1] = iTopNumber;
321
322 FormatQuery(g_szQuery, charsmax(g_szQuery),
323 "SELECT `_name_field_`, `_time_field_` FROM `_table_name_` ORDER BY `_time_field_` DESC LIMIT %d", iTopNumber);
324 SQL_SendThreadedQuery("FormatTop", g_hSqlHandle,"QueryHandler_FormatTopList", g_szQuery, iData);
325}
326
327public QueryHandler_FormatTopList(FailState, Handle:hQuery, szError[], iError, Data[], iDataSize)
328{
329 if(FailState)
330 {
331 PluginLog_SQLCallback("QueryHandler_FormatTopList", Data[iDataSize - 1], iError, FailState, szError);
332 return;
333 }
334
335 if(iError)
336 {
337 PluginLog_SQLCallback("QueryHandler_FormatTopList", Data[iDataSize - 1], iError, FailState, szError);
338 return;
339 }
340
341 #if !defined PREPARE_TOP_MOTD
342 if(!is_user_connected(Data[0]))
343 {
344 return;
345 }
346 #endif
347
348 new iLen, szName[32], iPlace, iTime;
349 iLen = formatex(g_szTopMotd, charsmax(g_szTopMotd), "<body bgcolor=#000000><font color=#FFB00><pre>");
350 iLen += format(g_szTopMotd[iLen], charsmax(g_szTopMotd) - iLen,"%s %-22.22s %3s\n", "#", "Name", "Time in minutes");
351
352 new iCount;
353
354 if(!SQL_NumResults(hQuery))
355 {
356 #if defined PREPARE_TOP_MOTD
357 g_bTopMotdNoData = true;
358 #else
359 client_print_color(Data[0], print_team_default, "%s \x03No top time motd as there is no data.");
360 #endif
361
362 return;
363 }
364
365 while(SQL_MoreResults(hQuery))
366 {
367 SQL_ReadResult(hQuery, 0, szName, charsmax(szName));
368 iTime = SQL_ReadResult(hQuery, 1);
369
370 replace_all(szName, charsmax(szName), "<", "<");
371 replace_all(szName, charsmax(szName), ">", ">");
372
373 iLen += formatex(g_szTopMotd[iLen], charsmax(g_szTopMotd) - iLen, "%d %-22.22s %d\n", ++iPlace, szName, iTime / 60);
374 SQL_NextRow(hQuery)
375 iCount++;
376 }
377
378 if(iCount)
379 {
380 iLen += formatex(g_szTopMotd[iLen], charsmax(g_szTopMotd) - iLen, "</pre></font></body>");
381
382 new szTitle[25];
383 formatex(szTitle, charsmax(szTitle), "Time Top%d", Data[1]);
384
385 if(Data[0] > 0)
386 {
387 show_motd(Data[0], g_szTopMotd, szTitle);
388 }
389 }
390
391 else
392 {
393 client_print_color(Data[0], print_team_default, "%s \x01No data in database yet..", PREFIX);
394 }
395}
396
397public client_disconnected(id)
398{
399 if(is_user_bot(id))
400 {
401 return;
402 }
403
404 if(g_iPlayedTime[id] != NOT_RETRIEVED)
405 {
406 SavePlayedTime(id, true);
407 g_iPlayedTime[id] = NOT_RETRIEVED;
408 }
409}
410
411public client_authorized(id)
412{
413 if(is_user_bot(id))
414 {
415 return;
416 }
417
418 g_iPlayedTime[id] = NOT_RETRIEVED;
419 #if !defined GET_TIME_INSTANT_QUERY
420 GetClientPlayedTime(id, true);
421 #else
422 g_iPlayedTime[id] = GetClientPlayedTime(id, true);
423 #endif
424}
425
426public client_infochanged(id)
427{
428 if(!is_user_connected(id))
429 {
430 return;
431 }
432
433 get_user_name(id, g_szOldName[id], charsmax(g_szOldName[]));
434}
435
436public FMCallback_InfoChanged_Post(id)
437{
438 if(!is_user_connected(id))
439 {
440 return;
441 }
442
443 new szNewName[32];
444 get_user_name(id, szNewName, charsmax(szNewName));
445
446 if(!equal(g_szOldName[id], szNewName))
447 {
448 #if defined USE_NAME;
449 g_iPlayedTime[id] = NOT_RETRIEVED;
450 GetClientPlayedTime(id, false); // Get new played time for the new name.
451 #else
452 CleanString(szNewName, charsmax(szNewName))
453 UpdateNameInDatabase(id, szNewName);
454 #endif
455 }
456}
457
458#if !defined USE_NAME
459stock UpdateNameInDatabase(id, szNewName[])
460{
461 if(g_iPlayedTime[id] == NOT_RETRIEVED)
462 {
463 return;
464 }
465
466 new szAuthId[33]; get_user_authid(id, szAuthId, charsmax(szAuthId));
467 FormatQuery(g_szQuery, charsmax(g_szQuery), "UPDATE `_table_name_` SET `_name_field_` = '%s' WHERE `_identifier_field_` = '%s'", szNewName, szAuthId);
468 SQL_ThreadQuery(g_hSqlHandle, "QueryHandler_Dump", g_szQuery);
469}
470#endif
471
472stock SavePlayedTime(id, bool:bIsDisconnect)
473{
474 new szIdentifier[IDENTIFIER_MAX_LENGTH];
475
476 new iRet
477 ExecuteForward(g_hSaveTimeForward, iRet, id, bIsDisconnect);
478
479 #if defined USE_NAME
480 get_user_name(id, szIdentifier, charsmax(szIdentifier));
481 CleanString(szIdentifier, charsmax(szIdentifier));
482 #else
483 get_user_authid(id, szIdentifier, charsmax(szIdentifier));
484 #endif
485
486 #if defined USE_NAME
487 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);
488 #else
489 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);
490 #endif
491
492 SQL_SendThreadedQuery("SavePlayedTime", g_hSqlHandle, "QueryHandler_Dump", g_szQuery);
493}
494
495#if !defined GET_TIME_INSTANT_QUERY
496stock GetClientPlayedTime(id, bool:bConnect = true)
497{
498 new szIdentifier[MAX_NAME_LENGTH + 3];
499 #if defined USE_NAME
500 get_user_name(id, szIdentifier, charsmax(szIdentifier));
501 CleanString(szIdentifier, charsmax(szIdentifier));
502 #else
503 get_user_authid(id, szIdentifier, charsmax(szIdentifier));
504 #endif
505
506 #if defined USE_NAME
507 FormatQuery(g_szQuery, charsmax(g_szQuery), "SELECT `_time_field_` FROM `_table_name_` WHERE `_name_field_` ='%s'", szIdentifier);
508 #else
509 new szName[MAX_NAME_LENGTH]; get_user_name(id, szName, charsmax(szName));
510 FormatQuery(g_szQuery, charsmax(g_szQuery), "SELECT `_time_field_`, `_name_field_` FROM `_table_name_` WHERE `_identifier_field_` ='%s'", szIdentifier);
511 #endif
512
513 new Data[MAX_DATA_ARRAY_SIZE];
514 Data[0] = id; Data[1] = _:bConnect;
515 SQL_SendThreadedQuery("QueryHandler_GetPlayedTime", g_hSqlHandle, "QueryHandler_GetPlayedTime", g_szQuery, Data);
516}
517
518public QueryHandler_GetPlayedTime(FailState, Handle:hQuery, szError[], iError, Data[], iDataSize)
519{
520 PluginLog_SQLCallback("QueryHandler_GetPlayedTime", Data[iDataSize - 1], iError, FailState, szError);
521
522 if(iError)
523 {
524 return;
525 }
526
527 new szName[MAX_NAME_LENGTH];
528
529 #if !defined USE_NAME
530 new szIdentifier[IDENTIFIER_MAX_LENGTH]; get_user_authid(Data[0], szIdentifier, charsmax(szIdentifier));
531 #endif
532
533 new id = Data[0];
534 if(!SQL_MoreResults(hQuery))
535 {
536 get_user_name(id, szName, charsmax(szName));
537
538 #if defined USE_NAME
539 FormatQuery(g_szQuery, charsmax(g_szQuery), "INSERT INTO `_table_name_` (`_name_field_`, `_time_field_`) VALUES ('%s', '0')", szName);
540 #else
541 FormatQuery(g_szQuery, charsmax(g_szQuery), "INSERT INTO `_table_name_` (`_identifier_field_`, `_name_field_`, `_time_field_`) VALUES ('%s', '%s', '0')", szIdentifier, szName);
542 #endif
543
544 g_iPlayedTime[id] = 0;
545 SQL_SendThreadedQuery("QueryHandler_GetPlayedTime", g_hSqlHandle, "QueryHandler_Dump", g_szQuery);
546 return;
547 }
548
549 g_iPlayedTime[id] = SQL_ReadResult(hQuery, 0);
550
551 new iRet;
552 ExecuteForward(g_hGetTimeForward, iRet, id, Data[1]);
553
554 get_user_name(id, szName, charsmax(szName));
555 PluginLog("Got %d minutes (%d sec) for %s", g_iPlayedTime[id] / 60, g_iPlayedTime[id], szName);
556
557 #if !defined USE_NAME
558 new szOldSavedName[MAX_NAME_LENGTH];
559
560 //get_user_name(id, szName, charsmax(szName));
561 SQL_ReadResult(hQuery, 1, szOldSavedName, charsmax(szOldSavedName))
562
563 CleanString(szName, charsmax(szName));
564
565 if(!equal(szName, szOldSavedName))
566 {
567 FormatQuery(g_szQuery, charsmax(g_szQuery),
568 "UPDATE `_table_name_` SET `_name_field_` = '%s' WHERE `_identifier_field_` = '%s'",
569 szName, szIdentifier);
570 SQL_SendThreadedQuery("QueryHandler_GetPlayedTime", g_hSqlHandle, "QueryHandler_Dump", g_szQuery);
571 }
572 #endif
573}
574#else
575
576stock GetClientPlayedTime(id, bool:bConnect = true)
577{
578 new szIdentifier[MAX_NAME_LENGTH + 3];
579 new szName[MAX_NAME_LENGTH]; get_user_name(id, szName, charsmax(szName));
580
581 #if defined USE_NAME
582 get_user_name(id, szIdentifier, charsmax(szIdentifier));
583 CleanString(szIdentifier, charsmax(szIdentifier));
584 #else
585 get_user_authid(id, szIdentifier, charsmax(szIdentifier));
586 #endif
587
588 #if defined USE_NAME
589 FormatQuery(g_szQuery, charsmax(g_szQuery), "SELECT `_time_field_` FROM `_table_name_` WHERE `_name_field_` ='%s'", szIdentifier);
590 #else
591 FormatQuery(g_szQuery, charsmax(g_szQuery), "SELECT `_time_field_`, `_name_field_` FROM `_table_name_` WHERE `_identifier_field_` ='%s'", szIdentifier);
592 #endif
593
594 //SQL_SendThreadedQuery("QueryHandler_GetPlayedTime", g_hSqlHandle, "QueryHandler_GetPlayedTime", g_szQuery, Data);
595
596 PluginLog_Query("GetClientPlayedTime", g_szQuery);
597
598 new Handle:hQuery, Handle:hConnection;
599 new iError, szError[256];
600 hConnection = SQL_Connect(g_hSqlHandle, iError, szError, charsmax(szError));
601 ++g_iQueryNumber
602
603 if(iError)
604 {
605 SQL_FreeHandle(hConnection);
606 PluginLog_SQLCallback("GetClientPlayedTime #1", g_iQueryNumber, iError, 0, szError);
607
608 return;
609 }
610
611 hQuery = SQL_PrepareQuery(g_hSqlHandle, g_szQuery);
612
613 if(!SQL_Execute(hQuery))
614 {
615 SQL_QueryError(hQuery, szError, charsmax(szError));
616 PluginLog_SQLCallback("GetClientPlayedTime #2", g_iQueryNumber, 0, 0, szError);
617
618 SQL_FreeHandle(hQuery);
619 SQL_FreeHandle(hConnection);
620 return;
621 }
622
623 if(!SQL_MoreResults(hQuery))
624 {
625 SQL_FreeHandle(hQuery);
626 SQL_FreeHandle(hConnection);
627
628 get_user_name(id, szName, charsmax(szName));
629
630 #if defined USE_NAME
631 FormatQuery(g_szQuery, charsmax(g_szQuery), "INSERT INTO `_table_name_` (`_name_field_`, `_time_field_`) VALUES ('%s', '0')", szName);
632 #else
633 FormatQuery(g_szQuery, charsmax(g_szQuery), "INSERT INTO `_table_name_` (`_identifier_field_`, `_name_field_`, `_time_field_`) VALUES ('%s', '%s', '0')", szIdentifier, szName);
634 #endif
635
636 g_iPlayedTime[id] = 0;
637 SQL_SendThreadedQuery("GetClientPlayedTime #3", g_hSqlHandle, "QueryHandler_Dump", g_szQuery);
638 return;
639 }
640
641 new iRet;
642 ExecuteForward(g_hGetTimeForward, iRet, id, bConnect);
643
644 get_user_name(id, szName, charsmax(szName));
645 PluginLog("Got %d minutes (%d sec) for %s", g_iPlayedTime[id] / 60, g_iPlayedTime[id], szName);
646
647 #if !defined USE_NAME
648 new szOldSavedName[MAX_NAME_LENGTH];
649
650 //get_user_name(id, szName, charsmax(szName));
651 SQL_ReadResult(hQuery, 1, szOldSavedName, charsmax(szOldSavedName))
652
653 CleanString(szName, charsmax(szName));
654
655 if(!equal(szName, szOldSavedName))
656 {
657 FormatQuery(g_szQuery, charsmax(g_szQuery),
658 "UPDATE `_table_name_` SET `_name_field_` = '%s' WHERE `_identifier_field_` = '%s'",
659 szName, szIdentifier);
660 SQL_SendThreadedQuery("GetClientPlayedTime #3", g_hSqlHandle, "QueryHandler_Dump", g_szQuery);
661 }
662 #endif
663
664 g_iPlayedTime[id] = SQL_ReadResult(hQuery, 0);
665
666 SQL_FreeHandle(hQuery);
667 SQL_FreeHandle(hConnection);
668}
669#endif
670
671
672public QueryHandler_Dump(FailState, Handle:Query, szError[], iError, Data[], iDataSize)
673{
674 PluginLog_SQLCallback("QueryHandler_Dump", Data[iDataSize - 1], iError, FailState, szError);
675}
676
677CreateTableInDB()
678{
679 #if SAVE_TYPE == SQLITE
680 SQL_SetAffinity("sqlite");
681 g_hSqlHandle = SQL_MakeDbTuple("", "", "", "played_time_database");
682 #endif
683
684 #if SAVE_TYPE == MYSQL
685 SQL_SetAffinity("mysql");
686 g_hSqlHandle = SQL_MakeDbTuple(SQL_CONNECT_DATA[0], SQL_CONNECT_DATA[1], SQL_CONNECT_DATA[2], SQL_CONNECT_DATA[3]);
687 #endif
688
689 if(g_hSqlHandle == Empty_Handle)
690 {
691 set_fail_state("Could not connect to the SQL Database.");
692 }
693
694 #if SAVE_TYPE == SQLITE
695 #if defined USE_NAME
696 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");
697 #else
698 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)");
699 #endif
700 #endif
701 #if SAVE_TYPE == MYSQL
702 #if defined USE_NAME
703 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)");
704 #else
705 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)");
706 #endif
707 #endif
708
709 SQL_SendThreadedQuery("CreateTableInDB", g_hSqlHandle, "QueryHandler_Initialize", g_szQuery);
710}
711
712public QueryHandler_Initialize(FailState, Handle:Query, szError[], iError, Data[], iDataSize)
713{
714 if(FailState || iError)
715 {
716 PluginLog_SQLCallback("QueryHandler_Initialize", Data[iDataSize - 1], iError, FailState, szError);
717 #if AMXX_VERSION_NUM < 183
718 new szFailStateMessage[256];
719 formatex(szFailStateMessage, charsmax(szFailStateMessage), "FailState %d %d: %s", FailState, iError, szError);
720 set_fail_state(szFailStateMessage);
721 #else
722 set_fail_state("FailState %d %d: %s", FailState, iError, szError);
723 #endif
724 }
725
726 else
727 {
728 PluginLog("(QueryHandler_Initialize) [Query #: %d]: StartUp Query executed Successfully.", Data[iDataSize - 1]);
729 }
730
731 #if defined PREPARE_TOP_MOTD
732 FormatTop(-1, TOP_DEFAULT_NUMBER);
733 #endif
734}
735
736// NATIVES
737public native_get_user_played_time(plugin_id, argc)
738{
739 new id = get_param(1);
740 if(!IsValidPlayer_Native(id))
741 {
742 return -1
743 }
744
745 return g_iPlayedTime[id];
746}
747
748public native_set_user_played_time(plugin_id, argc)
749{
750 new id = get_param(1);
751 new iNewTime = get_param(2);
752
753 if(!IsValidPlayer_Native(id))
754 {
755 return 0
756 }
757
758 g_iPlayedTime[id] = iNewTime;
759 return 1;
760}
761
762public native_get_save_type(plugin_id, argc)
763{
764 return SAVE_TYPE;
765}
766
767stock IsValidPlayer_Native(id)
768{
769 if(!is_user_connected(id))
770 {
771 log_error(AMX_ERR_NATIVE, "Client %d is NOT connected", id);
772 return 0;
773 }
774
775 if(is_user_bot(id))
776 {
777 log_error(AMX_ERR_NATIVE, "Client %d is a BOT", id);
778 return 0;
779 }
780
781 if(is_user_hltv(id))
782 {
783 log_error(AMX_ERR_NATIVE, "HLTV client %d", id);
784 return 0;
785 }
786
787 if( !( 1 <= id <= g_iMaxPlayers ) )
788 {
789 log_error(AMX_ERR_NATIVE, "Index out of bounds %d", id);
790 return 0
791 }
792
793 return 1;
794}
795
796stock CleanString(szName[], iSize)
797{
798 replace_all(szName, iSize, "\"", "");
799 replace_all(szName, iSize, "'", "");
800}
801
802stock FormatQuery(szQueryStorage[], iSize, szQuery[], any:...)
803{
804 vformat(szQueryStorage, iSize, szQuery, 4);
805
806 replace_all(szQueryStorage, iSize, "_identifier_field_", "steamid");
807 replace_all(szQueryStorage, iSize, "_name_field_", "name");
808 replace_all(szQueryStorage, iSize, "_time_field_", "time_played");
809 replace_all(szQueryStorage, iSize, "_table_name_", "played_time");
810}
811
812stock SQL_SendThreadedQuery(szPosition[], Handle:hSql, szQueryCallback[], szQuery[], Data[MAX_DATA_ARRAY_SIZE] = "")
813{
814 new ModifiedData[MAX_DATA_ARRAY_SIZE + 1];
815
816 // Must be before, as this is where the increment happen.
817 PluginLog_Query(szPosition, szQuery);
818 for(new i; i < MAX_DATA_ARRAY_SIZE; i++)
819 {
820 ModifiedData[i] = Data[i];
821 }
822
823 ModifiedData[MAX_DATA_ARRAY_SIZE] = g_iQueryNumber;
824
825 SQL_ThreadQuery(hSql, szQueryCallback, szQuery, ModifiedData, MAX_DATA_ARRAY_SIZE + 1);
826}
827
828stock PluginLog(szString[], any:...)
829{
830 #if !defined DO_NOT_LOG
831 new szLog[1024]
832 vformat(szLog, charsmax(szLog), szString, 2);
833
834 log_to_file(LOG_FILE_PLAYED_TIME, szLog);
835 //log_amx("[Played Time] %s", szLog);
836 #endif
837}
838
839stock PluginLog_Query(szPosition[], szQuery[])
840{
841 #if !defined DO_NOT_LOG
842 log_to_file(LOG_FILE_PLAYED_TIME, "(%s) Query Executed (#%d): \n\t\t\t\t%s", szPosition, ++g_iQueryNumber, szQuery);
843 //log_amx("[Played Time] (%s) Query Executed (#%d): \n\t\t%s", szPosition, g_iQueryNumber, szQuery);
844 #endif
845}
846
847stock PluginLog_SQLCallback(szPosition[], iQueryNumber, iError, FailState, szError[])
848{
849 #if !defined DO_NOT_LOG
850 if(iError || FailState)
851 {
852 log_to_file(LOG_FILE_PLAYED_TIME, "(%s) [Query#: %d] [Error# :%d] [FailState: %d]: %s", szPosition, iQueryNumber, iError, FailState, szError);
853 }
854
855 else if(!iError && !FailState)
856 {
857 log_to_file(LOG_FILE_PLAYED_TIME, "(%s) [Query#: %d] executed successfully", szPosition, iQueryNumber);
858 }
859 #endif
860}