Skip to content

Commit 4a4283c

Browse files
committed
Added CommandListener hook method
1 parent c244443 commit 4a4283c

4 files changed

Lines changed: 102 additions & 16 deletions

File tree

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,19 @@ The config can be found at `addons/sourcemod/config/metachatprocessor.cfg`:
5454
"HexTags" "1"
5555
"Fix Post Calls" "0"
5656
}
57+
// Transport defines the message channel/type. You should probably keep it at SayText.
58+
// Possible values: [ PrintToChat , SayText ]
5759
"Transport" "SayText"
60+
// HookMode defines how messages are cought. Command listener is experimental and might not block the original message correctly in all cases.
61+
// Possible values: [ Command , UserMessage ]
62+
"HookMode" "UserMessage"
5863
"Input Sanitizer"
5964
{
65+
// Trim messages of "space" codepoints (utf8 support) ?
6066
"Trim All Whitespaces" 1
67+
// get rid of hackers
6168
"Ban On NewLine" 1
69+
// clients are not allowed to use \x01..\x08 colors
6270
"Strip Native Colorcodes" 1
6371
}
6472
}

scripting/MetaChatProcessor.sp

Lines changed: 80 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
#pragma semicolon 1
2525
#pragma newdecls required
2626

27-
#define PLUGIN_VERSION "22w26c"
27+
#define PLUGIN_VERSION "22w34a"
2828

