Skip to content

Commit 250c665

Browse files
committed
Implemented HLKZ to Service communication for Discord webhook
1 parent 6673770 commit 250c665

16 files changed

+1106
-232
lines changed

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,12 @@ Doing `cd` into your _ag/maps_ folder and executing `ls *.bsp >> ../addons/amxmo
2020

2121
speclist provides a command to toggle a list of spectators watching you
2222

23+
## hl_kreedz_discord
24+
25+
hl_kreedz_discord can send info about new WRs to a service (not directly to the webhook as this AMXX cURL doesn't support SSL yet), in the format of a JSON that a Discord webhook can understand so that a Discord bot posts that info to a chat. Requires setting the URL of the service with this cvar:
26+
kz_discord_service "http://example.domain/whatever/some_service_name.php"
27+
And the Discord webhook token with this cvar:
28+
kz_discord_webhook "https://ptb.discordapp.com/api/webhooks/some_number/some_token"
29+
2330

2431
TODO: explain all the available commands for admins and players

data/lang/q_jumpstats.txt

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
[en]
2-
Q_JS_GODLIKE = [LJStats] [GODLIKE] %s did a %s of %.2f!
3-
Q_JS_PERFECT = [LJStats] [Perfect] %s did a %s of %.2f!
4-
Q_JS_IMPRESSIVE = [LJStats] [Impressive] %s did a %s of %.2f!
5-
Q_JS_LEET = [LJStats] [Leet] %s did a %s of %.2f!
6-
Q_JS_PRO = [LJStats] [Pro] %s did a %s of %.2f!
2+
Q_JS_GODLIKE = [LJStats] [GODLIKE] %s^0 did a %s of %.2f!
3+
Q_JS_PERFECT = [LJStats] [Perfect] %s^0 did a %s of %.2f!
4+
Q_JS_IMPRESSIVE = [LJStats] [Impressive] %s^0 did a %s of %.2f!
5+
Q_JS_LEET = [LJStats] [Leet] %s^0 did a %s of %.2f!
6+
Q_JS_PRO = [LJStats] [Pro] %s^0 did a %s of %.2f!
77

88
[es]
9-
Q_JS_GODLIKE = [LJStats] [ALUCINANTE] %s hizo un %s de %.2f!
10-
Q_JS_PERFECT = [LJStats] [Perfecto] %s hizo un %s de %.2f!
11-
Q_JS_IMPRESSIVE = [LJStats] [Impresionante] %s hizo un %s de %.2f!
12-
Q_JS_LEET = [LJStats] [Leet] %s hizo un %s de %.2f!
13-
Q_JS_PRO = [LJStats] [Pro] %s hizo un %s de %.2f!
9+
Q_JS_GODLIKE = [LJStats] [ALUCINANTE] %s^0 hizo un %s de %.2f!
10+
Q_JS_PERFECT = [LJStats] [Perfecto] %s^0 hizo un %s de %.2f!
11+
Q_JS_IMPRESSIVE = [LJStats] [Impresionante] %s^0 hizo un %s de %.2f!
12+
Q_JS_LEET = [LJStats] [Leet] %s^0 hizo un %s de %.2f!
13+
Q_JS_PRO = [LJStats] [Pro] %s^0 hizo un %s de %.2f!

modules/curl_amxx.dll

425 KB
Binary file not shown.

modules/curl_amxx_i386.so

760 KB
Binary file not shown.

plugins/hl_kreedz.amxx

-497 Bytes
Binary file not shown.

plugins/hl_kreedz_discord.amxx

5.6 KB
Binary file not shown.

scripting/hl_kreedz.sma

Lines changed: 48 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -108,16 +108,6 @@ enum _:COUNTERS
108108
COUNTER_SP,
109109
}
110110

111-
enum _:STATS
112-
{
113-
STATS_ID[32],
114-
STATS_NAME[32],
115-
STATS_CP,
116-
STATS_TP,
117-
Float:STATS_TIME, // Timer value
118-
STATS_TIMESTAMP, // Date
119-
}
120-
121111
enum BUTTON_TYPE
122112
{
123113
BUTTON_START,
@@ -225,14 +215,13 @@ new g_FwLightStyle;
225215
new pcvar_sv_ag_match_running;
226216

227217
new mfwd_hlkz_cheating;
218+
new mfwd_hlkz_worldrecord;
228219

229220
new Array:g_ArrayStatsNub;
230221
new Array:g_ArrayStatsPro;
231222
new Array:g_ArrayStatsPure;
232223

233224

234-
235-
236225
public plugin_precache()
237226
{
238227
g_FwLightStyle = register_forward(FM_LightStyle, "Fw_FmLightStyle");
@@ -337,7 +326,8 @@ public plugin_init()
337326
register_touch("trigger_push", "player", "Fw_FmPlayerTouchPush");
338327
register_touch("trigger_multiple", "player", "Fw_FmPlayerTouchHealthBooster");
339328

340-
mfwd_hlkz_cheating = CreateMultiForward( "hlkz_cheating", ET_IGNORE, FP_CELL );
329+
mfwd_hlkz_cheating = CreateMultiForward("hlkz_cheating", ET_IGNORE, FP_CELL);
330+
mfwd_hlkz_worldrecord = CreateMultiForward("hlkz_worldrecord", ET_IGNORE, FP_CELL, FP_FLOAT, FP_CELL, FP_CELL);
341331

342332
register_message(get_user_msgid("Health"), "Fw_MsgHealth");
343333
register_message(SVC_TEMPENTITY, "Fw_MsgTempEntity");
@@ -1685,10 +1675,10 @@ FinishTimer(id)
16851675
{
16861676
if (get_bit(g_baIsPureRunning, id))
16871677
{
1688-
log_amx(" ----- Checking records after Pure Run end ------");
1689-
log_amx("Checking Pure top... ");
1678+
//log_amx(" ----- Checking records after Pure Run end ------");
1679+
//log_amx("Checking Pure top... ");
16901680
UpdateRecords(id, kztime, g_szTops[0]);
1691-
log_amx("Checking Pro top... ");
1681+
//log_amx("Checking Pro top... ");
16921682
UpdateRecords(id, kztime, g_szTops[1]);
16931683
}
16941684
else
@@ -2865,7 +2855,7 @@ LoadRecords(szTopType[])
28652855

28662856
new data[1024], stats[STATS], uniqueid[32], name[32], cp[24], tp[24];
28672857
new kztime[24], timestamp[24];
2868-
//new current_time = get_systime();
2858+
28692859
new Array:arr;
28702860
if (equali(szTopType, g_szTops[0]))
28712861
arr = g_ArrayStatsPure;
@@ -2886,21 +2876,13 @@ LoadRecords(szTopType[])
28862876

28872877
stats[STATS_TIMESTAMP] = str_to_num(timestamp);
28882878

2889-
/*
2890-
// Stale old records that are below specified amount, otherwise we use them to inform player about better/worse time and position
2891-
if (current_time - stats[STATS_TIMESTAMP] > staleStatTime &&
2892-
i > keepStatPlayers)
2893-
continue;
2894-
*/
2895-
28962879
copy(stats[STATS_ID], charsmax(stats[STATS_ID]), uniqueid);
28972880
copy(stats[STATS_NAME], charsmax(stats[STATS_NAME]), name);
28982881
stats[STATS_CP] = str_to_num(cp);
28992882
stats[STATS_TP] = str_to_num(tp);
29002883
stats[STATS_TIME] = _:str_to_float(kztime);
29012884

29022885
ArrayPushArray(arr, stats);
2903-
//i++;
29042886
}
29052887

29062888
fclose(file);
@@ -2952,51 +2934,65 @@ UpdateRecords(id, Float:kztime, szTopType[])
29522934
new minutes, Float:seconds, Float:slower, Float:faster;
29532935
LoadRecords(szTopType);
29542936

2955-
new Array:arr;
2937+
new Array:arr, type;
29562938
if (equali(szTopType, g_szTops[0]))
2939+
{
29572940
arr = g_ArrayStatsPure;
2941+
type = 0;
2942+
}
29582943
else if (equali(szTopType, g_szTops[1]))
2944+
{
29592945
arr = g_ArrayStatsPro;
2946+
type = 1;
2947+
}
29602948
else
2949+
{
29612950
arr = g_ArrayStatsNub;
2951+
type = 2;
2952+
}
29622953

29632954
GetUserUniqueId(id, uniqueid, charsmax(uniqueid));
29642955
GetColorlessName(id, name, charsmax(name));
29652956

2966-
new result, bool:skipResult = false;
2957+
new result;
29672958

2968-
log_amx("uniqueid = %s, name = %s", uniqueid, name);
2959+
//log_amx("uniqueid = %s, name = %s", uniqueid, name);
29692960

2970-
log_amx("-- Entering records loop. Array size: %d", ArraySize(arr));
2961+
//log_amx("-- Entering records loop. Array size: %d", ArraySize(arr));
29712962
for (new i = 0; i < ArraySize(arr); i++)
29722963
{
29732964
ArrayGetArray(arr, i, stats);
29742965
result = floatcmp(kztime, stats[STATS_TIME]);
2975-
log_amx("comparing current run's time (%.2f) to best #%d time (%.2f); result = %d", kztime, i+1, stats[STATS_TIME], result);
2966+
//log_amx("comparing current run's time (%.2f) to best #%d time (%.2f); result = %d", kztime, i+1, stats[STATS_TIME], result);
29762967

29772968
if (result == -1 && insertItemId == -1)
29782969
{
29792970
insertItemId = i;
2980-
log_amx("insertItemId = %d", insertItemId);
2971+
//log_amx("insertItemId = %d", insertItemId);
29812972
}
29822973

2983-
log_amx("comparing %s to current runner ID (%s)", stats[STATS_ID], uniqueid);
2974+
//log_amx("comparing %s to current runner ID (%s)", stats[STATS_ID], uniqueid);
29842975
if (!equal(stats[STATS_ID], uniqueid))
29852976
{
2986-
log_amx("not equal, continue finding the current runner's position...");
2977+
//log_amx("not equal, continue finding the current runner's position...");
29872978
continue;
29882979
}
2989-
log_amx("equal, this is the record that we want to check...");
2980+
//log_amx("equal, this is the record that we want to check...");
29902981

29912982
if (result != -1)
29922983
{
29932984
slower = kztime - stats[STATS_TIME];
29942985
minutes = floatround(slower, floatround_floor) / 60;
29952986
seconds = slower - (60 * minutes);
2996-
client_print(id, print_chat, GetVariableDecimalMessage(id, "[%s] You failed your %s time by %02d:%"),
2997-
PLUGIN_TAG, szTopType, minutes, seconds);
2987+
if (get_bit(g_baIsPureRunning, id))
2988+
{
2989+
client_print(id, print_chat, GetVariableDecimalMessage(id, "[%s] You failed your %s time by %02d:%"),
2990+
PLUGIN_TAG, szTopType, minutes, seconds);
2991+
}
2992+
/*
29982993
log_amx(GetVariableDecimalMessage(id, "%s failed their %s time by %02d:%", ", nothing to update here!"),
29992994
name, szTopType, minutes, seconds);
2995+
*/
30002996

30012997
return;
30022998
}
@@ -3006,20 +3002,22 @@ UpdateRecords(id, Float:kztime, szTopType[])
30063002
seconds = faster - (60 * minutes);
30073003
client_print(id, print_chat, GetVariableDecimalMessage(id, "[%s] You improved your %s time by %02d:%"),
30083004
PLUGIN_TAG, szTopType, minutes, seconds);
3005+
/*
30093006
log_amx(GetVariableDecimalMessage(id, "%s improved their %s time by %02d:%"),
30103007
name, szTopType, minutes, seconds);
3008+
*/
30113009

30123010
deleteItemId = i;
3013-
log_amx("deleteItemId = %d", deleteItemId);
3011+
//log_amx("deleteItemId = %d", deleteItemId);
30143012

30153013
break;
30163014
}
3017-
log_amx("-- Records loop finished. State of variables:");
3018-
log_amx("uniqueid = %s, name = %s", uniqueid, name);
3019-
log_amx("current run's time = %.2f", kztime);
3020-
log_amx("result = %d", result);
3021-
log_amx("insertItemId = %d", insertItemId);
3022-
log_amx("deleteItemId = %d", deleteItemId);
3015+
//log_amx("-- Records loop finished. State of variables:");
3016+
//log_amx("uniqueid = %s, name = %s", uniqueid, name);
3017+
//log_amx("current run's time = %.2f", kztime);
3018+
//log_amx("result = %d", result);
3019+
//log_amx("insertItemId = %d", insertItemId);
3020+
//log_amx("deleteItemId = %d", deleteItemId);
30233021

30243022
copy(stats[STATS_ID], charsmax(stats[STATS_ID]), uniqueid);
30253023
copy(stats[STATS_NAME], charsmax(stats[STATS_NAME]), name);
@@ -3043,7 +3041,7 @@ UpdateRecords(id, Float:kztime, szTopType[])
30433041
ArrayDeleteItem(arr, insertItemId != -1 ? deleteItemId + 1 : deleteItemId);
30443042

30453043
rank++;
3046-
log_amx("checking rank... rank = %d", rank);
3044+
//log_amx("checking rank... rank = %d", rank);
30473045
if (rank <= get_pcvar_num(pcvar_kz_top_records))
30483046
{
30493047
client_cmd(0, "spk woop");
@@ -3054,6 +3052,12 @@ UpdateRecords(id, Float:kztime, szTopType[])
30543052

30553053
SaveRecords(szTopType);
30563054

3055+
if (rank == 1)
3056+
{
3057+
new ret;
3058+
//new iArrayPass = PrepareArray(arr, ArraySize(arr));
3059+
ExecuteForward(mfwd_hlkz_worldrecord, ret, id, kztime, type, arr);
3060+
}
30573061
}
30583062

30593063
ShowTopClimbers(id, szTopType[])

scripting/hl_kreedz_discord.sma

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#include <amxmodx>
2+
#include <curl>
3+
#include <json>
4+
#include <hl_kreedz_util>
5+
6+
#define PLUGIN "HLKZ Discord WR Notifier"
7+
#define PLUGIN_TAG "HLKZ"
8+
#define VERSION "0.1.0"
9+
#define AUTHOR "naz"
10+
11+
new Handle:curl;
12+
new Handle:header;
13+
new pcvar_kz_discord_webhook;
14+
new pcvar_kz_discord_service;
15+
16+
17+
public plugin_init()
18+
{
19+
register_plugin(PLUGIN, VERSION, AUTHOR);
20+
pcvar_kz_discord_webhook = register_cvar("kz_discord_webhook", "");
21+
pcvar_kz_discord_service = register_cvar("kz_discord_service", "");
22+
23+
header = curl_create_slist();
24+
curl_slist_append(header, "Content-Type: application/json");
25+
}
26+
27+
public hlkz_worldrecord(id, Float:flTime, type, Array:arr)
28+
{
29+
if (ArraySize(arr) < 5)
30+
return;
31+
32+
static szName[32], szPostdata[640], szTime[12], szType[5], szMap[64], szWebhook[160], szURL[256];
33+
new minutes, Float:seconds, stats[STATS];
34+
new szRecDate[32], szRecTime[32];
35+
GetColorlessName(id, szName, charsmax(szName));
36+
minutes = floatround(flTime, floatround_floor) / 60;
37+
seconds = flTime - (60 * minutes);
38+
get_mapname(szMap, charsmax(szMap));
39+
get_pcvar_string(pcvar_kz_discord_webhook, szWebhook, charsmax(szWebhook));
40+
get_pcvar_string(pcvar_kz_discord_service, szURL, charsmax(szURL));
41+
42+
if (equal(szWebhook, "") || equal(szURL, ""))
43+
return;
44+
45+
switch (type)
46+
{
47+
case 0: szType = "pure";
48+
case 1: szType = "pro";
49+
case 2: szType = "noob";
50+
}
51+
formatex(szTime, charsmax(szTime), "%02d:%06.3f", minutes, seconds);
52+
53+
new JSON:root = json_init_object();
54+
json_object_set_string(root, "holder", szName);
55+
json_object_set_string(root, "time", szTime);
56+
json_object_set_string(root, "type", szType);
57+
json_object_set_string(root, "map", szMap);
58+
json_object_set_string(root, "webhook", szWebhook);
59+
60+
new JSONArray:records = json_init_array();
61+
for (new i = 0; i < 5; i++)
62+
{
63+
ArrayGetArray(arr, i, stats);
64+
65+
// TODO: Solve UTF halfcut at the end
66+
stats[STATS_NAME][17] = EOS;
67+
68+
minutes = floatround(stats[STATS_TIME], floatround_floor) / 60;
69+
seconds = stats[STATS_TIME] - (60 * minutes);
70+
71+
formatex(szRecTime, charsmax(szRecTime), "%02d:%06.3f", minutes, seconds);
72+
format_time(szRecDate, charsmax(szRecDate), "%d/%m/%Y", stats[STATS_TIMESTAMP]);
73+
74+
new JSON:record = json_init_object();
75+
json_object_set_string(record, "name", stats[STATS_NAME]);
76+
json_object_set_string(record, "time", szRecTime);
77+
json_object_set_string(record, "date", szRecDate);
78+
json_array_append_value(records, record);
79+
}
80+
json_object_set_value(root, "records", records);
81+
json_serial_to_string(root, szPostdata, charsmax(szPostdata));
82+
json_free(records);
83+
json_free(root);
84+
85+
curl = curl_init();
86+
curl_setopt_string(curl, CURLOPT_URL, szURL);
87+
curl_setopt_cell(curl, CURLOPT_FAILONERROR, 1);
88+
curl_setopt_cell(curl, CURLOPT_FOLLOWLOCATION, 0);
89+
curl_setopt_cell(curl, CURLOPT_FORBID_REUSE, 1);
90+
curl_setopt_cell(curl, CURLOPT_FRESH_CONNECT, 1);
91+
curl_setopt_cell(curl, CURLOPT_CONNECTTIMEOUT, 10);
92+
curl_setopt_cell(curl, CURLOPT_TIMEOUT, 10);
93+
curl_setopt_handle(curl, CURLOPT_HTTPHEADER, header);
94+
curl_setopt_cell(curl, CURLOPT_POST, 1);
95+
curl_setopt_string(curl, CURLOPT_POSTFIELDS, szPostdata);
96+
//curl_thread_exec(curl, "OnExecComplete");
97+
curl_thread_exec(curl, "OnExecComplete");
98+
}
99+
100+
public OnExecComplete(Handle:curl, CURLcode:code, const response[], any:eventType)
101+
{
102+
curl_close(curl);
103+
//curl_destroy_slist(header);
104+
}

0 commit comments

Comments
 (0)