Move ConCommand hooks into GameHooks and switch callbacks to ICommandArgs.

This commit is contained in:
David Anderson 2015-09-06 12:35:04 -07:00
parent b63bfdc72a
commit b048dc7b10
12 changed files with 169 additions and 66 deletions

View File

@ -36,20 +36,14 @@
#include "ChatTriggers.h"
#include "logic_bridge.h"
#include "sourcemod.h"
#include "provider.h"
#include "command_args.h"
#include <bridge/include/IScriptManager.h>
using namespace ke;
ConCmdManager g_ConCmds;
#if SOURCE_ENGINE == SE_DOTA
SH_DECL_HOOK2_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommandContext &, const CCommand &);
#elif SOURCE_ENGINE >= SE_ORANGEBOX
SH_DECL_HOOK1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
#else
SH_DECL_HOOK0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
#endif
SH_DECL_HOOK1_void(IServerGameClients, SetCommandClient, SH_NOATTRIB, false, int);
typedef ke::LinkedList<CmdHook *> PluginHookList;
@ -142,23 +136,13 @@ void ConCmdManager::OnPluginDestroyed(IPlugin *plugin)
delete pList;
}
#if SOURCE_ENGINE == SE_DOTA
void CommandCallback(const CCommandContext &context, const CCommand &command)
void CommandCallback(DISPATCH_ARGS)
{
#elif SOURCE_ENGINE >= SE_ORANGEBOX
void CommandCallback(const CCommand &command)
{
#else
void CommandCallback()
{
CCommand command;
#endif
DISPATCH_PROLOGUE;
EngineArgs args(command);
g_HL2.PushCommandStack(&command);
g_ConCmds.InternalDispatch(command);
g_HL2.PopCommandStack();
AutoEnterCommand autoEnterCommand(&args);
g_ConCmds.InternalDispatch(&args);
}
void ConCmdManager::SetCommandClient(int client)
@ -232,7 +216,7 @@ ResultType ConCmdManager::DispatchClientCommand(int client, const char *cmd, int
return (ResultType)result;
}
void ConCmdManager::InternalDispatch(const CCommand &command)
void ConCmdManager::InternalDispatch(const ICommandArgs *args)
{
int client = m_CmdClient;
@ -275,7 +259,7 @@ void ConCmdManager::InternalDispatch(const CCommand &command)
return;
cell_t result = Pl_Continue;
int args = command.ArgC() - 1;
int argc = args->ArgC() - 1;
// On a listen server, sometimes the server host's client index can be set
// as 0. So index 1 is passed to the command callback to correct this
@ -311,7 +295,7 @@ void ConCmdManager::InternalDispatch(const CCommand &command)
hook->pf->PushCell(realClient);
}
hook->pf->PushCell(args);
hook->pf->PushCell(argc);
cell_t tempres = result;
if (hook->pf->Execute(&tempres) == SP_ERROR_NONE)
@ -556,15 +540,12 @@ void ConCmdManager::RemoveConCmd(ConCmdInfo *info, const char *name, bool is_rea
}
else
{
if (is_read_safe)
{
/* Remove the external hook */
SH_REMOVE_HOOK(ConCommand, Dispatch, info->pCmd, SH_STATIC(CommandCallback), false);
}
// If it's not safe to read the pointer, we zap the SourceHook hook so it
// doesn't attempt to access the pointer's vtable.
if (!is_read_safe)
info->sh_hook->Zap();
if (untrack)
{
UntrackConCommandBase(info->pCmd, this);
}
}
}
@ -623,7 +604,11 @@ ConCmdInfo *ConCmdManager::AddOrFindCommand(const char *name, const char *descri
else
{
TrackConCommandBase(pCmd, this);
SH_ADD_HOOK(ConCommand, Dispatch, pCmd, SH_STATIC(CommandCallback), false);
CommandHook::Callback callback = [this] (const ICommandArgs *args) {
AutoEnterCommand autoEnterCommand(args);
this->InternalDispatch(args);
};
pInfo->sh_hook = sCoreProviderImpl.AddCommandHook(pCmd, callback);
}
pInfo->pCmd = pCmd;

View File

@ -40,6 +40,7 @@
#include <IRootConsoleMenu.h>
#include <IAdminSystem.h>
#include "concmd_cleaner.h"
#include "GameHooks.h"
#include <sm_stringhashmap.h>
#include <am-utility.h>
#include <am-inlinelist.h>
@ -105,6 +106,7 @@ struct ConCmdInfo
ConCommand *pCmd; /**< Pointer to the command itself */
CmdHookList hooks; /**< Hook list */
FlagBits eflags; /**< Effective admin flags */
ke::Ref<CommandHook> sh_hook; /**< SourceHook hook, if any. */
};
typedef List<ConCmdInfo *> ConCmdList;
@ -115,13 +117,7 @@ class ConCmdManager :
public IPluginsListener,
public IConCommandTracker
{
#if SOURCE_ENGINE == SE_DOTA
friend void CommandCallback(const CCommandContext &context, const CCommand &command);
#elif SOURCE_ENGINE >= SE_ORANGEBOX
friend void CommandCallback(const CCommand &command);
#else
friend void CommandCallback();
#endif
friend void CommandCallback(DISPATCH_ARGS);
public:
ConCmdManager();
~ConCmdManager();
@ -147,7 +143,7 @@ public:
bool LookForSourceModCommand(const char *cmd);
bool LookForCommandAdminFlags(const char *cmd, FlagBits *pFlags);
private:
void InternalDispatch(const CCommand &command);
void InternalDispatch(const ICommandArgs *args);
ResultType RunAdminCommand(ConCmdInfo *pInfo, int client, int args);
ConCmdInfo *AddOrFindCommand(const char *name, const char *description, int flags);
void SetCommandClient(int client);

View File

@ -50,6 +50,7 @@
#include "HalfLife2.h"
#include "ConCommandBaseIterator.h"
#include "logic_bridge.h"
#include "command_args.h"
#include <am-utility.h>
#include <bridge/include/ILogger.h>
@ -653,10 +654,10 @@ bool ConsoleDetours::RemoveListener(IPluginFunction *fun, const char *command)
}
}
cell_t ConsoleDetours::InternalDispatch(int client, const CCommand& args)
cell_t ConsoleDetours::InternalDispatch(int client, const ICommandArgs *args)
{
char name[255];
const char *realname = args.Arg(0);
const char *realname = args->Arg(0);
size_t len = strlen(realname);
// Disallow command strings that are too long, for now.
@ -675,7 +676,7 @@ cell_t ConsoleDetours::InternalDispatch(int client, const CCommand& args)
cell_t result = Pl_Continue;
m_pForward->PushCell(client);
m_pForward->PushString(name);
m_pForward->PushCell(args.ArgC() - 1);
m_pForward->PushCell(args->ArgC() - 1);
m_pForward->Execute(&result, NULL);
/* Don't let plugins block this. */
@ -694,7 +695,7 @@ cell_t ConsoleDetours::InternalDispatch(int client, const CCommand& args)
cell_t result2 = Pl_Continue;
forward->PushCell(client);
forward->PushString(name);
forward->PushCell(args.ArgC() - 1);
forward->PushCell(args->ArgC() - 1);
forward->Execute(&result2, NULL);
if (result2 > result)
@ -714,9 +715,12 @@ cell_t ConsoleDetours::Dispatch(ConCommand *pBase)
{
CCommand args;
#endif
g_HL2.PushCommandStack(&args);
cell_t res = g_ConsoleDetours.InternalDispatch(g_ConCmds.GetCommandClient(), args);
g_HL2.PopCommandStack();
EngineArgs cargs(args);
cell_t res;
{
AutoEnterCommand autoEnterCommand(&cargs);
res = g_ConsoleDetours.InternalDispatch(g_ConCmds.GetCommandClient(), &cargs);
}
#if SH_IMPL_VERSION < 4
if (res >= Pl_Handled)

View File

@ -36,6 +36,10 @@
#include <IForwardSys.h>
#include <sm_stringhashmap.h>
namespace SourceMod {
class ICommandArgs;
} // namespace SourceMod
class ConsoleDetours :
public SMGlobalClass,
public IFeatureProvider
@ -54,7 +58,7 @@ public:
bool AddListener(IPluginFunction *fun, const char *command);
bool RemoveListener(IPluginFunction *fun, const char *command);
private:
cell_t InternalDispatch(int client, const CCommand& args);
cell_t InternalDispatch(int client, const SourceMod::ICommandArgs *args);
#if SOURCE_ENGINE >= SE_ORANGEBOX
static cell_t Dispatch(ConCommand *pBase, const CCommand& args);
#else

View File

@ -27,6 +27,7 @@
#include "GameHooks.h"
#include "sourcemod.h"
#include "ConVarManager.h"
#include "command_args.h"
#if SOURCE_ENGINE >= SE_ORANGEBOX
SH_DECL_HOOK3_void(ICvar, CallGlobalChangeCallbacks, SH_NOATTRIB, false, ConVar *, const char *, float);
@ -42,6 +43,14 @@ SH_DECL_HOOK5_void(IServerGameDLL, OnQueryCvarValueFinished, SH_NOATTRIB, 0, Que
SH_DECL_HOOK5_void(IServerPluginCallbacks, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, edict_t *, EQueryCvarValueStatus, const char *, const char *);
#endif
#if SOURCE_ENGINE == SE_DOTA
SH_DECL_HOOK2_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommandContext &, const CCommand &);
#elif SOURCE_ENGINE >= SE_ORANGEBOX
SH_DECL_HOOK1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
#else
SH_DECL_HOOK0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
#endif
GameHooks::GameHooks()
: client_cvar_query_mode_(ClientCvarQueryMode::Unavailable)
{
@ -128,3 +137,43 @@ void GameHooks::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPla
g_ConVarManager.OnClientQueryFinished(cookie, client, result, cvarName, cvarValue);
}
#endif
ke::PassRef<CommandHook>
GameHooks::AddCommandHook(ConCommand *cmd, const CommandHook::Callback &callback)
{
return new CommandHook(cmd, callback, false);
}
ke::PassRef<CommandHook>
GameHooks::AddPostCommandHook(ConCommand *cmd, const CommandHook::Callback &callback)
{
return new CommandHook(cmd, callback, true);
}
CommandHook::CommandHook(ConCommand *cmd, const Callback &callback, bool post)
: hook_id_(0),
callback_(callback)
{
hook_id_ = SH_ADD_HOOK(ConCommand, Dispatch, cmd, SH_MEMBER(this, &CommandHook::Dispatch), post);
}
CommandHook::~CommandHook()
{
if (hook_id_)
SH_REMOVE_HOOK_ID(hook_id_);
}
void CommandHook::Dispatch(DISPATCH_ARGS)
{
DISPATCH_PROLOGUE;
EngineArgs args(command);
AddRef();
callback_(&args);
Release();
}
void CommandHook::Zap()
{
hook_id_ = 0;
}

View File

@ -32,18 +32,52 @@
#include <stddef.h>
#include <eiface.h>
#include <iserverplugin.h>
#include <amtl/am-refcounting.h>
#include <amtl/am-vector.h>
#include <amtl/am-function.h>
class ConVar;
class CCommand;
struct CCommandContext;
#if SOURCE_ENGINE == SE_DOTA
# define DISPATCH_ARGS const CCommandContext &context, const CCommand &command
# define DISPATCH_PROLOGUE
#elif SOURCE_ENGINE >= SE_ORANGEBOX
# define DISPATCH_ARGS const CCommand &command
# define DISPATCH_PROLOGUE
#else
# define DISPATCH_ARGS
# define DISPATCH_PROLOGUE CCommand command
#endif
namespace SourceMod {
// Describes the mechanism in which client cvar queries are implemented.
enum class ClientCvarQueryMode {
Unavailable,
DLL,
VSP
};
class ICommandArgs;
class CommandHook : public ke::Refcounted<CommandHook>
{
public:
typedef ke::Lambda<void(const ICommandArgs *)> Callback;
public:
CommandHook(ConCommand *cmd, const Callback &callback, bool post);
~CommandHook();
void Dispatch(DISPATCH_ARGS);
void Zap();
private:
int hook_id_;
Callback callback_;
};
class GameHooks
{
public:
@ -57,6 +91,10 @@ public:
return client_cvar_query_mode_;
}
public:
ke::PassRef<CommandHook> AddCommandHook(ConCommand *cmd, const CommandHook::Callback &callback);
ke::PassRef<CommandHook> AddPostCommandHook(ConCommand *cmd, const CommandHook::Callback &callback);
private:
// Static callback that Valve's ConVar object executes when the convar's value changes.
#if SOURCE_ENGINE >= SE_ORANGEBOX

View File

@ -825,7 +825,7 @@ bool CHalfLife2::KVLoadFromFile(KeyValues *kv, IBaseFileSystem *filesystem, cons
}
}
void CHalfLife2::PushCommandStack(const CCommand *cmd)
void CHalfLife2::PushCommandStack(const ICommandArgs *cmd)
{
CachedCommandInfo info;
@ -837,7 +837,7 @@ void CHalfLife2::PushCommandStack(const CCommand *cmd)
m_CommandStack.push(info);
}
const CCommand *CHalfLife2::PeekCommandStack()
const ICommandArgs *CHalfLife2::PeekCommandStack()
{
if (m_CommandStack.empty())
{

View File

@ -49,7 +49,9 @@
#include <tier0/icommandline.h>
#include <string_t.h>
class CCommand;
namespace SourceMod {
class ICommandArgs;
} // namespace SourceMod
using namespace SourceHook;
using namespace SourceMod;
@ -100,7 +102,7 @@ struct DelayedFakeCliCmd
struct CachedCommandInfo
{
const CCommand *args;
const ICommandArgs *args;
#if SOURCE_ENGINE <= SE_DARKMESSIAH
char cmd[300];
#endif
@ -141,6 +143,7 @@ class CHalfLife2 :
public SMGlobalClass,
public IGameHelpers
{
friend class AutoEnterCommand;
public:
CHalfLife2();
~CHalfLife2();
@ -190,9 +193,7 @@ public:
void AddToFakeCliCmdQueue(int client, int userid, const char *cmd);
void ProcessFakeCliCmdQueue();
public:
void PushCommandStack(const CCommand *cmd);
void PopCommandStack();
const CCommand *PeekCommandStack();
const ICommandArgs *PeekCommandStack();
const char *CurrentCommandName();
void AddDelayedKick(int client, int userid, const char *msg);
void ProcessDelayedKicks();
@ -200,6 +201,8 @@ public:
bool IsOriginalEngine();
#endif
private:
void PushCommandStack(const ICommandArgs *cmd);
void PopCommandStack();
DataTableInfo *_FindServerClass(const char *classname);
private:
void InitLogicalEntData();
@ -224,4 +227,15 @@ extern CHalfLife2 g_HL2;
bool IndexToAThings(cell_t, CBaseEntity **pEntData, edict_t **pEdictData);
class AutoEnterCommand
{
public:
AutoEnterCommand(const ICommandArgs *args) {
g_HL2.PushCommandStack(args);
}
~AutoEnterCommand() {
g_HL2.PopCommandStack();
}
};
#endif //_INCLUDE_SOURCEMOD_CHALFLIFE2_H_

View File

@ -47,6 +47,7 @@
#include "logic_bridge.h"
#include <sourcemod_version.h>
#include "smn_keyvalues.h"
#include "command_args.h"
#include <ITranslator.h>
#include <bridge/include/IExtensionBridge.h>
#include <bridge/include/IScriptManager.h>
@ -1180,7 +1181,8 @@ void PlayerManager::OnClientCommand(edict_t *pEntity)
RETURN_META(MRES_SUPERCEDE);
}
g_HL2.PushCommandStack(&args);
EngineArgs cargs(args);
AutoEnterCommand autoEnterCommand(&cargs);
int argcount = args.ArgC() - 1;
const char *cmd = g_HL2.CurrentCommandName();
@ -1199,10 +1201,9 @@ void PlayerManager::OnClientCommand(edict_t *pEntity)
if (g_ConsoleDetours.IsEnabled())
{
cell_t res2 = g_ConsoleDetours.InternalDispatch(client, args);
cell_t res2 = g_ConsoleDetours.InternalDispatch(client, &cargs);
if (res2 >= Pl_Stop)
{
g_HL2.PopCommandStack();
RETURN_META(MRES_SUPERCEDE);
}
else if (res2 > res)
@ -1226,14 +1227,11 @@ void PlayerManager::OnClientCommand(edict_t *pEntity)
if (res >= Pl_Stop)
{
g_HL2.PopCommandStack();
RETURN_META(MRES_SUPERCEDE);
}
res = g_ConCmds.DispatchClientCommand(client, cmd, argcount, (ResultType)res);
g_HL2.PopCommandStack();
if (res >= Pl_Handled)
{
RETURN_META(MRES_SUPERCEDE);

View File

@ -742,6 +742,18 @@ bool CoreProviderImpl::LoadBridge(char *error, size_t maxlength)
return true;
}
ke::PassRef<CommandHook>
CoreProviderImpl::AddCommandHook(ConCommand *cmd, const CommandHook::Callback &callback)
{
return hooks_.AddCommandHook(cmd, callback);
}
ke::PassRef<CommandHook>
CoreProviderImpl::AddPostCommandHook(ConCommand *cmd, const CommandHook::Callback &callback)
{
return hooks_.AddPostCommandHook(cmd, callback);
}
void CoreProviderImpl::InitializeHooks()
{
hooks_.Start();

View File

@ -65,6 +65,9 @@ public:
int QueryClientConVar(int client, const char *cvar) override;
bool IsClientConVarQueryingSupported() override;
ke::PassRef<CommandHook> AddCommandHook(ConCommand *cmd, const CommandHook::Callback &callback);
ke::PassRef<CommandHook> AddPostCommandHook(ConCommand *cmd, const CommandHook::Callback &callback);
private:
ke::Ref<ke::SharedLib> logic_;
LogicInitFunction logic_init_;

View File

@ -784,7 +784,7 @@ static cell_t sm_RegAdminCmd(IPluginContext *pContext, const cell_t *params)
static cell_t sm_GetCmdArgs(IPluginContext *pContext, const cell_t *params)
{
const CCommand *pCmd = g_HL2.PeekCommandStack();
const ICommandArgs *pCmd = g_HL2.PeekCommandStack();
if (!pCmd)
{
@ -796,7 +796,7 @@ static cell_t sm_GetCmdArgs(IPluginContext *pContext, const cell_t *params)
static cell_t sm_GetCmdArg(IPluginContext *pContext, const cell_t *params)
{
const CCommand *pCmd = g_HL2.PeekCommandStack();
const ICommandArgs *pCmd = g_HL2.PeekCommandStack();
if (!pCmd)
{
@ -814,7 +814,7 @@ static cell_t sm_GetCmdArg(IPluginContext *pContext, const cell_t *params)
static cell_t sm_GetCmdArgString(IPluginContext *pContext, const cell_t *params)
{
const CCommand *pCmd = g_HL2.PeekCommandStack();
const ICommandArgs *pCmd = g_HL2.PeekCommandStack();
if (!pCmd)
{