2929
public Plugin myinfo = {
3030
name = "Meta Chat Processor",
@@ -63,6 +63,11 @@ enum mcpTransportMethod (+=1) {
6363
mcpTransport_PrintToChat, //on drixevels discussion thread unf404 seemd to like this more, will probably break chat filters tho
6464
}
6565
mcpTransportMethod g_messageTransport = mcpTransport_SayText; //how to send message
66+
enum mcpMessageHookMethod (+=1) {
67+
mcpHook_UserMessage,
68+
mcpHook_CommandListener
69+
}
70+
mcpMessageHookMethod g_hookMethod = mcpHook_UserMessage; //how to hook messages
6671
bool g_fixCompatPostCalls = true; //always call OnChatMessagePost for scp?
6772
enum mcpInputSanity (<<=1) {
6873
mcpInputUnchecked = 0,
@@ -161,20 +166,36 @@ public void OnPluginStart() {
161166
g_bUseProtobuf = (CanTestFeatures() && GetFeatureStatus(FeatureType_Native, "GetUserMessageType") == FeatureStatus_Available && GetUserMessageType() == UM_Protobuf);
162167
g_processedMessages = new ArrayList(sizeof(MessageData));
163168

164-
ParseConfigs();
169+
LoadDataFiles();
165170
pluginAPI_init();
166171

167-
UserMsg userMessage;
168-
if ((userMessage = GetUserMessageId("SayText2")) != INVALID_MESSAGE_ID) {
169-
if (g_bUseProtobuf)
170-
HookUserMessage(userMessage, OnUserMessage_SayText2Proto, true);
171-
else
172-
HookUserMessage(userMessage, OnUserMessage_SayText2BB, true);
173-
//} else if ((userMessage = GetUserMessageId("SayText")) != INVALID_MESSAGE_ID) {
174-
//SCP only supported dods? maybe add that if people ask for it
175-
} else {
176-
LogError("Could not hook chat messages for this game - UserMessage SayText2 invalid");
177-
SetFailState("This game is currently not supported");
172+
switch (g_hookMethod) {
173+
case mcpHook_UserMessage: {
174+
UserMsg userMessage;
175+
if ((userMessage = GetUserMessageId("SayText2")) != INVALID_MESSAGE_ID) {
176+
if (g_bUseProtobuf)
177+
HookUserMessage(userMessage, OnUserMessage_SayText2Proto, true);
178+
else
179+
HookUserMessage(userMessage, OnUserMessage_SayText2BB, true);
180+
//} else if ((userMessage = GetUserMessageId("SayText")) != INVALID_MESSAGE_ID) {
181+
//SCP only supported dods? maybe add that if people ask for it
182+
} else {
183+
LogError("Could not hook chat messages for this game - UserMessage SayText2 invalid");
184+
SetFailState("This game is currently not supported, you might try switching hook mode");
185+
}
186+
}
187+
case mcpHook_CommandListener: {
188+
if (!CommandExists("say") || !CommandExists("say_team")) {
189+
LogError("Could not hook chat messages for this game - Commands do not exist");
190+
SetFailState("This game is currently not supported, you might try switching hook mode");
191+
} else if (!AddCommandListener(OnCommand_SayCommand, "say") || !AddCommandListener(OnCommand_SayCommand, "say_team")) {
192+
LogError("Could not hook chat messages for this game - Command hooks not available");
193+
SetFailState("This game is currently not supported, you might try switching hook mode");
194+
}
195+
}
196+
default: {
197+
SetFailState("Invalid value for g_hookMethod");
198+
}
178199
}
179200

180201
ConVar version = CreateConVar("mcp_version", PLUGIN_VERSION, "MetaChatProcessor Version", FCVAR_DONTRECORD|FCVAR_NOTIFY);
@@ -259,6 +280,52 @@ public Action OnUserMessage_SayText2BB(UserMsg msg_id, BfRead msg, const int[] p
259280
return ProcessSayText2();
260281
}
261282

283+
public Action OnCommand_SayCommand(int client, const char[] command, int argc) {
284+
if (!client || !IsClientInGame(client)) return Plugin_Continue;
285+
bool teamSay = StrEqual(command, "say_team");
286+
int team = GetClientTeam(client);
287+
288+
// collect basic message options
289+
g_currentMessage.Reset();
290+
g_currentMessage.sender = client;
291+
g_currentMessage.options = mcpMsgDefault;
292+
if (g_sanitizeInput & mcpInputStripColors) g_currentMessage.options |= mcpMsgRemoveColors;
293+
294+
// generate sender flags
295+
if (team == 1) g_currentMessage.senderflags = mcpSenderSpectator;
296+
else if (!IsPlayerAlive(client)) g_currentMessage.senderflags = mcpSenderDead;
297+
else g_currentMessage.senderflags = mcpSenderNone;
298+
// generate target group
299+
if (team == 1) g_currentMessage.group = mcpTargetSpecator;
300+
else if (team && teamSay) {
301+
if (g_msgNameTagCount) g_currentMessage.group = view_as<mcpTargetGroup>(team);
302+
else g_currentMessage.group = mcpTargetTeamSender;
303+
}
304+
else g_currentMessage.group = mcpTargetNone;
305+
306+
// build message format string mock
307+
BuildMessageFormat(g_currentMessage.senderflags, g_currentMessage.group, g_currentMessage.msg_name, sizeof(MessageData::msg_name));
308+
// fetch name and message
309+
GetClientName(client, g_currentMessage.sender_name, sizeof(MessageData::sender_name));
310+
GetCmdArgString(g_currentMessage.message, 128); //this uses the max length of the chat box, no cheating with console
311+
312+
// replace all control characters with a question mark. not possible through steam, but hacker can do
313+
int len = strlen(g_currentMessage.sender_name);
314+
for (int pos; pos<len; pos++) if (g_currentMessage.sender_name[pos] < 0x32) g_currentMessage.sender_name[pos]='?';
315+
// copy as initial display name
316+
strcopy(g_currentMessage.sender_display, sizeof(MessageData::sender_display), g_currentMessage.sender_name);
317+
318+
// collect recipients
319+
g_currentMessage.listRecipients.Clear();
320+
for (int target=1; target<=MaxClients; target++) {
321+
if (!IsClientInGame(target) || IsFakeClient(target)) continue;
322+
if (teamSay && GetClientTeam(target) != team) continue;
323+
g_currentMessage.listRecipients.Push(target);
324+
}
325+
326+
return ProcessSayText2(); //can be reused for command hook
327+
}
328+
262329
Action ProcessSayText2() {
263330
Action result;
264331
g_currentMessage.valid = true;

scripting/MetaChatProcessor/utilities.sp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#endif
88

99

10-
void ParseConfigs() {
10+
void LoadDataFiles() {
1111
GameData gameData = new GameData("metachatprocessor.games");
1212
if (gameData == INVALID_HANDLE) SetFailState("Could not load gamedata file");
1313
char buffer[64];
@@ -90,13 +90,24 @@ void LoadCompatConfig() {
9090
LogError("[MCP] WARNING: Transport method '%s' not supported, using SayText instead", part);
9191
}
9292
} else LogError("[MCP] WARNING: Transport method not set, using SayText instead", part);
93+
//hook method
94+
if (kv.GetDataType("HookMode")==KvData_String) {
95+
kv.GetString("HookMode", part, sizeof(part), "UserMessage");
96+
if (StrEqual(part, "Command", false)) {
97+
g_hookMethod = mcpHook_CommandListener;
98+
} else if (StrEqual(part, "UserMessage", false)) {
99+
g_hookMethod = mcpHook_UserMessage;
100+
} else {
101+
LogError("[MCP] WARNING: HookMode method '%s' not supported, using UserMessage instead", part);
102+
}
103+
} else LogError("[MCP] WARNING: HookMode method not set, using UserMessage instead", part);
93104
delete kv;
94105
}
95106

96107
static void GenerateDefaultConfig(KeyValues kv, const char[] path) {
97108
kv.ImportFromString("config { "...
98109
"Compatibility { \"SCP Redux\" 1 Drixevel 1 Cider 1 \"Custom-ChatColors\" 0 HexTags 0 \"Fix Post Calls\" 0 } "...
99-
"Transport SayText "...
110+
"Transport SayText HookMode UserMessage "...
100111
"\"Input Sanitizer\" { \"Trim All Whitespaces\" 1 \"Ban On NewLine\" 1 \"Strip Native Colorcodes\" 1 } "...
101112
"}");
102113
kv.ExportToFile(path);

scripting/include/metachatprocessor.inc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#if defined _mcp_included
22
#endinput
33
#endif
4-
#define _mcp_included 222603
4+
#define _mcp_included 223401
55
//yywwrr: y year, w week in year, r revision in week
66

77
#include <metachatprocessor/types>

0 commit comments

Comments
 (0)