· 8 years ago · Nov 19, 2017, 04:28 PM
1/*
2 * shavit's Timer - Chat
3 * by: shavit
4 *
5 * This file is part of shavit's Timer.
6 *
7 * This program is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, version 3.0, as published by the
9 * Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14 * details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19*/
20
21// Note: For donator perks, give donators a custom flag and then override it to have "shavit_chat".
22
23#include <sourcemod>
24#include <chat-processor>
25
26#undef REQUIRE_PLUGIN
27#define USES_CHAT_COLORS
28#include <shavit>
29#include <rtler>
30
31#pragma newdecls required
32#pragma semicolon 1
33
34// database
35Database gH_SQL = null;
36char gS_MySQLPrefix[32];
37
38// modules
39bool gB_RTLer = false;
40
41// cache
42EngineVersion gEV_Type = Engine_Unknown;
43
44bool gB_NameEnabled[MAXPLAYERS+1];
45char gS_CustomName[MAXPLAYERS+1][128];
46
47bool gB_MessageEnabled[MAXPLAYERS+1];
48char gS_CustomMessage[MAXPLAYERS+1][16];
49
50public Plugin myinfo =
51{
52 name = "[shavit] Chat",
53 author = "shavit",
54 description = "Custom chat privileges (custom name and message colors).",
55 version = SHAVIT_VERSION,
56 url = "https://github.com/shavitush/bhoptimer"
57}
58
59public void OnAllPluginsLoaded()
60{
61 gB_RTLer = LibraryExists("rtler");
62
63 if(gH_SQL == null)
64 {
65 Shavit_OnDatabaseLoaded();
66 }
67}
68
69public void OnPluginStart()
70{
71 gEV_Type = GetEngineVersion();
72
73 LoadTranslations("shavit-common.phrases");
74 LoadTranslations("shavit-chat.phrases");
75
76 RegConsoleCmd("sm_cchelp", Command_CCHelp, "Provides help with setting a custom chat name/message color.");
77 RegConsoleCmd("sm_ccname", Command_CCName, "Toggles/sets a custom chat name. Usage: sm_ccname <text> or sm_ccname \"off\" to disable.");
78 RegConsoleCmd("sm_ccmsg", Command_CCMessage, "Toggles/sets a custom chat message color. Usage: sm_ccmsg <color> or sm_ccmsg \"off\" to disable.");
79 RegConsoleCmd("sm_ccmessage", Command_CCMessage, "Toggles/sets a custom chat message color. Usage: sm_ccmessage <color> or sm_ccmessage \"off\" to disable.");
80
81 RegAdminCmd("sm_cclist", Command_CCList, ADMFLAG_CHAT, "Print the custom chat setting of all online players.");
82
83 for(int i = 1; i <= MaxClients; i++)
84 {
85 if(IsClientInGame(i) && !IsFakeClient(i))
86 {
87 OnClientPostAdminCheck(i);
88 }
89 }
90
91 SQL_SetPrefix();
92}
93
94public void Shavit_OnDatabaseLoaded()
95{
96 gH_SQL = Shavit_GetDatabase();
97 SetSQLInfo();
98}
99
100public Action CheckForSQLInfo(Handle Timer)
101{
102 return SetSQLInfo();
103}
104
105Action SetSQLInfo()
106{
107 if(gH_SQL == null)
108 {
109 gH_SQL = Shavit_GetDatabase();
110
111 CreateTimer(0.5, CheckForSQLInfo);
112 }
113
114 else
115 {
116 SQL_DBConnect();
117
118 return Plugin_Stop;
119 }
120
121 return Plugin_Continue;
122}
123
124void SQL_SetPrefix()
125{
126 char[] sFile = new char[PLATFORM_MAX_PATH];
127 BuildPath(Path_SM, sFile, PLATFORM_MAX_PATH, "configs/shavit-prefix.txt");
128
129 File fFile = OpenFile(sFile, "r");
130
131 if(fFile == null)
132 {
133 SetFailState("Cannot open \"configs/shavit-prefix.txt\". Make sure this file exists and that the server has read permissions to it.");
134 }
135
136 char[] sLine = new char[PLATFORM_MAX_PATH*2];
137
138 while(fFile.ReadLine(sLine, PLATFORM_MAX_PATH*2))
139 {
140 TrimString(sLine);
141 strcopy(gS_MySQLPrefix, 32, sLine);
142
143 break;
144 }
145
146 delete fFile;
147}
148
149public void OnLibraryAdded(const char[] name)
150{
151 if(StrEqual(name, "rtler"))
152 {
153 gB_RTLer = true;
154 }
155}
156
157public void OnLibraryRemoved(const char[] name)
158{
159 if(StrEqual(name, "rtler"))
160 {
161 gB_RTLer = false;
162 }
163}
164
165public void OnClientPutInServer(int client)
166{
167 gB_NameEnabled[client] = false;
168 strcopy(gS_CustomName[client], 128, "");
169
170 gB_MessageEnabled[client] = false;
171 strcopy(gS_CustomMessage[client], 128, "");
172}
173
174public void OnClientPostAdminCheck(int client)
175{
176 if(gH_SQL != null)
177 {
178 LoadFromDatabase(client);
179 }
180}
181
182public Action Command_CCHelp(int client, int args)
183{
184 if(client == 0)
185 {
186 ReplyToCommand(client, "%t", "NoConsole");
187
188 return Plugin_Handled;
189 }
190
191 Shavit_PrintToChat(client, "%T", "CheckConsole", client);
192
193 PrintToConsole(client, "%T\n", "CCHelp_Intro", client);
194 PrintToConsole(client, "%T", "CCHelp_Generic", client);
195 PrintToConsole(client, "%T", "CCHelp_GenericVariables", client);
196
197 if(gEV_Type == Engine_CSS)
198 {
199 PrintToConsole(client, "%T", "CCHelp_CSS_1", client);
200 PrintToConsole(client, "%T", "CCHelp_CSS_2", client);
201 }
202
203 else
204 {
205 PrintToConsole(client, "%T", "CCHelp_CSGO_1", client);
206 }
207
208 return Plugin_Handled;
209}
210
211public Action Command_CCName(int client, int args)
212{
213 if(client == 0)
214 {
215 ReplyToCommand(client, "%t", "NoConsole");
216
217 return Plugin_Handled;
218 }
219
220 if(!CheckCommandAccess(client, "shavit_chat", ADMFLAG_CHAT))
221 {
222 Shavit_PrintToChat(client, "%T", "NoCommandAccess", client);
223
224 return Plugin_Handled;
225 }
226
227 char[] sArgs = new char[128];
228 GetCmdArgString(sArgs, 128);
229 TrimString(sArgs);
230 FormatColors(sArgs, 128, true, true);
231
232 if(args == 0 || strlen(sArgs) == 0)
233 {
234 Shavit_PrintToChat(client, "%T", "ArgumentsMissing", client, "sm_ccname <text>");
235 Shavit_PrintToChat(client, "%T", "ChatCurrent", client, gS_CustomName[client]);
236
237 return Plugin_Handled;
238 }
239
240 else if(StrEqual(sArgs, "off"))
241 {
242 Shavit_PrintToChat(client, "%T", "NameOff", client, sArgs);
243
244 gB_NameEnabled[client] = false;
245
246 SaveToDatabase(client);
247
248 return Plugin_Handled;
249 }
250
251 Shavit_PrintToChat(client, "%T", "ChatUpdated", client);
252
253 gB_NameEnabled[client] = true;
254 strcopy(gS_CustomName[client], 128, sArgs);
255
256 SaveToDatabase(client);
257
258 return Plugin_Handled;
259}
260
261public Action Command_CCMessage(int client, int args)
262{
263 if(client == 0)
264 {
265 ReplyToCommand(client, "%t", "NoConsole");
266
267 return Plugin_Handled;
268 }
269
270 if(!CheckCommandAccess(client, "shavit_chat", ADMFLAG_CHAT))
271 {
272 Shavit_PrintToChat(client, "%T", "NoCommandAccess", client);
273
274 return Plugin_Handled;
275 }
276
277 char[] sArgs = new char[32];
278 GetCmdArgString(sArgs, 32);
279 TrimString(sArgs);
280 FormatColors(sArgs, 32, true, true);
281
282 if(args == 0 || strlen(sArgs) == 0)
283 {
284 Shavit_PrintToChat(client, "%T", "ArgumentsMissing", client, "sm_ccmsg <text>");
285 Shavit_PrintToChat(client, "%T", "ChatCurrent", client, gS_CustomMessage[client]);
286
287 return Plugin_Handled;
288 }
289
290 else if(StrEqual(sArgs, "off"))
291 {
292 Shavit_PrintToChat(client, "%T", "MessageOff", client, sArgs);
293
294 gB_MessageEnabled[client] = false;
295
296 SaveToDatabase(client);
297
298 return Plugin_Handled;
299 }
300
301 Shavit_PrintToChat(client, "%T", "ChatUpdated", client);
302
303 gB_MessageEnabled[client] = true;
304 strcopy(gS_CustomMessage[client], 16, sArgs);
305
306 SaveToDatabase(client);
307
308 return Plugin_Handled;
309}
310
311public Action Command_CCList(int client, int args)
312{
313 ReplyToCommand(client, "%T", "CheckConsole", client);
314
315 for(int i = 1; i <= MaxClients; i++)
316 {
317 if(CheckCommandAccess(client, "shavit_chat", ADMFLAG_CHAT))
318 {
319 PrintToConsole(client, "%N (%d/%d) (name: \"%s\"; message: \"%s\")", i, i, GetClientUserId(i), gS_CustomName[i], gS_CustomMessage[i]);
320 }
321 }
322
323 return Plugin_Handled;
324}
325
326public Action CP_OnChatMessage(int &author, ArrayList recipients, char[] flagstring, char[] name, char[] message, bool &processcolors, bool &removecolors)
327{
328 if(author == 0 || !CheckCommandAccess(client, "shavit_chat", ADMFLAG_CHAT))
329 {
330 return Plugin_Continue;
331 }
332
333 if(gB_NameEnabled[author] && strlen(gS_CustomName[author]) > 0)
334 {
335 char[] sName = new char[MAX_NAME_LENGTH];
336 GetClientName(author, sName, MAX_NAME_LENGTH);
337 ReplaceString(gS_CustomName[author], MAXLENGTH_NAME, "{name}", sName);
338
339 strcopy(name, MAXLENGTH_NAME, gS_CustomName[author]);
340 FormatRandom(name, MAXLENGTH_NAME);
341
342 if(gEV_Type == Engine_CSGO)
343 {
344 Format(name, MAXLENGTH_NAME, " %s", name);
345 }
346 }
347
348 if(gB_MessageEnabled[author] && strlen(gS_CustomMessage[author]) > 0)
349 {
350 char[] sTemp = new char[MAXLENGTH_MESSAGE];
351
352 // proper colors with rtler
353 if(gB_RTLer && RTLify(sTemp, MAXLENGTH_MESSAGE, message) > 0)
354 {
355 Format(message, MAXLENGTH_MESSAGE, "%s%s", message, gS_CustomMessage[author]);
356 }
357
358 else
359 {
360 Format(message, MAXLENGTH_MESSAGE, "%s%s", gS_CustomMessage[author], message);
361 }
362
363 FormatRandom(message, MAXLENGTH_MESSAGE);
364 }
365
366 #if defined DEBUG
367 PrintToServer("%N %s", author, flagstring);
368 #endif
369
370 bool allchat = (StrContains(flagstring, "_All") != -1);
371 int team = GetClientTeam(author);
372
373 recipients.Clear();
374
375 for(int i = 1; i <= MaxClients; i++)
376 {
377 if(i == author || (IsClientInGame(i) && (allchat || GetClientTeam(i) == team)))
378 {
379 recipients.Push(i);
380 }
381 }
382
383 removecolors = true;
384 processcolors = false;
385
386 return Plugin_Changed;
387}
388
389void FormatColors(char[] buffer, int size, bool colors, bool escape)
390{
391 if(colors)
392 {
393 for(int i = 0; i < sizeof(gS_GlobalColorNames); i++)
394 {
395 ReplaceString(buffer, size, gS_GlobalColorNames[i], gS_GlobalColors[i]);
396 }
397
398 for(int i = 0; i < sizeof(gS_CSGOColorNames); i++)
399 {
400 ReplaceString(buffer, size, gS_CSGOColorNames[i], gS_CSGOColors[i]);
401 }
402
403 ReplaceString(buffer, size, "^", "\x07");
404 ReplaceString(buffer, size, "{RGB}", "\x07");
405 ReplaceString(buffer, size, "&", "\x08");
406 ReplaceString(buffer, size, "{RGBA}", "\x08");
407 }
408
409 if(escape)
410 {
411 ReplaceString(buffer, size, "%%", "");
412 }
413}
414
415void FormatRandom(char[] buffer, int size)
416{
417 char[] temp = new char[8];
418
419 do
420 {
421 if(gEV_Type == Engine_CSS)
422 {
423 int color = ((RealRandomInt(0, 255) & 0xFF) << 16);
424 color |= ((RealRandomInt(0, 255) & 0xFF) << 8);
425 color |= (RealRandomInt(0, 255) & 0xFF);
426
427 FormatEx(temp, 8, "\x07%06X", color);
428 }
429
430 else
431 {
432 strcopy(temp, 8, gS_CSGOColors[RealRandomInt(0, sizeof(gS_CSGOColors) - 1)]);
433 }
434 }
435
436 while(ReplaceStringEx(buffer, size, "{rand}", temp) > 0);
437}
438
439int RealRandomInt(int min, int max)
440{
441 int random = GetURandomInt();
442
443 if(random == 0)
444 {
445 random++;
446 }
447
448 return (RoundToCeil(float(random) / (float(2147483647) / float(max - min + 1))) + min - 1);
449}
450
451void SQL_DBConnect()
452{
453 if(gH_SQL != null)
454 {
455 char[] sQuery = new char[512];
456 FormatEx(sQuery, 512, "CREATE TABLE IF NOT EXISTS `%schat` (`auth` CHAR(32) NOT NULL, `name` INT NOT NULL DEFAULT 0, `ccname` CHAR(128), `message` INT NOT NULL DEFAULT 0, `ccmessage` CHAR(16), PRIMARY KEY (`auth`));", gS_MySQLPrefix);
457
458 gH_SQL.Query(SQL_CreateTable_Callback, sQuery, 0, DBPrio_High);
459 }
460}
461
462public void SQL_CreateTable_Callback(Database db, DBResultSet results, const char[] error, any data)
463{
464 if(results == null)
465 {
466 LogError("Timer error! Chat table creation failed. Reason: %s", error);
467
468 return;
469 }
470
471 for(int i = 1; i <= MaxClients; i++)
472 {
473 if(CheckCommandAccess(client, "shavit_chat", ADMFLAG_CHAT))
474 {
475 LoadFromDatabase(i);
476 }
477 }
478}
479
480void SaveToDatabase(int client)
481{
482 char[] sAuthID3 = new char[32];
483
484 if(!GetClientAuthId(client, AuthId_Steam3, sAuthID3, 32))
485 {
486 return;
487 }
488
489 int iLength = ((strlen(gS_CustomName[client]) * 2) + 1);
490 char[] sEscapedName = new char[iLength];
491 gH_SQL.Escape(gS_CustomName[client], sEscapedName, iLength);
492
493 iLength = ((strlen(gS_CustomMessage[client]) * 2) + 1);
494 char[] sEscapedMessage = new char[iLength];
495 gH_SQL.Escape(gS_CustomMessage[client], sEscapedMessage, iLength);
496
497 char[] sQuery = new char[512];
498 FormatEx(sQuery, 512, "REPLACE INTO %schat (auth, name, ccname, message, ccmessage) VALUES ('%s', %d, '%s', %d, '%s');", gS_MySQLPrefix, sAuthID3, gB_NameEnabled[client], sEscapedName, gB_MessageEnabled[client], sEscapedMessage);
499
500 gH_SQL.Query(SQL_UpdateUser_Callback, sQuery, 0, DBPrio_High);
501}
502
503public void SQL_UpdateUser_Callback(Database db, DBResultSet results, const char[] error, any data)
504{
505 if(results == null)
506 {
507 LogError("Timer error! Failed to insert chat data. Reason: %s", error);
508
509 return;
510 }
511}
512
513void LoadFromDatabase(int client)
514{
515 char[] sAuthID3 = new char[32];
516
517 if(!GetClientAuthId(client, AuthId_Steam3, sAuthID3, 32))
518 {
519 return;
520 }
521
522 char sQuery[256];
523 FormatEx(sQuery, 256, "SELECT name, ccname, message, ccmessage FROM %schat WHERE auth = '%s';", gS_MySQLPrefix, sAuthID3);
524
525 gH_SQL.Query(SQL_GetChat_Callback, sQuery, GetClientSerial(client), DBPrio_Low);
526}
527
528public void SQL_GetChat_Callback(Database db, DBResultSet results, const char[] error, any data)
529{
530 if(results == null)
531 {
532 LogError("Timer (Chat cache update) SQL query failed. Reason: %s", error);
533
534 return;
535 }
536
537 int client = GetClientFromSerial(data);
538
539 if(client == 0)
540 {
541 return;
542 }
543
544 while(results.FetchRow())
545 {
546 gB_NameEnabled[client] = view_as<bool>(results.FetchInt(0));
547 results.FetchString(1, gS_CustomName[client], 128);
548
549 gB_MessageEnabled[client] = view_as<bool>(results.FetchInt(2));
550 results.FetchString(3, gS_CustomMessage[client], 16);
551 }
552}