Allow setting multiple chat trigger characters (PR #449, bug 4341, bug 5668)

Special characters only, minus a couple of potentially-problematic characters.

Technically this is a breaking change - but anyone using multi-char triggers is probably crazy anyway and has been driven off by now.
This commit is contained in:
Asher Baker 2016-10-04 16:34:42 +01:00 committed by GitHub
parent 098a693c1a
commit ec7f1727e5
3 changed files with 56 additions and 27 deletions

View File

@ -30,12 +30,12 @@
"ServerLang" "en" "ServerLang" "en"
/** /**
* String to use as the public chat trigger. Set an empty string to disable. * List of characters to use for public chat triggers. Set an empty list to disable.
*/ */
"PublicChatTrigger" "!" "PublicChatTrigger" "!"
/** /**
* String to use as the silent chat trigger. Set an empty string to disable. * List of characters to use for silent chat triggers. Set an empty list to disable.
*/ */
"SilentChatTrigger" "/" "SilentChatTrigger" "/"

View File

@ -8,7 +8,7 @@
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the * the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation. * Free Software Foundation.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * 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 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
@ -38,12 +38,13 @@
#include "logic_bridge.h" #include "logic_bridge.h"
#include "sourcemod.h" #include "sourcemod.h"
#include "provider.h" #include "provider.h"
#include <bridge/include/ILogger.h>
#include <amtl/am-string.h> #include <amtl/am-string.h>
ChatTriggers g_ChatTriggers; ChatTriggers g_ChatTriggers;
bool g_bSupressSilentFails = false; bool g_bSupressSilentFails = false;
ChatTriggers::ChatTriggers() : m_bWillProcessInPost(false), ChatTriggers::ChatTriggers() : m_bWillProcessInPost(false),
m_ReplyTo(SM_REPLY_CONSOLE), m_ArgSBackup(NULL) m_ReplyTo(SM_REPLY_CONSOLE), m_ArgSBackup(NULL)
{ {
m_PubTrigger = "!"; m_PubTrigger = "!";
@ -61,20 +62,43 @@ ChatTriggers::~ChatTriggers()
m_ArgSBackup = NULL; m_ArgSBackup = NULL;
} }
ConfigResult ChatTriggers::OnSourceModConfigChanged(const char *key, void ChatTriggers::SetChatTrigger(ChatTriggerType type, const char *value)
const char *value, {
ke::AutoPtr<char[]> filtered(new char[strlen(value) + 1]);
const char *src = value;
char *dest = filtered.get();
char c;
while ((c = *src++) != '\0') {
if (c <= ' ' || c == '"' || c == '\'' || (c >= '0' && c <= '9') || c == ';' || (c >= 'A' && c <= 'Z') || c == '\\' || (c >= 'a' && c <= 'z') || c >= 0x7F) {
logger->LogError("Ignoring %s chat trigger character '%c', not in valid set: %s", (type == ChatTrigger_Private ? "silent" : "public"), c, "!#$%&()*+,-./:<=>?@[]^_`{|}~");
continue;
}
*dest++ = c;
}
*dest = '\0';
if (type == ChatTrigger_Private) {
m_PrivTrigger = filtered.get();
} else {
m_PubTrigger = filtered.get();
}
}
ConfigResult ChatTriggers::OnSourceModConfigChanged(const char *key,
const char *value,
ConfigSource source, ConfigSource source,
char *error, char *error,
size_t maxlength) size_t maxlength)
{ {
if (strcmp(key, "PublicChatTrigger") == 0) if (strcmp(key, "PublicChatTrigger") == 0)
{ {
m_PubTrigger = value; SetChatTrigger(ChatTrigger_Public, value);
return ConfigResult_Accept; return ConfigResult_Accept;
} }
else if (strcmp(key, "SilentChatTrigger") == 0) else if (strcmp(key, "SilentChatTrigger") == 0)
{ {
m_PrivTrigger = value; SetChatTrigger(ChatTrigger_Private, value);
return ConfigResult_Accept; return ConfigResult_Accept;
} }
else if (strcmp(key, "SilentFailSuppress") == 0) else if (strcmp(key, "SilentFailSuppress") == 0)
@ -156,7 +180,7 @@ bool ChatTriggers::OnSayCommand_Pre(int client, const ICommandArgs *command)
if (!args) if (!args)
return false; return false;
/* Save these off for post hook as the command data returned from the engine in older engine versions /* Save these off for post hook as the command data returned from the engine in older engine versions
* can be NULL, despite the data still being there and valid. */ * can be NULL, despite the data still being there and valid. */
m_Arg0Backup = command->Arg(0); m_Arg0Backup = command->Arg(0);
size_t len = strlen(args); size_t len = strlen(args);
@ -182,7 +206,7 @@ bool ChatTriggers::OnSayCommand_Pre(int client, const ICommandArgs *command)
if ( if (
#if SOURCE_ENGINE == SE_EPISODEONE #if SOURCE_ENGINE == SE_EPISODEONE
!m_bIsINS && !m_bIsINS &&
#endif #endif
client != 0 && args[0] == '"' && args[len-1] == '"') client != 0 && args[0] == '"' && args[len-1] == '"')
{ {
@ -250,17 +274,17 @@ bool ChatTriggers::OnSayCommand_Pre(int client, const ICommandArgs *command)
bool is_trigger = false; bool is_trigger = false;
bool is_silent = false; bool is_silent = false;
/* Check for either trigger */ // Prefer the silent trigger in case of clashes.
if (m_PubTrigger.length() && strncmp(m_ArgSBackup, m_PubTrigger.chars(), m_PubTrigger.length()) == 0) if (strchr(m_PrivTrigger.chars(), m_ArgSBackup[0])) {
{
is_trigger = true;
args = &m_ArgSBackup[m_PubTrigger.length()];
}
else if (m_PrivTrigger.length() && strncmp(m_ArgSBackup, m_PrivTrigger.chars(), m_PrivTrigger.length()) == 0)
{
is_trigger = true; is_trigger = true;
is_silent = true; is_silent = true;
args = &m_ArgSBackup[m_PrivTrigger.length()]; } else if (strchr(m_PubTrigger.chars(), m_ArgSBackup[0])) {
is_trigger = true;
}
if (is_trigger) {
// Bump the args past the chat trigger - we only support single-character triggers now.
args = &m_ArgSBackup[1];
} }
/** /**
@ -318,8 +342,8 @@ bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args)
char cmd_buf[64]; char cmd_buf[64];
size_t cmd_len = 0; size_t cmd_len = 0;
const char *inptr = args; const char *inptr = args;
while (*inptr != '\0' while (*inptr != '\0'
&& !textparsers->IsWhitespace(inptr) && !textparsers->IsWhitespace(inptr)
&& *inptr != '"' && *inptr != '"'
&& cmd_len < sizeof(cmd_buf) - 1) && cmd_len < sizeof(cmd_buf) - 1)
{ {
@ -342,7 +366,7 @@ bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args)
return false; return false;
} }
/* Now, prepend. Don't worry about the buffers. This will /* Now, prepend. Don't worry about the buffers. This will
* work because the sizes are limited from earlier. * work because the sizes are limited from earlier.
*/ */
char new_buf[80]; char new_buf[80];

View File

@ -8,7 +8,7 @@
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the * the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation. * Free Software Foundation.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * 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 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
@ -50,10 +50,10 @@ public: //SMGlobalClass
void OnSourceModAllInitialized_Post(); void OnSourceModAllInitialized_Post();
void OnSourceModGameInitialized(); void OnSourceModGameInitialized();
void OnSourceModShutdown(); void OnSourceModShutdown();
ConfigResult OnSourceModConfigChanged(const char *key, ConfigResult OnSourceModConfigChanged(const char *key,
const char *value, const char *value,
ConfigSource source, ConfigSource source,
char *error, char *error,
size_t maxlength); size_t maxlength);
private: //ConCommand private: //ConCommand
bool OnSayCommand_Pre(int client, const ICommandArgs *args); bool OnSayCommand_Pre(int client, const ICommandArgs *args);
@ -64,6 +64,11 @@ public:
bool IsChatTrigger(); bool IsChatTrigger();
bool WasFloodedMessage(); bool WasFloodedMessage();
private: private:
enum ChatTriggerType {
ChatTrigger_Public,
ChatTrigger_Private,
};
void SetChatTrigger(ChatTriggerType type, const char *value);
bool PreProcessTrigger(edict_t *pEdict, const char *args); bool PreProcessTrigger(edict_t *pEdict, const char *args);
bool ClientIsFlooding(int client); bool ClientIsFlooding(int client);
cell_t CallOnClientSayCommand(int client); cell_t CallOnClientSayCommand(int client);