Added ProcessTargetString simple filter API (bug 4404, r=ds).

This commit is contained in:
David Anderson 2010-05-13 12:28:51 -07:00
parent fb28f4bcd0
commit 28217f10cb
11 changed files with 403 additions and 3 deletions

View File

@ -31,6 +31,7 @@ files = [
'Profiler.cpp',
'smn_functions.cpp',
'smn_timers.cpp',
'smn_players.cpp',
'sm_crc32.cpp'
]
if AMBuild.target['platform'] == 'windows':

View File

@ -0,0 +1,92 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* 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
* Free Software Foundation.
*
* 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
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#ifndef _INCLUDE_SOURCEMOD_AUTO_HANDLE_ROOTER_H_
#define _INCLUDE_SOURCEMOD_AUTO_HANDLE_ROOTER_H_
#include "common_logic.h"
#include <IHandleSys.h>
class AutoHandleRooter
{
public:
AutoHandleRooter(Handle_t hndl)
{
if (hndl != BAD_HANDLE)
this->hndl = handlesys->FastCloneHandle(hndl);
else
this->hndl = BAD_HANDLE;
}
~AutoHandleRooter()
{
if (hndl != BAD_HANDLE)
{
HandleSecurity sec(g_pCoreIdent, g_pCoreIdent);
handlesys->FreeHandle(hndl, &sec);
}
}
Handle_t getHandle()
{
return hndl;
}
private:
Handle_t hndl;
};
class AutoHandleCloner
{
Handle_t original;
HandleSecurity sec;
AutoHandleRooter ahr;
public:
AutoHandleCloner(Handle_t original, HandleSecurity sec)
: original(original), sec(sec), ahr(original)
{
}
~AutoHandleCloner()
{
if (original != BAD_HANDLE)
{
handlesys->FreeHandle(original, &sec);
}
}
Handle_t getClone()
{
return ahr.getHandle();
}
};
#endif /* _INCLUDE_SOURCEMOD_AUTO_HANDLE_ROOTER_H_ */

View File

@ -27,7 +27,8 @@ OBJECTS = \
Profiler.cpp \
smn_functions.cpp \
sm_crc32.cpp \
smn_timers.cpp
smn_timers.cpp \
smn_players.cpp
##############################################
### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ###

View File

@ -52,6 +52,7 @@ IPluginManager *pluginsys;
IForwardManager *forwardsys;
ITimerSystem *timersys;
ServerGlobals serverGlobals;
IPlayerManager *playerhelpers;
static sm_logic_t logic =
{
@ -79,6 +80,7 @@ static void logic_init(const sm_core_t* core, sm_logic_t* _logic)
pluginsys = core->pluginsys;
forwardsys = core->forwardsys;
timersys = core->timersys;
playerhelpers = core->playerhelpers;
}
PLATFORM_EXTERN_C ITextParsers *get_textparsers()

View File

@ -49,6 +49,7 @@ extern IPluginManager *pluginsys;
extern IForwardManager *forwardsys;
extern ITimerSystem *timersys;
extern ServerGlobals serverGlobals;
extern IPlayerManager *playerhelpers;
#endif /* _INCLUDE_SOURCEMOD_COMMON_LOGIC_H_ */

View File

@ -42,7 +42,7 @@ using namespace SourceMod;
* Add 1 to the RHS of this expression to bump the intercom file
* This is to prevent mismatching core/logic binaries
*/
#define SM_LOGIC_MAGIC (0x0F47C0DE - 4)
#define SM_LOGIC_MAGIC (0x0F47C0DE - 5)
#if defined SM_LOGIC
class IVEngineServer
@ -64,6 +64,7 @@ namespace SourceMod
class IPluginManager;
class IForwardManager;
class ITimerSystem;
class IPlayerManager;
}
class IVEngineServer;
@ -89,6 +90,7 @@ struct sm_core_t
IPluginManager *pluginsys;
IForwardManager *forwardsys;
ITimerSystem *timersys;
IPlayerManager *playerhelpers;
/* Functions */
void (*AddNatives)(sp_nativeinfo_t* nlist);
ConVar * (*FindConVar)(const char*);

235
core/logic/smn_players.cpp Normal file
View File

