Skip to content

Commit c244443

Browse files
committed
Merge branch 'develop'
Tries to fix doubled messages
2 parents a66f183 + 532ee0e commit c244443

5 files changed

Lines changed: 156 additions & 32 deletions

File tree

Modules.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# BaseChat
2+
3+
This variation of the AM plugin uses MCP to proxy it's various chat commands.
4+
This allows admin snooping, as well as player the player prefix to be applied to /say /psay and /chat.
5+
6+
#mcp-sayredirects
7+
8+
Replacement for Cider ChatProcessors AllChat and DeadChat with some bonus features.
9+
10+
`sm_sayredirect_allchat` - Redirect team chat as follows:
11+
0 - Disables this option
12+
1 - All team chat is converted to global chat
13+
2 - Team messages from team 2 are converted to global chat
14+
3 - Team messages from team 3 are converted to global chat
15+
16+
`sm_sayredirect_deadchat` - Allows alive and dead players to chat (1/0)
17+
18+
`sm_sayredirect_snoopflag` - Add staff members with the specified admin bit as recipients to MCP chat messages (Default z, empty to disable)
19+
20+
`sm_sayredirect_colorteamtag` - Set the (TEAM)-say prefix to use team color (1/0)

scripting/MetaChatProcessor.sp

Lines changed: 38 additions & 15 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 "22w26b"
27+
#define PLUGIN_VERSION "22w26c"
2828

