Programming with the IceOps Plugin API
More than a decade ago now the guys of the IceOps-Team developed a server extension for the stock MW1 game offering a programmable plugin API. In this article I will detail the process of writing a plugin to prevent IP and URL advertisement in a game server.
The plugin API offers a broad range of functions for managing cvars, interacting with registered commands, file operations and so on.
As well as that, it offers callback functions for game events:
PCL void OnPreFastRestart();
PCL void OnExitLevel();
PCL void OnPostFastRestart();
PCL void OnPreGameRestart(int savepersist);
PCL void OnPostGameRestart(int savepersist);
PCL void OnSpawnServer();
First things first, compile suitable regexes for later use:
qboolean create_regex()
{
return regcomp(®ex.ip, REG_IP, REG_EXTENDED) == 0 &&
regcomp(®ex.url, REG_URL, REG_EXTENDED) == 0;
}
We indicate to the server if they fail to compile in the OnInit()
function:
PCL int OnInit()
{
if (create_regex() == qfalse)
{
log_info("AdStop: Failed to compile RegEx, exiting...");
return 1;
}
...
}
Then we register our plugin cvars, this gives users of the plugin the ability to configure its behaviour from config files:
PCL int OnInit()
{
...
cvars.sub = Plugin_Cvar_RegisterString(..., ..., ...);
cvars.sub_ip = Plugin_Cvar_RegisterBool(..., ..., ...);
cvars.sub_url = Plugin_Cvar_RegisterBool(..., ..., ...);
return 0;
}
Before checking for regex matches we must first clean the incoming message of colour codes. If we don't do this coloured messages may fail a regex test.
The following snippet uses pointer arithmetic to step through the string until we meet ^[0-9]
, skips those characters if present, otherwise the char at p is copied into the position at q. The message string is effectively cleaned in situ.
ptrdiff_t remove_colours(char *message)
{
char *p, *q;
p = q = message;
while (*p)
{
if (*p == '^' && *(p + 1) && isdigit(*(p + 1)))
{
p++;
}
else if (isprint(*p))
{
*q++ = *p;
}
p++;
}
*q = '\0';
return q - message;
}
Finally, if a match occurs we overwrite the original message. All of this is handled in the APIs OnMessageSent
callback function:
PCL void OnMessageSent(char *msg, int slot, qboolean *show, int mode)
{
remove_colours(msg);
enum match_type match = matches(msg);
if (match == IP || match == URL)
{
snprintf(message,
MAX_SAY_TEXT,
Plugin_Cvar_GetString(cvars.sub));
}
...
}
Once the plugin is loaded abusers attempting to advertise on the server will have their messages replaced.
Note. if the replacement text
is set to a blank string the users message will not show at all, not even a prompt indicating an attempted message.
Subscribe to this blog's RSS feed