reworked antiflood. it now has some logic in core to take care of loading order nastiness, and to fully prevent trigger spamming

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401931
This commit is contained in:
David Anderson
2008-03-12 03:33:52 +00:00
parent b10bf9d31a
commit aed775162c
7 changed files with 219 additions and 52 deletions
+86 -1
View File
@@ -34,6 +34,8 @@
#include "sm_stringutil.h"
#include "ConCmdManager.h"
#include "PlayerManager.h"
#include "Translator.h"
#include "HalfLife2.h"
/* :HACKHACK: We can't SH_DECL here because ConCmdManager.cpp does.
* While the OB build only runs on MM:S 1.6.0+ (SH 5+), the older one
@@ -55,6 +57,7 @@ extern bool __SourceHook_FHAddConCommandDispatch(void *, bool, class fastdelegat
ChatTriggers g_ChatTriggers;
bool g_bSupressSilentFails = false;
CPhraseFile *g_pFloodPhrases = NULL;
ChatTriggers::ChatTriggers() : m_pSayCmd(NULL), m_bWillProcessInPost(false),
m_bTriggerWasSilent(false), m_ReplyTo(SM_REPLY_CONSOLE)
@@ -103,6 +106,20 @@ ConfigResult ChatTriggers::OnSourceModConfigChanged(const char *key,
return ConfigResult_Ignore;
}
void ChatTriggers::OnSourceModAllInitialized()
{
m_pShouldFloodBlock = g_Forwards.CreateForward("OnClientFloodCheck", ET_Event, 1, NULL, Param_Cell);
m_pDidFloodBlock = g_Forwards.CreateForward("OnClientFloodResult", ET_Event, 2, NULL, Param_Cell, Param_Cell);
}
void ChatTriggers::OnSourceModAllInitialized_Post()
{
unsigned int file_id;
file_id = g_Translator.FindOrAddPhraseFile("antiflood.phrases.txt");
g_pFloodPhrases = g_Translator.GetFileByIndex(file_id);
}
void ChatTriggers::OnSourceModGameInitialized()
{
unsigned int total = 2;
@@ -155,6 +172,9 @@ void ChatTriggers::OnSourceModShutdown()
SH_REMOVE_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayCmd, this, &ChatTriggers::OnSayCommand_Post, true);
SH_REMOVE_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayCmd, this, &ChatTriggers::OnSayCommand_Pre, false);
}
g_Forwards.ReleaseForward(m_pShouldFloodBlock);
g_Forwards.ReleaseForward(m_pDidFloodBlock);
}
#if defined ORANGEBOX_BUILD
@@ -167,6 +187,7 @@ void ChatTriggers::OnSayCommand_Pre()
#endif
int client = g_ConCmds.GetCommandClient();
m_bIsChatTrigger = false;
m_bWasFloodedMessage = false;
/* The server console cannot do this */
if (client == 0)
@@ -181,6 +202,35 @@ void ChatTriggers::OnSayCommand_Pre()
RETURN_META(MRES_IGNORED);
}
/* Check if we need to block this message from being sent */
if (ClientIsFlooding(client))
{
char buffer[128];
/* :TODO: log an error? */
if (g_Translator.CoreTransEx(g_pFloodPhrases,
client,
buffer,
sizeof(buffer),
"Flooding the server",
NULL,
NULL)
!= Trans_Okay)
{
UTIL_Format(buffer, sizeof(buffer), "You are flooding the server!");
}
/* :TODO: we should probably kick people who spam too much. */
char fullbuffer[192];
UTIL_Format(fullbuffer, sizeof(fullbuffer), "[SM] %s", buffer);
g_HL2.TextMsg(client, HUD_PRINTTALK, fullbuffer);
m_bWasFloodedMessage = true;
RETURN_META(MRES_SUPERCEDE);
}
/* Handle quoted string sets */
bool is_quoted = false;
if (args[0] == '"')
@@ -197,7 +247,9 @@ void ChatTriggers::OnSayCommand_Pre()
{
is_trigger = true;
args = &args[m_PubTriggerSize];
} else if (m_PrivTriggerSize && strncmp(args, m_PrivTrigger, m_PrivTriggerSize) == 0) {
}
else if (m_PrivTriggerSize && strncmp(args, m_PrivTrigger, m_PrivTriggerSize) == 0)
{
is_trigger = true;
is_silent = true;
args = &args[m_PrivTriggerSize];
@@ -250,6 +302,7 @@ void ChatTriggers::OnSayCommand_Post()
#endif
{
m_bIsChatTrigger = false;
m_bWasFloodedMessage = false;
if (m_bWillProcessInPost)
{
/* Reset this for re-entrancy */
@@ -355,3 +408,35 @@ bool ChatTriggers::IsChatTrigger()
{
return m_bIsChatTrigger;
}
bool ChatTriggers::ClientIsFlooding(int client)
{
bool is_flooding = false;
if (m_pShouldFloodBlock->GetFunctionCount() != 0)
{
cell_t res = 0;
m_pShouldFloodBlock->PushCell(client);
m_pShouldFloodBlock->Execute(&res);
if (res != 0)
{
is_flooding = true;
}
}
if (m_pDidFloodBlock->GetFunctionCount() != 0)
{
m_pDidFloodBlock->PushCell(client);
m_pDidFloodBlock->PushCell(is_flooding ? 1 : 0);
m_pDidFloodBlock->Execute(NULL);
}
return is_flooding;
}
bool ChatTriggers::WasFloodedMessage()
{
return m_bWasFloodedMessage;
}
+8
View File
@@ -36,6 +36,7 @@
#include "sourcemm_api.h"
#include <IGameHelpers.h>
#include <compat_wrappers.h>
#include <IForwardSys.h>
class ChatTriggers : public SMGlobalClass
{
@@ -43,6 +44,8 @@ public:
ChatTriggers();
~ChatTriggers();
public: //SMGlobalClass
void OnSourceModAllInitialized();
void OnSourceModAllInitialized_Post();
void OnSourceModGameInitialized();
void OnSourceModShutdown();
ConfigResult OnSourceModConfigChanged(const char *key,
@@ -62,8 +65,10 @@ public:
unsigned int GetReplyTo();
unsigned int SetReplyTo(unsigned int reply);
bool IsChatTrigger();
bool WasFloodedMessage();
private:
bool PreProcessTrigger(edict_t *pEdict, const char *args, bool is_quoted);
bool ClientIsFlooding(int client);
private:
ConCommand *m_pSayCmd;
ConCommand *m_pSayTeamCmd;
@@ -74,8 +79,11 @@ private:
bool m_bWillProcessInPost;
bool m_bTriggerWasSilent;
bool m_bIsChatTrigger;
bool m_bWasFloodedMessage;
unsigned int m_ReplyTo;
char m_ToExecute[300];
IForward *m_pShouldFloodBlock;
IForward *m_pDidFloodBlock;
};
extern ChatTriggers g_ChatTriggers;
+19 -5
View File
@@ -299,6 +299,16 @@ void ConCmdManager::InternalDispatch(const CCommand &command)
return;
}
/* This is a hack to prevent say triggers from firing on messages that were
* blocked because of flooding. We won't remove this, but the hack will get
* "nicer" when we expose explicit say hooks.
*/
if (META_RESULT_STATUS == MRES_SUPERCEDE
&& g_ChatTriggers.WasFloodedMessage())
{
return;
}
cell_t result = Pl_Continue;
int args = command.ArgC() - 1;
@@ -456,7 +466,9 @@ bool ConCmdManager::CheckCommandAccess(int client, const char *cmd, FlagBits cmd
if (rule == Command_Allow)
{
return true;
} else if (rule == Command_Deny) {
}
else if (rule == Command_Deny)
{
return false;
}
}
@@ -486,18 +498,20 @@ bool ConCmdManager::CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmi
if (g_Translator.CoreTrans(client, buffer, sizeof(buffer), "No Access", NULL, NULL)
!= Trans_Okay)
{
snprintf(buffer, sizeof(buffer), "You do not have access to this command");
UTIL_Format(buffer, sizeof(buffer), "You do not have access to this command");
}
unsigned int replyto = g_ChatTriggers.GetReplyTo();
if (replyto == SM_REPLY_CONSOLE)
{
char fullbuffer[192];
snprintf(fullbuffer, sizeof(fullbuffer), "[SM] %s.\n", buffer);
UTIL_Format(fullbuffer, sizeof(fullbuffer), "[SM] %s.\n", buffer);
engine->ClientPrintf(pEdict, fullbuffer);
} else if (replyto == SM_REPLY_CHAT) {
}
else if (replyto == SM_REPLY_CHAT)
{
char fullbuffer[192];
snprintf(fullbuffer, sizeof(fullbuffer), "[SM] %s.", buffer);
UTIL_Format(fullbuffer, sizeof(fullbuffer), "[SM] %s.", buffer);
g_HL2.TextMsg(client, HUD_PRINTTALK, fullbuffer);
}
+24 -15
View File
@@ -949,25 +949,19 @@ size_t Translator::Translate(char *buffer, size_t maxlength, void **params, cons
return gnprintf(buffer, maxlength, pTrans->szPhrase, new_params);
}
TransError Translator::CoreTrans(int client,
char *buffer,
size_t maxlength,
const char *phrase,
void **params,
size_t *outlen)
TransError Translator::CoreTransEx(CPhraseFile *pFile,
int client,
char *buffer,
size_t maxlength,
const char *phrase,
void **params,
size_t *outlen)
{
/* :TODO: do language stuff here */
if (!g_pCorePhrases)
{
return Trans_BadPhraseFile;
}
Translation trans;
TransError err;
/* Using server lang temporarily until client lang stuff is implemented */
if ((err=g_pCorePhrases->GetTranslation(phrase, m_ServerLang, &trans)) != Trans_Okay)
if ((err = pFile->GetTranslation(phrase, m_ServerLang, &trans)) != Trans_Okay)
{
return err;
}
@@ -982,6 +976,21 @@ TransError Translator::CoreTrans(int client,
return Trans_Okay;
}
TransError Translator::CoreTrans(int client,
char *buffer,
size_t maxlength,
const char *phrase,
void **params,
size_t *outlen)
{
if (!g_pCorePhrases)
{
return Trans_BadPhraseFile;
}
return CoreTransEx(g_pCorePhrases, client, buffer, maxlength, phrase, params, outlen);
}
unsigned int Translator::GetServerLanguage()
{
return m_ServerLang;
+7
View File
@@ -140,6 +140,13 @@ public:
bool GetLanguageByName(const char *name, unsigned int *index);
size_t Translate(char *buffer, size_t maxlength, void **params, const Translation *pTrans);
CPhraseFile *GetFileByIndex(unsigned int index);
TransError CoreTransEx(CPhraseFile *pFile,
int client,
char *buffer,
size_t maxlength,
const char *phrase,
void **params,
size_t *outlen=NULL);
TransError CoreTrans(int client,
char *buffer,
size_t maxlength,