Code:
/*
Copyleft 2015 @ HamletEagle
ReportsSystem is free software;
you can redistribute it and/or modify it under the terms of the
GNU General Public License as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with ReportsSystem; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
#include <amxmodx>
#include <amxmisc>
#include <curl>
#define PluginName "ReportsSystem"
#define PluginVersion "1.0"
#define PluginAuthor "HamletEagle"
#define CURL_BUFFER_SIZE 1024
static webhook_url[] = "https://discord.com/api/webhooks/1083950891004080298/UJVNv5ffXvIGWhot7qw1iDW28fnRK9-AO93kp2eJaTH56z3OTPQRUw8ZQmaTyiB0AwSF"
new server_hostname[32], server_ip[32]
enum _:ReportData
{
ReporterName[32],
ReportedName[32],
Reason[128]
}
enum _:Mode
{
ModeReasons,
ModeReports
}
const AdminFlag = ADMIN_BAN
new Array:ArrayReasons
new Array:ArrayReports
new ReportedPlayer[33]
new ConfigsDirPath[80]
new ConfigFilePath[128]
new CvarReportLimit
new Float:FullReportTime[33]
public plugin_init()
{
register_plugin
(
.plugin_name = PluginName,
.version = PluginVersion,
.author = PluginAuthor
)
register_clcmd("say /report_player", "ClientCommand_Report")
register_clcmd("say_team /report_player", "ClientCommand_Report")
register_concmd("amx_showreports", "ClientCommand_ShowReports", AdminFlag)
register_concmd("amx_solvereport", "ClientCommand_SolveReport", AdminFlag)
register_concmd("amx_clearreports", "ClientCommand_ClearReports", AdminFlag)
CvarReportLimit = register_cvar("amx_nextreport", "10")
ArrayReasons = ArrayCreate(128)
ArrayReports = ArrayCreate(ReportData)
get_configsdir(ConfigsDirPath, charsmax(ConfigsDirPath))
ParseReasonsFile()
ParseReportsFile()
get_user_ip(0, server_ip, charsmax(server_ip));
get_cvar_string("hostname", server_hostname, charsmax(server_hostname));
}
public plugin_end()
{
AddReportsToFile()
ArrayDestroy(ArrayReasons)
ArrayDestroy(ArrayReports)
}
/*
public client_disconnect(id)
{
new Size = ArraySize(ArrayReports), Data[ReportData]
for(new i; i < Size; i++)
{
ArrayGetArray(ArrayReports, i, Data)
if
(
id == get_user_index(Data[ReporterName]) ||
id == get_user_index(Data[ReportedName])
)
{
ArrayDeleteItem(ArrayReports, i)
}
}
}
*/
ParseReasonsFile()
{
new const ReasonsFile[] = "report_reasons.ini"
formatex(ConfigFilePath, charsmax(ConfigFilePath), "%s/%s", ConfigsDirPath, ReasonsFile)
ReadFile(ConfigFilePath, ModeReasons)
}
ParseReportsFile()
{
new const ReportsFile[] = "reports_list.ini"
formatex(ConfigFilePath, charsmax(ConfigFilePath), "%s/%s", ConfigsDirPath, ReportsFile)
ReadFile(ConfigFilePath, ModeReports)
}
AddReportsToFile()
{
if(file_exists(ConfigFilePath))
{
delete_file(ConfigFilePath)
}
new FilePointer = fopen(ConfigFilePath, "wt"), Data[ReportData]
if(FilePointer)
{
new Size = ArraySize(ArrayReports)
for(new i; i < Size; i++)
{
ArrayGetArray(ArrayReports, i, Data)
fprintf(FilePointer, "%s %s %s^n", Data[ReporterName], Data[ReportedName], Data[Reason])
}
fclose(FilePointer)
}
}
ReadFile(File[], Mod)
{
new FilePointer = fopen(File, "rt")
if(FilePointer)
{
new FileData[128], Data[ReportData]
while(!feof(FilePointer))
{
fgets(FilePointer, FileData, charsmax(FileData))
trim(FileData)
if(!FileData[0] || FileData[0] == ';' || FileData[0] == '#' || FileData[0] == '/')
{
continue
}
switch(Mod)
{
case ModeReasons:
{
ArrayPushString(ArrayReasons, FileData)
}
case ModeReports:
{
parse
(
FileData,
Data[ReporterName], charsmax(Data[ReporterName]),
Data[ReportedName], charsmax(Data[ReportedName]),
Data[Reason ], charsmax(Data[Reason ])
)
ArrayPushArray(ArrayReports, Data)
}
}
}
}
}
public ClientCommand_Report(id)
{
new Float:GameTime = get_gametime()
if(GameTime > FullReportTime[id])
{
new ReportMenu = menu_create("Report:", "HandleReportMenu")
new Players[32], PlayersNum, index
get_players(Players, PlayersNum)
new PlayerName[32], UserId[6]
for(new i ; i < PlayersNum; i++)
{
index = Players[i]
get_user_name(index, PlayerName, charsmax(PlayerName))
num_to_str(get_user_userid(index), UserId, charsmax(UserId))
menu_additem(ReportMenu, PlayerName, UserId, 0)
}
menu_display(id, ReportMenu, 0)
FullReportTime[id] = GameTime + (float(get_pcvar_num(CvarReportLimit)) * 60.0)
}
else
{
client_print(id, print_chat, "You must wait: %.1f in order to report again", FullReportTime[id] - GameTime)
}
}
public ClientCommand_ShowReports(id, level, cid)
{
if(!cmd_access(id, level, cid, 0))
{
return 1
}
new Size = ArraySize(ArrayReports), Data[ReportData]
if(!Size)
{
console_print(id, "There are no reports open")
}
else
{
for(new i; i < Size; i++)
{
ArrayGetArray(ArrayReports, i, Data)
console_print(id, "[ %i ]Reporter: %s^nReported: %s^nReason:%s",i, Data[ReporterName], Data[ReportedName], Data[Reason])
console_print(id, "=========================================")
}
console_print(id, "Write amx_solvereport report_number to close it")
}
return 1
}
public ClientCommand_SolveReport(id, level, cid)
{
if(!cmd_access(id, level, cid, 1))
{
return 1
}
new Argument[5], Data[ReportData], ArrayEntry, Size = ArraySize(ArrayReports)
read_argv(1, Argument, charsmax(Argument))
ArrayEntry = str_to_num(Argument)
if(ArrayEntry >= Size || ArrayEntry < 0)
{
console_print(id, "Report number is invalid. Valid range: 0 - %i", Size)
}
else
{
ArrayGetArray(ArrayReports, ArrayEntry, Data)
console_print(id, "You closed the report with number %i", ArrayEntry)
client_print(0, print_chat, "%s reported %s for %s. Report is now closed", Data[ReporterName], Data[ReportedName], Data[Reason])
ArrayDeleteItem(ArrayReports, ArrayEntry)
}
return 1
}
public ClientCommand_ClearReports(id, level, cid)
{
if(!cmd_access(id, level, cid, 1))
{
return 1
}
ArrayClear(ArrayReports)
console_print(id, "You cleared all the reports")
return 1
}
public HandleReportMenu(id, ReportMenu, item)
{
if(item == MENU_EXIT)
{
menu_destroy(ReportMenu)
return
}
new UserId[6], Name[32], Access, CallBack
menu_item_getinfo(ReportMenu, item, Access, UserId, charsmax(UserId), Name, charsmax(Name), CallBack)
new IntUserId = str_to_num(UserId)
new Target = find_player("k", IntUserId) //get reported player index
if(Target)
{
ReportedPlayer[id] = Target
BuildReasonsMenu(id)
}
else
{
client_print(id, print_chat, "Target could not be found %s", Name)
}
menu_destroy(ReportMenu)
}
BuildReasonsMenu(id)
{
new ReasonsMenu = menu_create("Select a reason", "HandleReasonsMenu")
new Size = ArraySize(ArrayReasons), HandleReason[128]
for(new i; i < Size; i++)
{
ArrayGetString(ArrayReasons, i, HandleReason, charsmax(HandleReason))
menu_additem(ReasonsMenu, HandleReason, "", 0)
}
menu_display(id, ReasonsMenu, 0)
}
public HandleReasonsMenu(id, ReasonsMenu, item)
{
if(item == MENU_EXIT)
{
menu_destroy(ReasonsMenu)
return
}
//Get the reason for reporting
new HandleReason[128]
ArrayGetString(ArrayReasons, item, HandleReason, charsmax(HandleReason))
AddReport(id, ReportedPlayer[id], HandleReason)
client_print(id, print_chat, "Report was succesfully sent")
menu_destroy(ReasonsMenu)
}
AddReport(id, Target, const HandleReason[])
{
new Data[ReportData]
get_user_name(id, Data[ReporterName], charsmax(Data[ReporterName]))
get_user_name(Target, Data[ReportedName], charsmax(Data[ReportedName]))
copy(Data[Reason], charsmax(Data[Reason]), HandleReason)
ArrayPushArray(ArrayReports, Data)
send_discord_message(id, Target, Data[Reason])
new Players[32], Num, index
get_players(Players, Num, "c")
for(new i; i < Num; i++)
{
index = Players[i]
if(get_user_flags(index) & AdminFlag)
{
client_print(index, print_center, "A new report was send")
}
}
}
enum dataStruct { curl_slist: linkedList };
public send_discord_message(id, target, reason[]){
new CURL: pCurl, curl_slist: pHeaders;
new sData[dataStruct];
pHeaders = curl_slist_append(pHeaders, "Content-Type: application/json");
pHeaders = curl_slist_append(pHeaders, "User-Agent: pay-attention");
pHeaders = curl_slist_append(pHeaders, "Connection: Keep-Alive");
sData[linkedList] = pHeaders;
if ((pCurl = curl_easy_init())) {
new text_send[CURL_BUFFER_SIZE];
new reporter_name[32], reporter_steamid[32]
new target_name[32], target_steamid[32]
get_user_name(id, reporter_name, charsmax(reporter_name))
get_user_authid(id, reporter_steamid, charsmax(reporter_steamid))
get_user_name(target, target_name, charsmax(target_name))
get_user_authid(target, target_steamid, charsmax(target_steamid))
remove_quotes(reason)
formatex(text_send, charsmax(text_send),
"{ ^"username^": ^"Calladmin Report System^", \
^"avatar_url^": ^"https://picsum.photos/200/200.jpg^", \
^"content^": ^"New report received^", \
^"embeds^": [ { \
^"author^": { ^"name^": ^"%s^", ^"url^": ^"https://gametracker.com/server_info/%s^" }, ^"color^": %d, ^"title^": ^"IP: %s^", \
^"fields^": [ \
{ ^"name^": ^"Reporter^", ^"value^": ^"%s^", ^"inline^": true }, \
{ ^"name^": ^"Steam ID^", ^"value^": ^"%s^", ^"inline^": true }, \
{ ^"name^": ^"\u200b^", ^"value^": ^"\u200b^" }, \
{ ^"name^": ^"Reported^", ^"value^": ^"%s^", ^"inline^": true }, \
{ ^"name^": ^"Steam ID^", ^"value^": ^"%s^", ^"inline^": true }, \
{ ^"name^": ^"Reason^", ^"value^": ^"%s^", ^"inline^": true } \
] } \
] \
}", server_hostname, server_ip, random(16777215), server_ip, reporter_name, reporter_steamid, target_name, target_steamid, reason);
// write_file("test.txt", text_send) # TESTING
curl_easy_setopt(pCurl, CURLOPT_URL, webhook_url);
curl_easy_setopt(pCurl, CURLOPT_COPYPOSTFIELDS, text_send);
curl_easy_setopt(pCurl, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(pCurl, CURLOPT_HTTPHEADER, pHeaders);
curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 0);
curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYHOST, 0);
curl_easy_setopt(pCurl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
curl_easy_setopt(pCurl, CURLOPT_FAILONERROR, 0);
curl_easy_setopt(pCurl, CURLOPT_FOLLOWLOCATION, 0);
curl_easy_setopt(pCurl, CURLOPT_FORBID_REUSE, 0);
curl_easy_setopt(pCurl, CURLOPT_FRESH_CONNECT, 0);
curl_easy_setopt(pCurl, CURLOPT_CONNECTTIMEOUT, 10);
curl_easy_setopt(pCurl, CURLOPT_TIMEOUT, 10);
curl_easy_setopt(pCurl, CURLOPT_POST, 1);
curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, "@responseWrite");
curl_easy_perform(pCurl, "@requestComplete", sData, dataStruct);
}
}
@responseWrite(const data[], const size, const nmemb){
server_print("Response body: \n%s", data);
return size * nmemb;
}
@requestComplete(CURL: curl, CURLcode: code, const data[dataStruct]){
curl_easy_cleanup(curl);
curl_slist_free_all(data[linkedList]);
}