Added generic command hooking mechanism, to replace Reg*Cmd which is intended for command creation (bug 4015, r=pred).
This commit is contained in:
parent
493a756aaa
commit
d8474cfafa
@ -81,6 +81,7 @@ for i in SM.sdkInfo:
|
|||||||
'smn_datapacks.cpp',
|
'smn_datapacks.cpp',
|
||||||
'smn_lang.cpp',
|
'smn_lang.cpp',
|
||||||
'sm_srvcmds.cpp',
|
'sm_srvcmds.cpp',
|
||||||
|
'ConsoleDetours.cpp'
|
||||||
]
|
]
|
||||||
binary.AddSourceFiles('core', files)
|
binary.AddSourceFiles('core', files)
|
||||||
SM.PostSetupHL2Job(extension, binary, i)
|
SM.PostSetupHL2Job(extension, binary, i)
|
||||||
|
@ -159,3 +159,4 @@ private:
|
|||||||
extern ConCmdManager g_ConCmds;
|
extern ConCmdManager g_ConCmds;
|
||||||
|
|
||||||
#endif // _INCLUDE_SOURCEMOD_CONCMDMANAGER_H_
|
#endif // _INCLUDE_SOURCEMOD_CONCMDMANAGER_H_
|
||||||
|
|
||||||
|
@ -519,45 +519,18 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/* First, preprocess the signature */
|
/* First, preprocess the signature */
|
||||||
char real_sig[511];
|
unsigned char real_sig[511];
|
||||||
size_t real_bytes;
|
size_t real_bytes;
|
||||||
size_t length;
|
size_t length;
|
||||||
|
|
||||||
real_bytes = 0;
|
real_bytes = 0;
|
||||||
length = strlen(s_TempSig.sig);
|
length = strlen(s_TempSig.sig);
|
||||||
|
|
||||||
for (size_t i=0; i<length; i++)
|
real_bytes = UTIL_DecodeHexString(real_sig, sizeof(real_sig), s_TempSig.sig);
|
||||||
{
|
|
||||||
if (real_bytes >= sizeof(real_sig))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
real_sig[real_bytes++] = s_TempSig.sig[i];
|
|
||||||
if (s_TempSig.sig[i] == '\\'
|
|
||||||
&& s_TempSig.sig[i+1] == 'x')
|
|
||||||
{
|
|
||||||
if (i + 3 >= length)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* Get the hex part */
|
|
||||||
char s_byte[3];
|
|
||||||
int r_byte;
|
|
||||||
s_byte[0] = s_TempSig.sig[i+2];
|
|
||||||
s_byte[1] = s_TempSig.sig[i+3];
|
|
||||||
s_byte[2] = '\0';
|
|
||||||
/* Read it as an integer */
|
|
||||||
sscanf(s_byte, "%x", &r_byte);
|
|
||||||
/* Save the value */
|
|
||||||
real_sig[real_bytes-1] = r_byte;
|
|
||||||
/* Adjust index */
|
|
||||||
i += 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (real_bytes >= 1)
|
if (real_bytes >= 1)
|
||||||
{
|
{
|
||||||
final_addr = g_MemUtils.FindPattern(addrInBase, real_sig, real_bytes);
|
final_addr = g_MemUtils.FindPattern(addrInBase, (char*)real_sig, real_bytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ OBJECTS = AdminCache.cpp CDataPack.cpp ConCmdManager.cpp ConVarManager.cpp CoreC
|
|||||||
sourcemm_api.cpp sourcemod.cpp MenuStyle_Base.cpp MenuStyle_Valve.cpp MenuManager.cpp \
|
sourcemm_api.cpp sourcemod.cpp MenuStyle_Base.cpp MenuStyle_Valve.cpp MenuManager.cpp \
|
||||||
MenuStyle_Radio.cpp ChatTriggers.cpp ADTFactory.cpp MenuVoting.cpp sm_crc32.cpp \
|
MenuStyle_Radio.cpp ChatTriggers.cpp ADTFactory.cpp MenuVoting.cpp sm_crc32.cpp \
|
||||||
frame_hooks.cpp concmd_cleaner.cpp PhraseCollection.cpp NextMap.cpp \
|
frame_hooks.cpp concmd_cleaner.cpp PhraseCollection.cpp NextMap.cpp \
|
||||||
NativeOwner.cpp logic_bridge.cpp
|
NativeOwner.cpp logic_bridge.cpp ConsoleDetours.cpp
|
||||||
OBJECTS += smn_admin.cpp smn_bitbuffer.cpp smn_console.cpp smn_core.cpp \
|
OBJECTS += smn_admin.cpp smn_bitbuffer.cpp smn_console.cpp smn_core.cpp \
|
||||||
smn_datapacks.cpp smn_entities.cpp smn_events.cpp smn_fakenatives.cpp \
|
smn_datapacks.cpp smn_entities.cpp smn_events.cpp smn_fakenatives.cpp \
|
||||||
smn_filesystem.cpp smn_gameconfigs.cpp smn_halflife.cpp \
|
smn_filesystem.cpp smn_gameconfigs.cpp smn_halflife.cpp \
|
||||||
|
@ -51,7 +51,7 @@ public: // SMGlobalClass
|
|||||||
void OnSourceModAllInitialized();
|
void OnSourceModAllInitialized();
|
||||||
public: // IMemoryUtils
|
public: // IMemoryUtils
|
||||||
void *FindPattern(const void *libPtr, const char *pattern, size_t len);
|
void *FindPattern(const void *libPtr, const char *pattern, size_t len);
|
||||||
private:
|
public:
|
||||||
bool GetLibraryInfo(const void *libPtr, DynLibInfo &lib);
|
bool GetLibraryInfo(const void *libPtr, DynLibInfo &lib);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -48,6 +48,7 @@
|
|||||||
#include "GameConfigs.h"
|
#include "GameConfigs.h"
|
||||||
#include "ExtensionSys.h"
|
#include "ExtensionSys.h"
|
||||||
#include <sourcemod_version.h>
|
#include <sourcemod_version.h>
|
||||||
|
#include "ConsoleDetours.h"
|
||||||
|
|
||||||
PlayerManager g_Players;
|
PlayerManager g_Players;
|
||||||
bool g_OnMapStarted = false;
|
bool g_OnMapStarted = false;
|
||||||
@ -725,6 +726,20 @@ void PlayerManager::OnClientCommand(edict_t *pEntity)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (g_ConsoleDetours.IsEnabled())
|
||||||
|
{
|
||||||
|
cell_t res2 = g_ConsoleDetours.InternalDispatch(client, args);
|
||||||
|
if (res2 >= Pl_Stop)
|
||||||
|
{
|
||||||
|
g_HL2.PopCommandStack();
|
||||||
|
RETURN_META(MRES_SUPERCEDE);
|
||||||
|
}
|
||||||
|
else if (res2 > res)
|
||||||
|
{
|
||||||
|
res = res2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cell_t res2 = Pl_Continue;
|
cell_t res2 = Pl_Continue;
|
||||||
m_clcommand->PushCell(client);
|
m_clcommand->PushCell(client);
|
||||||
m_clcommand->PushCell(argcount);
|
m_clcommand->PushCell(argcount);
|
||||||
|
@ -39,6 +39,9 @@
|
|||||||
|
|
||||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||||
SH_DECL_HOOK1_void(ICvar, UnregisterConCommand, SH_NOATTRIB, 0, ConCommandBase *);
|
SH_DECL_HOOK1_void(ICvar, UnregisterConCommand, SH_NOATTRIB, 0, ConCommandBase *);
|
||||||
|
SH_DECL_HOOK1_void(ICvar, RegisterConCommand, SH_NOATTRIB, 0, ConCommandBase *);
|
||||||
|
#else
|
||||||
|
SH_DECL_HOOK1_void(ICvar, RegisterConCommandBase, SH_NOATTRIB, 0, ConCommandBase *);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace SourceHook;
|
using namespace SourceHook;
|
||||||
@ -51,29 +54,55 @@ struct ConCommandInfo
|
|||||||
};
|
};
|
||||||
|
|
||||||
List<ConCommandInfo *> tracked_bases;
|
List<ConCommandInfo *> tracked_bases;
|
||||||
|
IConCommandLinkListener *IConCommandLinkListener::head = NULL;
|
||||||
|
|
||||||
ConCommandBase *FindConCommandBase(const char *name);
|
ConCommandBase *FindConCommandBase(const char *name);
|
||||||
|
|
||||||
class ConCommandCleaner : public SMGlobalClass
|
class ConCommandCleaner : public SMGlobalClass
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
|
||||||
void OnSourceModAllInitialized()
|
void OnSourceModAllInitialized()
|
||||||
{
|
{
|
||||||
|
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||||
SH_ADD_HOOK_MEMFUNC(ICvar, UnregisterConCommand, icvar, this, &ConCommandCleaner::UnlinkConCommandBase, false);
|
SH_ADD_HOOK_MEMFUNC(ICvar, UnregisterConCommand, icvar, this, &ConCommandCleaner::UnlinkConCommandBase, false);
|
||||||
|
SH_ADD_HOOK_MEMFUNC(ICvar, RegisterConCommand, icvar, this, &ConCommandCleaner::LinkConCommandBase, false);
|
||||||
|
#else
|
||||||
|
SH_ADD_HOOK_MEMFUNC(ICvar, RegisterConCommandBase, icvar, this, &ConCommandCleaner::LinkConCommandBase, false);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnSourceModShutdown()
|
void OnSourceModShutdown()
|
||||||
{
|
{
|
||||||
|
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||||
SH_REMOVE_HOOK_MEMFUNC(ICvar, UnregisterConCommand, icvar, this, &ConCommandCleaner::UnlinkConCommandBase, false);
|
SH_REMOVE_HOOK_MEMFUNC(ICvar, UnregisterConCommand, icvar, this, &ConCommandCleaner::UnlinkConCommandBase, false);
|
||||||
}
|
SH_REMOVE_HOOK_MEMFUNC(ICvar, RegisterConCommand, icvar, this, &ConCommandCleaner::LinkConCommandBase, false);
|
||||||
|
#else
|
||||||
|
SH_REMOVE_HOOK_MEMFUNC(ICvar, RegisterConCommandBase, icvar, this, &ConCommandCleaner::LinkConCommandBase, false);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinkConCommandBase(ConCommandBase *pBase)
|
||||||
|
{
|
||||||
|
IConCommandLinkListener *listener = IConCommandLinkListener::head;
|
||||||
|
while (listener)
|
||||||
|
{
|
||||||
|
listener->OnLinkConCommand(pBase);
|
||||||
|
listener = listener->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void UnlinkConCommandBase(ConCommandBase *pBase)
|
void UnlinkConCommandBase(ConCommandBase *pBase)
|
||||||
{
|
{
|
||||||
ConCommandInfo *pInfo;
|
ConCommandInfo *pInfo;
|
||||||
List<ConCommandInfo *>::iterator iter = tracked_bases.begin();
|
List<ConCommandInfo *>::iterator iter = tracked_bases.begin();
|
||||||
|
|
||||||
|
IConCommandLinkListener *listener = IConCommandLinkListener::head;
|
||||||
|
while (listener)
|
||||||
|
{
|
||||||
|
listener->OnUnlinkConCommand(pBase);
|
||||||
|
listener = listener->next;
|
||||||
|
}
|
||||||
|
|
||||||
if (pBase)
|
if (pBase)
|
||||||
{
|
{
|
||||||
while (iter != tracked_bases.end())
|
while (iter != tracked_bases.end())
|
||||||
|
@ -42,4 +42,26 @@ void TrackConCommandBase(ConCommandBase *pBase, IConCommandTracker *me);
|
|||||||
void UntrackConCommandBase(ConCommandBase *pBase, IConCommandTracker *me);
|
void UntrackConCommandBase(ConCommandBase *pBase, IConCommandTracker *me);
|
||||||
void Global_OnUnlinkConCommandBase(ConCommandBase *pBase);
|
void Global_OnUnlinkConCommandBase(ConCommandBase *pBase);
|
||||||
|
|
||||||
|
class IConCommandLinkListener
|
||||||
|
{
|
||||||
|
friend class ConCommandCleaner;
|
||||||
|
|
||||||
|
static IConCommandLinkListener *head;
|
||||||
|
IConCommandLinkListener *next;
|
||||||
|
public:
|
||||||
|
IConCommandLinkListener()
|
||||||
|
{
|
||||||
|
next = head;
|
||||||
|
head = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void OnLinkConCommand(ConCommandBase *pBase)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void OnUnlinkConCommand(ConCommandBase *pBase)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif //_INCLUDE_CONCMD_TRACKER_H_
|
#endif //_INCLUDE_CONCMD_TRACKER_H_
|
||||||
|
@ -142,6 +142,7 @@
|
|||||||
<Tool
|
<Tool
|
||||||
Name="VCResourceCompilerTool"
|
Name="VCResourceCompilerTool"
|
||||||
PreprocessorDefinitions="BINARY_NAME=\"$(TargetFileName)\""
|
PreprocessorDefinitions="BINARY_NAME=\"$(TargetFileName)\""
|
||||||
|
AdditionalIncludeDirectories="..\..\public"
|
||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCPreLinkEventTool"
|
Name="VCPreLinkEventTool"
|
||||||
@ -389,6 +390,7 @@
|
|||||||
<Tool
|
<Tool
|
||||||
Name="VCResourceCompilerTool"
|
Name="VCResourceCompilerTool"
|
||||||
PreprocessorDefinitions="BINARY_NAME=\"$(TargetFileName)\""
|
PreprocessorDefinitions="BINARY_NAME=\"$(TargetFileName)\""
|
||||||
|
AdditionalIncludeDirectories="..\..\public"
|
||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCPreLinkEventTool"
|
Name="VCPreLinkEventTool"
|
||||||
@ -1130,6 +1132,7 @@
|
|||||||
<Tool
|
<Tool
|
||||||
Name="VCResourceCompilerTool"
|
Name="VCResourceCompilerTool"
|
||||||
PreprocessorDefinitions="BINARY_NAME=\"$(TargetFileName)\""
|
PreprocessorDefinitions="BINARY_NAME=\"$(TargetFileName)\""
|
||||||
|
AdditionalIncludeDirectories="..\..\public"
|
||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCPreLinkEventTool"
|
Name="VCPreLinkEventTool"
|
||||||
@ -1377,6 +1380,7 @@
|
|||||||
<Tool
|
<Tool
|
||||||
Name="VCResourceCompilerTool"
|
Name="VCResourceCompilerTool"
|
||||||
PreprocessorDefinitions="BINARY_NAME=\"$(TargetFileName)\""
|
PreprocessorDefinitions="BINARY_NAME=\"$(TargetFileName)\""
|
||||||
|
AdditionalIncludeDirectories="..\..\public"
|
||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCPreLinkEventTool"
|
Name="VCPreLinkEventTool"
|
||||||
@ -1533,6 +1537,10 @@
|
|||||||
RelativePath="..\ConCmdManager.cpp"
|
RelativePath="..\ConCmdManager.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\ConsoleDetours.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\ConVarManager.cpp"
|
RelativePath="..\ConVarManager.cpp"
|
||||||
>
|
>
|
||||||
@ -1831,6 +1839,14 @@
|
|||||||
RelativePath="..\ConCmdManager.h"
|
RelativePath="..\ConCmdManager.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\ConCommandBaseIterator.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\ConsoleDetours.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\ConVarManager.h"
|
RelativePath="..\ConVarManager.h"
|
||||||
>
|
>
|
||||||
|
@ -1580,3 +1580,50 @@ char *UTIL_TrimWhitespace(char *str, size_t &len)
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t UTIL_DecodeHexString(unsigned char *buffer, size_t maxlength, const char *hexstr)
|
||||||
|
{
|
||||||
|
size_t written = 0;
|
||||||
|
size_t length = strlen(hexstr);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
if (written >= maxlength)
|
||||||
|
break;
|
||||||
|
buffer[written++] = hexstr[i];
|
||||||
|
if (hexstr[i] == '\\' && hexstr[i + 1] == 'x')
|
||||||
|
{
|
||||||
|
if (i + 3 >= length)
|
||||||
|
continue;
|
||||||
|
/* Get the hex part. */
|
||||||
|
char s_byte[3];
|
||||||
|
int r_byte;
|
||||||
|
s_byte[0] = hexstr[i + 2];
|
||||||
|
s_byte[1] = hexstr[i + 3];
|
||||||
|
s_byte[2] = '\0';
|
||||||
|
/* Read it as an integer */
|
||||||
|
sscanf(s_byte, "%x", &r_byte);
|
||||||
|
/* Save the value */
|
||||||
|
buffer[written - 1] = r_byte;
|
||||||
|
/* Adjust index */
|
||||||
|
i += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *UTIL_ToLowerCase(const char *str)
|
||||||
|
{
|
||||||
|
size_t len = strlen(str);
|
||||||
|
char *buffer = new char[len + 1];
|
||||||
|
for (size_t i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
if (str[i] >= 'A' && str[i] <= 'Z')
|
||||||
|
buffer[i] = tolower(str[i]);
|
||||||
|
else
|
||||||
|
buffer[i] = str[i];
|
||||||
|
}
|
||||||
|
buffer[len] = '\0';
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -60,5 +60,8 @@ char *sm_strdup(const char *str);
|
|||||||
unsigned int UTIL_ReplaceAll(char *subject, size_t maxlength, const char *search, const char *replace, bool caseSensitive = true);
|
unsigned int UTIL_ReplaceAll(char *subject, size_t maxlength, const char *search, const char *replace, bool caseSensitive = true);
|
||||||
char *UTIL_ReplaceEx(char *subject, size_t maxLen, const char *search, size_t searchLen, const char *replace, size_t replaceLen, bool caseSensitive = true);
|
char *UTIL_ReplaceEx(char *subject, size_t maxLen, const char *search, size_t searchLen, const char *replace, size_t replaceLen, bool caseSensitive = true);
|
||||||
char *UTIL_TrimWhitespace(char *str, size_t &len);
|
char *UTIL_TrimWhitespace(char *str, size_t &len);
|
||||||
|
size_t UTIL_DecodeHexString(unsigned char *buffer, size_t maxlength, const char *hexstr);
|
||||||
|
char *UTIL_ToLowerCase(const char *str);
|
||||||
|
|
||||||
#endif // _INCLUDE_SOURCEMOD_STRINGUTIL_H_
|
#endif // _INCLUDE_SOURCEMOD_STRINGUTIL_H_
|
||||||
|
|
||||||
|
@ -43,6 +43,8 @@
|
|||||||
#include <inetchannel.h>
|
#include <inetchannel.h>
|
||||||
#include <bitbuf.h>
|
#include <bitbuf.h>
|
||||||
#include <sm_trie_tpl.h>
|
#include <sm_trie_tpl.h>
|
||||||
|
#include "Logger.h"
|
||||||
|
#include "ConsoleDetours.h"
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
||||||
#define NET_SETCONVAR 6
|
#define NET_SETCONVAR 6
|
||||||
@ -668,7 +670,7 @@ static cell_t sm_RegServerCmd(IPluginContext *pContext, const cell_t *params)
|
|||||||
|
|
||||||
if (strcasecmp(name, "sm") == 0)
|
if (strcasecmp(name, "sm") == 0)
|
||||||
{
|
{
|
||||||
return pContext->ThrowNativeError("Cannot override \"sm\" command");
|
return pContext->ThrowNativeError("Cannot register \"sm\" command");
|
||||||
}
|
}
|
||||||
|
|
||||||
pContext->LocalToString(params[3], &help);
|
pContext->LocalToString(params[3], &help);
|
||||||
@ -696,7 +698,7 @@ static cell_t sm_RegConsoleCmd(IPluginContext *pContext, const cell_t *params)
|
|||||||
|
|
||||||
if (strcasecmp(name, "sm") == 0)
|
if (strcasecmp(name, "sm") == 0)
|
||||||
{
|
{
|
||||||
return pContext->ThrowNativeError("Cannot override \"sm\" command");
|
return pContext->ThrowNativeError("Cannot register \"sm\" command");
|
||||||
}
|
}
|
||||||
|
|
||||||
pContext->LocalToString(params[3], &help);
|
pContext->LocalToString(params[3], &help);
|
||||||
@ -727,7 +729,7 @@ static cell_t sm_RegAdminCmd(IPluginContext *pContext, const cell_t *params)
|
|||||||
|
|
||||||
if (strcasecmp(name, "sm") == 0)
|
if (strcasecmp(name, "sm") == 0)
|
||||||
{
|
{
|
||||||
return pContext->ThrowNativeError("Cannot override \"sm\" command");
|
return pContext->ThrowNativeError("Cannot register \"sm\" command");
|
||||||
}
|
}
|
||||||
|
|
||||||
pContext->LocalToString(params[4], &help);
|
pContext->LocalToString(params[4], &help);
|
||||||
@ -1332,6 +1334,46 @@ static cell_t RemoveServerTag(IPluginContext *pContext, const cell_t *params)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static cell_t AddCommandListener(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
IPluginFunction *pFunction;
|
||||||
|
|
||||||
|
pContext->LocalToString(params[2], &name);
|
||||||
|
|
||||||
|
if (strcasecmp(name, "sm") == 0)
|
||||||
|
{
|
||||||
|
g_Logger.LogError("Request to register \"sm\" command denied.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pFunction = pContext->GetFunctionById(params[1]);
|
||||||
|
|
||||||
|
if (!pFunction)
|
||||||
|
return pContext->ThrowNativeError("Invalid function id (%X)", params[1]);
|
||||||
|
|
||||||
|
if (!g_ConsoleDetours.AddListener(pFunction, name[0] == '\0' ? NULL : name))
|
||||||
|
return pContext->ThrowNativeError("This game does not support command listeners");
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cell_t RemoveCommandListener(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
IPluginFunction *pFunction;
|
||||||
|
|
||||||
|
pContext->LocalToString(params[2], &name);
|
||||||
|
pFunction = pContext->GetFunctionById(params[1]);
|
||||||
|
if (!pFunction)
|
||||||
|
return pContext->ThrowNativeError("Invalid function id (%X)", params[1]);
|
||||||
|
|
||||||
|
if (!g_ConsoleDetours.RemoveListener(pFunction, name[0] == '\0' ? NULL : name))
|
||||||
|
return pContext->ThrowNativeError("No matching callback was registered");
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
REGISTER_NATIVES(consoleNatives)
|
REGISTER_NATIVES(consoleNatives)
|
||||||
{
|
{
|
||||||
{"CreateConVar", sm_CreateConVar},
|
{"CreateConVar", sm_CreateConVar},
|
||||||
@ -1381,5 +1423,7 @@ REGISTER_NATIVES(consoleNatives)
|
|||||||
{"SendConVarValue", SendConVarValue},
|
{"SendConVarValue", SendConVarValue},
|
||||||
{"AddServerTag", AddServerTag},
|
{"AddServerTag", AddServerTag},
|
||||||
{"RemoveServerTag", RemoveServerTag},
|
{"RemoveServerTag", RemoveServerTag},
|
||||||
|
{"AddCommandListener", AddCommandListener},
|
||||||
|
{"RemoveCommandListener", RemoveCommandListener},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
@ -45,6 +45,41 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"Keys"
|
||||||
|
{
|
||||||
|
/* Windows */
|
||||||
|
"CES_Patch_Windows" "\xFF\x52\x2C\x5B\x5F\x8B\xC6"
|
||||||
|
"CES_Offset_Windows" "530"
|
||||||
|
"CES_Save_Windows" "3"
|
||||||
|
"CES_Reg_Windows" "1"
|
||||||
|
"CGC_Patch_Windows" "\xFF\x50\x2C\x5F\xB0\x01"
|
||||||
|
"CGC_Offset_Windows" "190"
|
||||||
|
"CGC_Save_Windows" "3"
|
||||||
|
"CGC_Reg_Windows" "1"
|
||||||
|
|
||||||
|
/* Linux i486 */
|
||||||
|
"CES_Patch_Linux_486" "\x89\x1C\x24\xFF\x52\x30"
|
||||||
|
"CES_Offset_Linux_486" "901"
|
||||||
|
"CES_Reg_Linux_486" "3"
|
||||||
|
"CGC_Patch_Linux_486" "\xFF\x57\x30\xBA\x01\x00\x00"
|
||||||
|
"CGC_Offset_Linux_486" "391"
|
||||||
|
|
||||||
|
/* Linux i686 */
|
||||||
|
"CES_Patch_Linux_686" "\x89\x1C\x24\xFF\x52\x30"
|
||||||
|
"CES_Offset_Linux_686" "901"
|
||||||
|
"CES_Reg_Linux_686" "3"
|
||||||
|
"CGC_Patch_Linux_686" "\xFF\x57\x30\xBA\x01\x00\x00"
|
||||||
|
"CGC_Offset_Linux_686" "391"
|
||||||
|
|
||||||
|
/* Linux AMD */
|
||||||
|
"CES_Patch_Linux_AMD" "\xFF\x52\x30\x89\xDA\x83\xC4\x10"
|
||||||
|
"CES_Offset_Linux_AMD" "916"
|
||||||
|
"CES_Save_Linux_AMD" "3"
|
||||||
|
"CGC_Patch_Linux_AMD" "\x89\x1C\x24\xFF\x52\x30"
|
||||||
|
"CGC_Offset_Linux_AMD" "380"
|
||||||
|
"CGC_Reg_Linux_AMD" "3"
|
||||||
|
}
|
||||||
|
|
||||||
"Signatures"
|
"Signatures"
|
||||||
{
|
{
|
||||||
"LevelShutdown"
|
"LevelShutdown"
|
||||||
@ -52,11 +87,27 @@
|
|||||||
"library" "server"
|
"library" "server"
|
||||||
"windows" "\xE8\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\xB9\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\xE8"
|
"windows" "\xE8\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\xB9\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\xE8"
|
||||||
}
|
}
|
||||||
|
|
||||||
"gEntList"
|
"gEntList"
|
||||||
{
|
{
|
||||||
"library" "server"
|
"library" "server"
|
||||||
"linux" "@gEntList"
|
"linux" "@gEntList"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"Cmd_ExecuteString"
|
||||||
|
{
|
||||||
|
"library" "engine"
|
||||||
|
"linux" "@_Z17Cmd_ExecuteStringPKc12cmd_source_t"
|
||||||
|
"windows" "\x8B\x4C\x24\x04\x8B\x44\x24\x08\x51\xA3\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\x83\xC4\x04\x83\x3D"
|
||||||
|
}
|
||||||
|
|
||||||
|
"CGameClient::ExecuteString"
|
||||||
|
{
|
||||||
|
"library" "engine"
|
||||||
|
"linux" "@_ZN11CGameClient20ExecuteStringCommandEPKc"
|
||||||
|
"windows" "\x56\x8B\x74\x24\x08\x57\x56\x8B\xF9\xE8\x2A\x2A\x2A\x2A\x84\xC0\x0F\x85\xC4\x00\x00\x00\x56\x8D"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -835,3 +835,52 @@ native AddServerTag(const String:tag[]);
|
|||||||
* @noreturn
|
* @noreturn
|
||||||
*/
|
*/
|
||||||
native RemoveServerTag(const String:tag[]);
|
native RemoveServerTag(const String:tag[]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for command listeners. This is invoked whenever any command
|
||||||
|
* reaches the server, from the server console itself or a player.
|
||||||
|
|
||||||
|
* Returning Plugin_Handled or Plugin_Stop will prevent the original,
|
||||||
|
* baseline code from running.
|
||||||
|
*
|
||||||
|
* -- TEXT BELOW IS IMPLEMENTATION, AND NOT GUARANTEED --
|
||||||
|
* Even if returning Plugin_Handled or Plugin_Stop, some callbacks will still
|
||||||
|
* trigger. These are:
|
||||||
|
* * C++ command dispatch hooks from Metamod:Source plugins
|
||||||
|
* * Reg*Cmd() hooks that did not create new commands.
|
||||||
|
*
|
||||||
|
* @param client Client, or 0 for server. Client will be connected but
|
||||||
|
* not necessarily in game.
|
||||||
|
* @param command Command name, lower case. To get name as typed, use
|
||||||
|
* GetCmdArg() and specify argument 0.
|
||||||
|
* @param argc Argument count.
|
||||||
|
* @return Action to take (see extended notes above).
|
||||||
|
*/
|
||||||
|
functag public Action:CommandListener(client, const String:command[], argc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a callback that will fire when a command is sent to the server.
|
||||||
|
*
|
||||||
|
* Registering commands is designed to create a new command as part of the UI,
|
||||||
|
* whereas this is a lightweight hook on a command string, existing or not.
|
||||||
|
* Using Reg*Cmd to intercept is in poor practice, as it physically creates a
|
||||||
|
* new command and can slow down dispatch in general.
|
||||||
|
*
|
||||||
|
* @param callback Callback.
|
||||||
|
* @param command Command, or if not specified, a global listener.
|
||||||
|
* The command is case insensitive.
|
||||||
|
* @return True if this feature is available on the current game,
|
||||||
|
* false otherwise.
|
||||||
|
*/
|
||||||
|
native bool:AddCommandListener(CommandListener:callback, const String:command[]="");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a previously added command listener, in reverse order of being added.
|
||||||
|
*
|
||||||
|
* @param callback Callback.
|
||||||
|
* @param command Command, or if not specified, a global listener.
|
||||||
|
* The command is case insensitive.
|
||||||
|
* @error Callback has no active listeners.
|
||||||
|
*/
|
||||||
|
native RemoveCommandListener(CommandListener:callback, const String:command[]="");
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user