@ -0,0 +1,235 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* 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
* Free Software Foundation.
*
* 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
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#include "common_logic.h"
#include <IPluginSys.h>
#include <IPlayerHelpers.h>
#include <sh_string.h>
#include <sh_list.h>
#include "AutoHandleRooter.h"
#include "CellArray.h"
using namespace SourceHook;
using namespace SourceMod;
class PlayerLogicHelpers :
public SMGlobalClass,
public IPluginsListener,
public ICommandTargetProcessor
{
struct SimpleMultiTargetFilter
{
IPlugin *plugin;
SourceHook::String pattern;
IPluginFunction *fun;
SourceHook::String phrase;
bool phraseIsML;
SimpleMultiTargetFilter(IPlugin *plugin, const char *pattern, IPluginFunction *fun,
const char *phrase, bool phraseIsML)
: plugin(plugin), pattern(pattern), fun(fun), phrase(phrase), phraseIsML(phraseIsML)
{
}
};
List<SimpleMultiTargetFilter *> simpleMultis;
bool filterEnabled;
public:
void AddMultiTargetFilter(IPlugin *plugin, const char *pattern, IPluginFunction *fun,
const char *phrase, bool phraseIsML)
{
SimpleMultiTargetFilter *smtf = new SimpleMultiTargetFilter(plugin, pattern, fun, phrase,
phraseIsML);
simpleMultis.push_back(smtf);
if (!filterEnabled) {
playerhelpers->RegisterCommandTargetProcessor(this);
filterEnabled = true;
}
}
void RemoveMultiTargetFilter(const char *pattern, IPluginFunction *fun)
{
List<SimpleMultiTargetFilter *>::iterator iter = simpleMultis.begin();
while (iter != simpleMultis.end()) {
if ((*iter)->fun == fun && strcmp((*iter)->pattern.c_str(), pattern) == 0) {
delete (*iter);
iter = simpleMultis.erase(iter);
break;
}
iter++;
}
}
PlayerLogicHelpers()
: filterEnabled(false)
{
}
public: //ICommandTargetProcessor
bool ProcessCommandTarget(cmd_target_info_t *info)
{
List<SimpleMultiTargetFilter *>::iterator iter;
for (iter = simpleMultis.begin(); iter != simpleMultis.end(); iter++) {
SimpleMultiTargetFilter *smtf = (*iter);
if (strcmp(smtf->pattern.c_str(), info->pattern) == 0) {
CellArray *array = new CellArray(1);
HandleSecurity sec(g_pCoreIdent, g_pCoreIdent);
Handle_t hndl = handlesys->CreateHandleEx(htCellArray, array, &sec, NULL, NULL);
AutoHandleCloner ahc(hndl, sec);
if (ahc.getClone() == BAD_HANDLE) {
smcore.LogError("[SM] Could not allocate a handle (%s, %d)", __FILE__, __LINE__);
delete array;
return false;
}
smtf->fun->PushString(info->pattern);
smtf->fun->PushCell(ahc.getClone());
cell_t result = 0;
if (smtf->fun->Execute(&result) != SP_ERROR_NONE || !result)
return false;
IGamePlayer *pAdmin = info->admin
? playerhelpers->GetGamePlayer(info->admin)
: NULL;
info->num_targets = 0;
for (size_t i = 0; i < array->size(); i++) {
cell_t client = *array->at(i);
IGamePlayer *pClient = playerhelpers->GetGamePlayer(client);
if (pClient == NULL || !pClient->IsConnected())
continue;
if (playerhelpers->FilterCommandTarget(pAdmin, pClient, info->flags) ==
COMMAND_TARGET_VALID)
{
info->targets[info->num_targets++] = client;
if (info->num_targets >= unsigned(info->max_targets))
break;
}
}
info->reason = info->num_targets > 0
? COMMAND_TARGET_VALID
: COMMAND_TARGET_EMPTY_FILTER;
if (info->num_targets) {
smcore.strncopy(info->target_name, smtf->phrase.c_str(), info->target_name_maxlength);
info->target_name_style = smtf->phraseIsML
? COMMAND_TARGETNAME_ML
: COMMAND_TARGETNAME_RAW;
}
return true;
}
}
return false;
}
public: //SMGlobalClass
void OnSourceModAllInitialized()
{
pluginsys->AddPluginsListener(this);
}
void OnSourceModShutdown()
{
pluginsys->RemovePluginsListener(this);
if (filterEnabled) {
playerhelpers->UnregisterCommandTargetProcessor(this);
filterEnabled = false;
}
}
public: //IPluginsListener
void OnPluginDestroyed(IPlugin *plugin)
{
List<SimpleMultiTargetFilter *>::iterator iter = simpleMultis.begin();
while (iter != simpleMultis.end()) {
if ((*iter)->plugin != plugin) {
iter++;
} else {
delete (*iter);
iter = simpleMultis.erase(iter);
}
}
}
} s_PlayerLogicHelpers;
static cell_t
AddMultiTargetFilter(IPluginContext *ctx, const cell_t *params)
{
IPluginFunction *fun = ctx->GetFunctionById(funcid_t(params[2]));
if (fun == NULL)
return ctx->ThrowNativeError("Invalid function id (%X)", params[2]);
char *pattern;
char *phrase;
ctx->LocalToString(params[1], &pattern);
ctx->LocalToString(params[3], &phrase);
bool phraseIsML = !!params[4];
IPlugin *plugin = pluginsys->FindPluginByContext(ctx->GetContext());
s_PlayerLogicHelpers.AddMultiTargetFilter(plugin, pattern, fun, phrase, phraseIsML);
return 1;
}
static cell_t
RemoveMultiTargetFilter(IPluginContext *ctx, const cell_t *params)
{
IPluginFunction *fun = ctx->GetFunctionById(funcid_t(params[2]));
if (fun == NULL)
return ctx->ThrowNativeError("Invalid function id (%X)", params[2]);
char *pattern;
ctx->LocalToString(params[1], &pattern);
s_PlayerLogicHelpers.RemoveMultiTargetFilter(pattern, fun);
return 1;
}
REGISTER_NATIVES(playernatives)
{
{"AddMultiTargetFilter", AddMultiTargetFilter},
{"RemoveMultiTargetFilter", RemoveMultiTargetFilter},
{NULL, NULL}
};