2929
public Plugin myinfo = {
3030
name = "Meta Chat Processor",
@@ -166,8 +166,10 @@ public void OnPluginStart() {
166166

167167
UserMsg userMessage;
168168
if ((userMessage = GetUserMessageId("SayText2")) != INVALID_MESSAGE_ID) {
169-
if (g_bUseProtobuf) HookUserMessage(userMessage, OnUserMessage_SayText2Proto, true);
170-
else HookUserMessage(userMessage, OnUserMessage_SayText2BB, true);
169+
if (g_bUseProtobuf)
170+
HookUserMessage(userMessage, OnUserMessage_SayText2Proto, true);
171+
else
172+
HookUserMessage(userMessage, OnUserMessage_SayText2BB, true);
171173
//} else if ((userMessage = GetUserMessageId("SayText")) != INVALID_MESSAGE_ID) {
172174
//SCP only supported dods? maybe add that if people ask for it
173175
} else {
@@ -221,6 +223,7 @@ public Action OnUserMessage_SayText2Proto(UserMsg msg_id, BfRead msg, const int[
221223
// copy as initial display name
222224
strcopy(g_currentMessage.sender_display, sizeof(MessageData::sender_display), g_currentMessage.sender_name);
223225

226+
g_currentMessage.listRecipients.Clear();
224227
for (int reci=0;reci<playersNum;reci++) {
225228
g_currentMessage.listRecipients.Push(players[reci]);
226229
}
@@ -247,6 +250,7 @@ public Action OnUserMessage_SayText2BB(UserMsg msg_id, BfRead msg, const int[] p
247250
// copy as initial display name
248251
strcopy(g_currentMessage.sender_display, sizeof(MessageData::sender_display), g_currentMessage.sender_name);
249252

253+
g_currentMessage.listRecipients.Clear();
250254
for (int reci=0;reci<playersNum;reci++) {
251255
g_currentMessage.listRecipients.Push(players[reci]);
252256
}
@@ -258,7 +262,7 @@ public Action OnUserMessage_SayText2BB(UserMsg msg_id, BfRead msg, const int[] p
258262
Action ProcessSayText2() {
259263
Action result;
260264
g_currentMessage.valid = true;
261-
#define THEN_CANCEL { g_currentMessage.valid = true; return Plugin_Handled; }
265+
#define THEN_CANCEL { g_currentMessage.valid = false; return Plugin_Handled; }
262266

263267
//this is some basic chat sanitizing. should we do this as chat processor?
264268
// i think most server operators wont event know this can be an issue, and
@@ -282,7 +286,8 @@ Action ProcessSayText2() {
282286
BanClient(g_currentMessage.sender, 0, BANFLAG_AUTHID|BANFLAG_AUTO, "Hacked Client: Invalid characters in chat input (line breaks)", "Hacked client detected", "say", g_currentMessage.sender);
283287
return Plugin_Handled;
284288
}
285-
if (TrimStringMB(tmp) && tmp[0]==0) THEN_CANCEL //message is empty or a "break chat" message
289+
TrimStringMB(tmp);
290+
if (tmp[0]==0) THEN_CANCEL //message is empty or a "break chat" message
286291
if (g_sanitizeInput & mcpInputTrimMBSpace) strcopy(g_currentMessage.message, sizeof(MessageData::message), tmp);
287292
}
288293

@@ -312,31 +317,49 @@ Action ProcessSayText2() {
312317

313318
result = g_currentMessage.changed ? Plugin_Handled : Plugin_Continue;
314319
//send of to next frame as we can't create another user message within this hook
315-
g_processedMessages.PushArray(g_currentMessage);
316-
g_currentMessage.Reset(.newRecipientsInstace = true); //because we pushed the list handle, sets valid false
320+
for (int rec=g_currentMessage.listRecipients.Length-1;rec>=0;rec--) {
321+
//map client ids to user-ids since we are about to cross tick boundary
322+
int recipient = g_currentMessage.listRecipients.Get(rec);
323+
if (!recipient) continue;
324+
g_currentMessage.listRecipients.Set(rec, GetClientUserId( recipient ));
325+
}
326+
g_processedMessages.PushArray(g_currentMessage); //push with .valid = true
327+
g_currentMessage.Reset(.newRecipientsInstace = true); //because we pushed the list handle, sets .valid false
317328

318329
#undef THEN_CANCEL
319330
return result;
320331
}
321332
//continuation
322333
public void OnGameFrame() {
323-
for (int index; index < g_processedMessages.Length; index++) {
334+
while (g_processedMessages.Length > 0) {
324335
// pop message
325336
//delete the previous handle, we will fetch an old one from the list
326337
delete g_currentMessage.listRecipients;
327-
g_processedMessages.GetArray(index, g_currentMessage);
328-
g_processedMessages.Erase(index);
338+
g_processedMessages.GetArray(0, g_currentMessage);
339+
g_processedMessages.Erase(0);
340+
//re-map recipients from uids to clients
341+
for (int i=g_currentMessage.listRecipients.Length-1; i>=0; i-=1) {
342+
int recipient = g_currentMessage.listRecipients.Get(i);
343+
if (!recipient) continue; //don't touch server recipient, that's always 0
344+
recipient = GetClientOfUserId(recipient); // validate
345+
if (recipient) g_currentMessage.listRecipients.Set(i, recipient);
346+
else g_currentMessage.listRecipients.Erase(i);
347+
}
329348

330349
// process message
331350
//if this failes we hopefully threw an error and will continue processing
332351
//other messages in the next game tick, as this one was already dequeued
333-
g_currentMessage.valid = true;
334-
if (g_currentMessage.changed) ResendChatMessage();
335-
Call_OnChatMessagePost();
336-
g_currentMessage.valid = false;
352+
if (g_currentMessage.valid) {
353+
if (g_currentMessage.changed) ResendChatMessage();
354+
Call_OnChatMessagePost();
355+
} else {
356+
LogError("Pushed or didnt clear invalid message! %N : %s", g_currentMessage.sender, g_currentMessage.message);
357+
}
337358
}
338359
//we still have an old recipients list here that wasn't deleted. this instance
339360
//will be cleared and reused by the next SayText2 hook
361+
//until then, the message structure is invalid tho
362+
g_currentMessage.valid = false;
340363
}
341364

342365
static void ResendChatMessage() {
@@ -350,7 +373,7 @@ static void ResendChatMessage() {
350373
bool chatFlag = !(g_currentMessage.options & mcpMsgNoConsoleCopy);
351374

352375
int recipientCount = g_currentMessage.listRecipients.Length;
353-
for (int i; i < recipientCount; i++) {
376+
for (int i; i < recipientCount; i+=1) {
354377
int recipient = g_currentMessage.listRecipients.Get(i);
355378
if (!recipient) continue;
356379

scripting/MetaChatProcessor/pluginapi.sp

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ public void pluginAPI_register() {
4747
mcp_cider_init();
4848

4949
CreateNative("MCP_HookChatMessage", Native_HookChatMessage);
50+
CreateNative("MCP_UnhookChatMessage", Native_UnhookChatMessage);
51+
CreateNative("MCP_UnhookAllChatMessages", Native_UnhookAllChatMessage);
5052
CreateNative("MCP_RegisterSenderFlag", Native_RegisterSenderFlag);
5153
CreateNative("MCP_RegisterTargetGroup", Native_RegisterTargetGroup);
5254
CreateNative("MCP_UnregisterSenderFlags", Native_UnregisterSenderFlag);
@@ -136,16 +138,18 @@ static void ValidateAfterCall(const char[] stage, int error, Action& returnedAct
136138
LogError("MCP_OnChatMessage%s cleard the recipients list instead of cancelling - As PluginDev, Please reconsider", stage);
137139
}
138140
returnedAction = Plugin_Stop;
139-
} else { //remove doubles
140-
g_currentMessage.listRecipients.Sort(Sort_Ascending, Sort_Integer);
141-
for (int i = g_currentMessage.listRecipients.Length-1; i > 0; i -= 1) {
142-
if (g_currentMessage.listRecipients.Get(i) == g_currentMessage.listRecipients.Get(i-1))
143-
g_currentMessage.listRecipients.Erase(i);
144-
}
145141
}
142+
//remove doubled recipients
143+
g_currentMessage.listRecipients.Sort(Sort_Ascending, Sort_Integer);
144+
for (int i = g_currentMessage.listRecipients.Length-1; i > 0; i -= 1) {
145+
if (g_currentMessage.listRecipients.Get(i) == g_currentMessage.listRecipients.Get(i-1))
146+
g_currentMessage.listRecipients.Erase(i);
147+
}
148+
//check error code
146149
if (error != SP_ERROR_NONE) {
147150
ThrowError("MCP_OnChatMessage%s failed with error code %i", stage, error);
148151
}
152+
//rebuild message format string if required
149153
if (returnedAction == Plugin_Changed && rebuildMessageFormat)
150154
BuildMessageFormat(g_currentMessage.senderflags, g_currentMessage.group, g_currentMessage.msg_name, sizeof(MessageData::msg_name));
151155

@@ -303,6 +307,44 @@ public int Native_HookChatMessage(Handle plugin, int numParams) {
303307
default: ThrowNativeError(SP_ERROR_PARAM, "Invalid hook type");
304308
}
305309
}
310+
public int Native_UnhookChatMessage(Handle plugin, int numParams) {
311+
Function fun = GetNativeFunction(1);
312+
if (fun == INVALID_FUNCTION) {
313+
switch (GetNativeCell(2)) {
314+
case 0: g_fwdOnMessagePre.RemoveAllFunctions(plugin);
315+
case 1: g_fwdOnMessage_Early.RemoveAllFunctions(plugin);
316+
case 2: g_fwdOnMessage_Normal.RemoveAllFunctions(plugin);
317+
case 3: g_fwdOnMessage_Late.RemoveAllFunctions(plugin);
318+
case 4: g_fwdOnMessageColors.RemoveAllFunctions(plugin);
319+
case 5: g_fwdOnMessageGroupName.RemoveAllFunctions(plugin);
320+
case 6: g_fwdOnMessageFormatted.RemoveAllFunctions(plugin);
321+
case 7: g_fwdOnMessagePost.RemoveAllFunctions(plugin);
322+
default: ThrowNativeError(SP_ERROR_PARAM, "Invalid hook type");
323+
}
324+
} else {
325+
switch (GetNativeCell(2)) {
326+
case 0: g_fwdOnMessagePre.RemoveFunction(plugin, fun);
327+
case 1: g_fwdOnMessage_Early.RemoveFunction(plugin, fun);
328+
case 2: g_fwdOnMessage_Normal.RemoveFunction(plugin, fun);
329+
case 3: g_fwdOnMessage_Late.RemoveFunction(plugin, fun);
330+
case 4: g_fwdOnMessageColors.RemoveFunction(plugin, fun);
331+
case 5: g_fwdOnMessageGroupName.RemoveFunction(plugin, fun);
332+
case 6: g_fwdOnMessageFormatted.RemoveFunction(plugin, fun);
333+
case 7: g_fwdOnMessagePost.RemoveFunction(plugin, fun);
334+
default: ThrowNativeError(SP_ERROR_PARAM, "Invalid hook type");
335+
}
336+
}
337+
}
338+
public int Native_UnhookAllChatMessage(Handle plugin, int numParams) {
339+
g_fwdOnMessagePre.RemoveAllFunctions(plugin);
340+
g_fwdOnMessage_Early.RemoveAllFunctions(plugin);
341+
g_fwdOnMessage_Normal.RemoveAllFunctions(plugin);
342+
g_fwdOnMessage_Late.RemoveAllFunctions(plugin);
343+
g_fwdOnMessageColors.RemoveAllFunctions(plugin);
344+
g_fwdOnMessageGroupName.RemoveAllFunctions(plugin);
345+
g_fwdOnMessageFormatted.RemoveAllFunctions(plugin);
346+
g_fwdOnMessagePost.RemoveAllFunctions(plugin);
347+
}
306348

307349
public int Native_RegisterSenderFlag(Handle plugin, int numParams) {
308350
char phrase[64];

scripting/include/metachatprocessor.inc

Lines changed: 18 additions & 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 222601
4+
#define _mcp_included 222603
55
//yywwrr: y year, w week in year, r revision in week
66

77
#include <metachatprocessor/types>
@@ -15,6 +15,23 @@
1515
*/
1616
native void MCP_HookChatMessage(ChatMessageCallback callback, mcpHookType type=mcpHookDefault);
1717

18+
/**
19+
* Remove a message callback from MCP. If you pass INVALID_FUNCTION it will unhook all callbacks for the specified type.
20+
*
21+
* @param callback - the function to remove OR INVLID_FUNCTION to remove all
22+
* @param type - what type the callback was added to
23+
* @noreturn
24+
*/
25+
native void MCP_UnhookChatMessage(ChatMessageCallback callback=INVALID_FUNCTION, mcpHookType type=mcpHookDefault);
26+
27+
/**
28+
* Completely removes all hooks you added. If you wanna be extra sure, you can put this in OnPluginEnd, but normally
29+
* this shouldn't be required.
30+
*
31+
* @noreturn
32+
*/
33+
native void MCP_UnhookAllChatMessages();
34+
1835
/**
1936
* Add a translation phrase for a custom sender flag prefix.
2037
* You can OR the return value to senderflags to add the prefix in ** before a chat message.

scripting/mcp-sayredirects.sp

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,27 +20,39 @@ AdminFlag g_SnoopFlag;
2020
bool g_SnoopingEnabled;
2121
int g_AllChatMode;
2222
bool g_DeadChat;
23+
bool g_TeamTagColor;
24+
25+
static void HookAndLoadConVar(ConVar convar, ConVarChanged hook) {
26+
//I sometimes hate convars...
27+
// You need to manually read the value after the convars are set up, as that will not trigger a change!
28+
// This wrapper will invoke the change handler manually before hooking the convar, so the currrent value is always processed
29+
char value[4]; //too small for general use!
30+
convar.GetString(value, sizeof(value));
31+
Call_StartFunction(INVALID_HANDLE, hook);
32+
Call_PushCell(convar);
33+
Call_PushString("");
34+
Call_PushString(value);
35+
Call_Finish();
36+
convar.AddChangeHook(hook);
37+
}
2338

2439
public void OnPluginStart() {
2540
ConVar cvar1 = CreateConVar("sm_sayredirect_snoopflag", "z", "AdminFlag that shall be able to snoop chat messages, empty to disable");
26-
cvar1.AddChangeHook(OnConVarChanged_SnoopFlag);
2741
ConVar cvar2 = CreateConVar("sm_sayredirect_allchat", "0", "Redirect team chat as follows: 0-Don't change; 1-Always to all; 2-Team 2 chat to all; 3-Team 3 chat to all", _, true, 0.0, true, 3.0);
28-
cvar2.AddChangeHook(OnConVarChanged_AllChat);
2942
ConVar cvar3 = CreateConVar("sm_sayredirect_deadchat", "0", "Send messages from dead players to alive players", _, true, 0.0, true, 1.0);
30-
cvar3.AddChangeHook(OnConVarChanged_DeadChat);
31-
AutoExecConfig();
43+
ConVar cvar4 = CreateConVar("sm_sayredirect_colorteamtag", "0", "Color the (TEAM) tag for say_team in team color", _, true, 0.0, true, 1.0);
44+
AutoExecConfig(); //gen/load config
45+
HookAndLoadConVar(cvar1,OnConVarChanged_SnoopFlag);
46+
HookAndLoadConVar(cvar2,OnConVarChanged_AllChat);
47+
HookAndLoadConVar(cvar3,OnConVarChanged_DeadChat);
48+
HookAndLoadConVar(cvar4,OnConVarChanged_TeamTagColor);
3249
delete cvar1;
3350
delete cvar2;
3451
delete cvar3;
52+
delete cvar4;
3553
}
3654

3755
public void OnAllPluginsLoaded() {
38-
if (LibraryExists("MetaChatProcessor")) HookMessages();
39-
}
40-
public void OnLibraryAdded(const char[] name) {
41-
if (StrEqual(name,"MetaChatProcessor")) HookMessages();
42-
}
43-
void HookMessages() {
4456
MCP_HookChatMessage(OnMessage_Redirect, mcpHookPre);
4557
MCP_HookChatMessage(OnMessage_Snoop, mcpHookLate);
4658
}
@@ -54,6 +66,9 @@ public void OnConVarChanged_AllChat(ConVar convar, const char[] oldValue, const
5466
public void OnConVarChanged_DeadChat(ConVar convar, const char[] oldValue, const char[] newValue) {
5567
g_DeadChat = convar.BoolValue;
5668
}
69+
public void OnConVarChanged_TeamTagColor(ConVar convar, const char[] oldValue, const char[] newValue) {
70+
g_TeamTagColor = convar.BoolValue;
71+
}
5772

5873
public Action OnMessage_Redirect(int& sender, ArrayList recipients, mcpSenderFlag& senderflags, mcpTargetGroup& targetgroup, mcpMessageOption& options, char[] targetgroupColor) {
5974
bool isTeamSay = mcpTargetTeam1 <= targetgroup <= mcpTargetTeamSender;
@@ -64,9 +79,16 @@ public Action OnMessage_Redirect(int& sender, ArrayList recipients, mcpSenderFla
6479
bool checkTeam = isTeamSay;
6580
if (isTeamSay && (g_AllChatMode==1||(g_AllChatMode>1 && g_AllChatMode==fromTeam))) {
6681
targetgroup = mcpTargetNone; //remove (TEAM) grouptag
82+
isTeamSay = false;
6783
checkTeam = false; //add any team
6884
}
6985

86+
//i like if the TEAM tag is team colored
87+
if (isTeamSay && g_TeamTagColor) {
88+
options |= mcpMsgGrouptagColor;
89+
strcopy(targetgroupColor, MCP_MAXLENGTH_COLORTAG, "\x03");
90+
}
91+
7092
//if we do dead chat and the sender is dead, add all alive players
7193
//otherwise, if we drop teamcheck we need to add other teams alive players
7294
bool addAlive = !checkTeam || (isDeadChat && g_DeadChat);

0 commit comments

Comments
 (0)