View File

@ -46,6 +46,7 @@
#include "TimerSys.h"
#include "logic_bridge.h"
#include "DebugReporter.h"
#include "PlayerManager.h"
static ILibrary *g_pLogic = NULL;
static LogicInitFunction logic_init_fn;
@ -113,6 +114,7 @@ static sm_core_t core_bridge =
&g_PluginSys,
&g_Forwards,
&g_Timers,
&g_Players,
/* Functions */
add_natives,
find_convar,

View File

@ -132,3 +132,34 @@ stock ReplyToTargetError(client, reason)
}
}
}
/**
* Adds clients to a multi-target filter.
*
* @param pattern Pattern name.
* @param clients Array to fill with unique, valid client indexes.
* @return True if pattern was recognized, false otherwise.
*/
functag public bool:MultiTargetFilter(const String:pattern[], Handle:clients);
/**
* Adds a multi-target filter function for ProcessTargetString().
*
* @param pattern Pattern to match (case sensitive).
* @param filter Filter function.
* @param phrase Descriptive phrase to display on successful match.
* @param phraseIsML True if phrase is multi-lingual, false otherwise.
* @noreturn
*/
native AddMultiTargetFilter(const String:pattern[], MultiTargetFilter:filter,
const String:phrase[], bool:phraseIsML);
/**
* Removes a multi-target filter function from ProcessTargetString().
*
* @param pattern Pattern to match (case sensitive).
* @param filter Filter function.
* @noreturn
*/
native RemoveMultiTargetFilter(const String:pattern[], MultiTargetFilter:filter);

View File

@ -0,0 +1,26 @@
#include <sourcemod>
public Plugin:myinfo =
{
name = "Test target filters",
author = "AlliedModders LLC",
description = "Tests target filters",
version = "1.0.0.0",
url = "http://www.sourcemod.net/"
};
public OnPluginStart()
{
AddMultiTargetFilter("@crab", filter, "all players", true)
}
public bool:filter(const String:pattern[], Handle:clients)
{
for (new i = 1; i <= MaxClients; i++) {
if (IsPlayerInGame(i))
PushArrayCell(clients, i)
}
return true
}

View File

@ -52,7 +52,7 @@
#include <sp_vm_types.h>
#define SMINTERFACE_HANDLESYSTEM_NAME "IHandleSys"
#define SMINTERFACE_HANDLESYSTEM_VERSION 3
#define SMINTERFACE_HANDLESYSTEM_VERSION 4
/** Specifies no Identity */
#define DEFAULT_IDENTITY NULL
@ -357,6 +357,13 @@ namespace SourceMod
const HandleSecurity *pSec,
const HandleAccess *pAccess,
HandleError *err) =0;
/**
* @brief Clones a handle, bypassing security checks.
*
* @return A new Handle_t, or 0 on failure.
*/
virtual Handle_t FastCloneHandle(Handle_t hndl) =0;
};
}