initial import of sdktools extension. we're missing some of the calling mechanisms and linux tests/support!
--HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40956
This commit is contained in:
parent
c133002c14
commit
bdf651634c
@ -22,6 +22,7 @@
|
||||
*/
|
||||
|
||||
#include "extension.h"
|
||||
#include "vcallbuilder.h"
|
||||
|
||||
/**
|
||||
* @file extension.cpp
|
||||
@ -31,19 +32,42 @@
|
||||
SDKTools g_SdkTools; /**< Global singleton for extension's main interface */
|
||||
IServerGameEnts *gameents = NULL;
|
||||
IBinTools *g_pBinTools = NULL;
|
||||
IPlayerManager *g_pPlayers = NULL;
|
||||
IGameConfig *g_pGameConf = NULL;
|
||||
HandleType_t g_CallHandle = 0;
|
||||
|
||||
SMEXT_LINK(&g_SdkTools);
|
||||
|
||||
extern sp_nativeinfo_t g_CallNatives[];
|
||||
|
||||
bool SDKTools::SDK_OnLoad(char *error, size_t maxlength, bool late)
|
||||
{
|
||||
SM_GET_IFACE(PLAYERMANAGER, g_pPlayers);
|
||||
sharesys->AddDependency(myself, "bintools.ext", true, true);
|
||||
sharesys->AddNatives(myself, g_CallNatives);
|
||||
|
||||
g_pShareSys->AddDependency(myself, "bintools.ext", true, true);
|
||||
if (!gameconfs->LoadGameConfigFile("sdktools.games", &g_pGameConf, error, maxlength))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
g_CallHandle = handlesys->CreateType("ValveCall", this, 0, NULL, NULL, myself->GetIdentity(), NULL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SDKTools::OnHandleDestroy(HandleType_t type, void *object)
|
||||
{
|
||||
if (type == g_CallHandle)
|
||||
{
|
||||
ValveCall *v = (ValveCall *)object;
|
||||
delete v;
|
||||
}
|
||||
}
|
||||
|
||||
void SDKTools::SDK_OnUnload()
|
||||
{
|
||||
gameconfs->CloseGameConfigFile(g_pGameConf);
|
||||
}
|
||||
|
||||
bool SDKTools::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late)
|
||||
{
|
||||
GET_V_IFACE_CURRENT(serverFactory, gameents, IServerGameEnts, INTERFACEVERSION_SERVERGAMEENTS);
|
||||
|
@ -37,80 +37,27 @@
|
||||
* @brief Implementation of the SDK Tools extension.
|
||||
* Note: Uncomment one of the pre-defined virtual functions in order to use it.
|
||||
*/
|
||||
class SDKTools : public SDKExtension
|
||||
class SDKTools : public SDKExtension, public IHandleTypeDispatch
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief This is called after the initial loading sequence has been processed.
|
||||
*
|
||||
* @param error Error message buffer.
|
||||
* @param maxlength Size of error message buffer.
|
||||
* @param late Whether or not the module was loaded after map load.
|
||||
* @return True to succeed loading, false to fail.
|
||||
*/
|
||||
void OnHandleDestroy(HandleType_t type, void *object);
|
||||
public:
|
||||
virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late);
|
||||
|
||||
/**
|
||||
* @brief This is called right before the extension is unloaded.
|
||||
*/
|
||||
//virtual void SDK_OnUnload();
|
||||
|
||||
/**
|
||||
* @brief This is called once all known extensions have been loaded.
|
||||
* Note: It is is a good idea to add natives here, if any are provided.
|
||||
*/
|
||||
virtual void SDK_OnUnload();
|
||||
virtual void SDK_OnAllLoaded();
|
||||
|
||||
/**
|
||||
* @brief Called when the pause state is changed.
|
||||
*/
|
||||
//virtual void SDK_OnPauseChange(bool paused);
|
||||
|
||||
/**
|
||||
* @brief this is called when Core wants to know if your extension is working.
|
||||
*
|
||||
* @param error Error message buffer.
|
||||
* @param maxlength Size of error message buffer.
|
||||
* @return True if working, false otherwise.
|
||||
*/
|
||||
virtual bool QueryRunning(char *error, size_t maxlength);
|
||||
public:
|
||||
#if defined SMEXT_CONF_METAMOD
|
||||
/**
|
||||
* @brief Called when Metamod is attached, before the extension version is called.
|
||||
*
|
||||
* @param error Error buffer.
|
||||
* @param maxlength Maximum size of error buffer.
|
||||
* @param late Whether or not Metamod considers this a late load.
|
||||
* @return True to succeed, false to fail.
|
||||
*/
|
||||
virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late);
|
||||
|
||||
/**
|
||||
* @brief Called when Metamod is detaching, after the extension version is called.
|
||||
* NOTE: By default this is blocked unless sent from SourceMod.
|
||||
*
|
||||
* @param error Error buffer.
|
||||
* @param maxlength Maximum size of error buffer.
|
||||
* @return True to succeed, false to fail.
|
||||
*/
|
||||
//virtual bool SDK_OnMetamodUnload(char *error, size_t maxlen);
|
||||
|
||||
/**
|
||||
* @brief Called when Metamod's pause state is changing.
|
||||
* NOTE: By default this is blocked unless sent from SourceMod.
|
||||
*
|
||||
* @param paused Pause state being set.
|
||||
* @param error Error buffer.
|
||||
* @param maxlength Maximum size of error buffer.
|
||||
* @return True to succeed, false to fail.
|
||||
*/
|
||||
//virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlen);
|
||||
#endif
|
||||
};
|
||||
|
||||
extern IServerGameEnts *gameents;
|
||||
extern IBinTools *g_pBinTools;
|
||||
extern IPlayerManager *g_pPlayers;
|
||||
extern IGameConfig *g_pGameConf;
|
||||
extern HandleType_t g_CallHandle;
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
|
||||
|
@ -62,6 +62,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="vstdlib.lib tier0.lib tier1.lib"
|
||||
OutputFile="$(OutDir)\sdktools.ext.dll"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
@ -184,6 +185,18 @@
|
||||
RelativePath="..\extension.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\vcallbuilder.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\vcaller.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\vdecoder.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
@ -194,6 +207,14 @@
|
||||
RelativePath="..\extension.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\vcallbuilder.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\vdecoder.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
|
@ -26,7 +26,7 @@
|
||||
|
||||
/* Basic information exposed publicly */
|
||||
#define SMEXT_CONF_NAME "SDK Tools"
|
||||
#define SMEXT_CONF_DESCRIPTION "Sample extension to help developers" /* :TODO: Describe this, heh */
|
||||
#define SMEXT_CONF_DESCRIPTION "Source SDK Tools"
|
||||
#define SMEXT_CONF_VERSION "0.0.0.0"
|
||||
#define SMEXT_CONF_AUTHOR "AlliedModders"
|
||||
#define SMEXT_CONF_URL "http://www.sourcemod.net/"
|
||||
@ -45,4 +45,12 @@
|
||||
*/
|
||||
#define SMEXT_CONF_METAMOD
|
||||
|
||||
/** Enable interfaces you want to use here by uncommenting lines */
|
||||
//#define SMEXT_ENABLE_FORWARDSYS
|
||||
#define SMEXT_ENABLE_HANDLESYS
|
||||
#define SMEXT_ENABLE_PLAYERHELPERS
|
||||
//#define SMEXT_ENABLE_DBMANAGER
|
||||
#define SMEXT_ENABLE_GAMECONF
|
||||
#define SMEXT_ENABLE_MEMUTILS
|
||||
|
||||
#endif // _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_
|
||||
|
@ -25,11 +25,32 @@
|
||||
* @brief Contains wrappers for making Extensions easier to write.
|
||||
*/
|
||||
|
||||
IShareSys *g_pShareSys = NULL; /**< Share system */
|
||||
IExtension *myself = NULL; /**< Ourself */
|
||||
IHandleSys *g_pHandleSys = NULL; /**< Handle system */
|
||||
IShareSys *g_pShareSys = NULL; /**< Share system */
|
||||
IShareSys *sharesys = NULL; /**< Share system */
|
||||
ISourceMod *g_pSM = NULL; /**< SourceMod helpers */
|
||||
ISourceMod *smutils = NULL; /**< SourceMod helpers */
|
||||
|
||||
#if defined SMEXT_ENABLE_FORWARDSYS
|
||||
IForwardManager *g_pForwards = NULL; /**< Forward system */
|
||||
IForwardManager *forwards = NULL; /**< Forward system */
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_HANDLESYS
|
||||
IHandleSys *g_pHandleSys = NULL; /**< Handle system */
|
||||
IHandleSys *handlesys = NULL; /**< Handle system */
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_PLAYERHELPERS
|
||||
IPlayerManager *playerhelpers = NULL; /**< Player helpers */
|
||||
#endif //SMEXT_ENABLE_PLAYERHELPERS
|
||||
#if defined SMEXT_ENABLE_DBMANAGER
|
||||
IDBManager *dbi = NULL; /**< DB Manager */
|
||||
#endif //SMEXT_ENABLE_DBMANAGER
|
||||
#if defined SMEXT_ENABLE_GAMECONF
|
||||
IGameConfigManager *gameconfs = NULL; /**< Game config manager */
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_MEMUTILS
|
||||
IMemoryUtils *memutils = NULL;
|
||||
#endif
|
||||
|
||||
/** Exports the main interface */
|
||||
PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI()
|
||||
@ -48,7 +69,7 @@ SDKExtension::SDKExtension()
|
||||
|
||||
bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t maxlength, bool late)
|
||||
{
|
||||
g_pShareSys = sys;
|
||||
g_pShareSys = sharesys = sys;
|
||||
myself = me;
|
||||
|
||||
#if defined SMEXT_CONF_METAMOD
|
||||
@ -63,10 +84,28 @@ bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error,
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
SM_GET_IFACE(HANDLESYSTEM, g_pHandleSys);
|
||||
SM_GET_IFACE(SOURCEMOD, g_pSM);
|
||||
smutils = g_pSM;
|
||||
#if defined SMEXT_ENABLE_HANDLESYS
|
||||
SM_GET_IFACE(HANDLESYSTEM, g_pHandleSys);
|
||||
handlesys = g_pHandleSys;
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_FORWARDSYS
|
||||
SM_GET_IFACE(FORWARDMANAGER, g_pForwards);
|
||||
forwards = g_pForwards;
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_PLAYERHELPERS
|
||||
SM_GET_IFACE(PLAYERMANAGER, playerhelpers);
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_DBMANAGER
|
||||
SM_GET_IFACE(DBI, dbi);
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_GAMECONF
|
||||
SM_GET_IFACE(GAMECONFIG, gameconfs);
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_MEMUTILS
|
||||
SM_GET_IFACE(MEMORYUTILS, memutils);
|
||||
#endif
|
||||
|
||||
if (SDK_OnLoad(error, maxlength, late))
|
||||
{
|
||||
|
@ -30,7 +30,21 @@
|
||||
#include <sp_vm_api.h>
|
||||
#include <sm_platform.h>
|
||||
#include <ISourceMod.h>
|
||||
#if defined SMEXT_ENABLE_FORWARDSYS
|
||||
#include <IForwardSys.h>
|
||||
#endif //SMEXT_ENABLE_FORWARDSYS
|
||||
#if defined SMEXT_ENABLE_PLAYERHELPERS
|
||||
#include <IPlayerHelpers.h>
|
||||
#endif //SMEXT_ENABLE_PlAYERHELPERS
|
||||
#if defined SMEXT_ENABLE_DBMANAGER
|
||||
#include <IDBDriver.h>
|
||||
#endif //SMEXT_ENABLE_DBMANAGER
|
||||
#if defined SMEXT_ENABLE_GAMECONF
|
||||
#include <IGameConfigs.h>
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_MEMUTILS
|
||||
#include <IMemoryUtils.h>
|
||||
#endif
|
||||
|
||||
#if defined SMEXT_CONF_METAMOD
|
||||
#include <ISmmPlugin.h>
|
||||
@ -108,7 +122,7 @@ public:
|
||||
virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength);
|
||||
#endif
|
||||
|
||||
public: // IExtensionInterface
|
||||
public: //IExtensionInterface
|
||||
virtual bool OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t maxlength, bool late);
|
||||
virtual void OnExtensionUnload();
|
||||
virtual void OnExtensionsAllLoaded();
|
||||
@ -138,9 +152,9 @@ public: // IExtensionInterface
|
||||
/** Returns date string */
|
||||
virtual const char *GetExtensionDateString();
|
||||
#if defined SMEXT_CONF_METAMOD
|
||||
public: // ISmmPlugin
|
||||
public: //ISmmPlugin
|
||||
/** Called when the extension is attached to Metamod. */
|
||||
virtual bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late);
|
||||
virtual bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlength, bool late);
|
||||
/** Returns the author to MM */
|
||||
virtual const char *GetAuthor();
|
||||
/** Returns the name to MM */
|
||||
@ -158,11 +172,11 @@ public: // ISmmPlugin
|
||||
/** Returns the logtag to MM */
|
||||
virtual const char *GetLogTag();
|
||||
/** Called on unload */
|
||||
virtual bool Unload(char *error, size_t maxlen);
|
||||
virtual bool Unload(char *error, size_t maxlength);
|
||||
/** Called on pause */
|
||||
virtual bool Pause(char *error, size_t maxlen);
|
||||
virtual bool Pause(char *error, size_t maxlength);
|
||||
/** Called on unpause */
|
||||
virtual bool Unpause(char *error, size_t maxlen);
|
||||
virtual bool Unpause(char *error, size_t maxlength);
|
||||
private:
|
||||
bool m_SourceMMLoaded;
|
||||
bool m_WeAreUnloaded;
|
||||
@ -171,12 +185,34 @@ private:
|
||||
};
|
||||
|
||||
extern SDKExtension *g_pExtensionIface;
|
||||
extern IExtension *myself;
|
||||
|
||||
extern IShareSys *g_pShareSys;
|
||||
extern IExtension *myself;
|
||||
extern IHandleSys *g_pHandleSys;
|
||||
extern IShareSys *sharesys; /* Note: Newer name */
|
||||
extern ISourceMod *g_pSM;
|
||||
extern ISourceMod *smutils; /* Note: Newer name */
|
||||
|
||||
/* Optional interfaces are below */
|
||||
#if defined SMEXT_ENABLE_FORWARDSYS
|
||||
extern IForwardManager *g_pForwards;
|
||||
extern IForwardManager *forwards; /* Note: Newer name */
|
||||
#endif //SMEXT_ENABLE_FORWARDSYS
|
||||
#if defined SMEXT_ENABLE_HANDLESYS
|
||||
extern IHandleSys *g_pHandleSys;
|
||||
extern IHandleSys *handlesys; /* Note: Newer name */
|
||||
#endif //SMEXT_ENABLE_HANDLESYS
|
||||
#if defined SMEXT_ENABLE_PLAYERHELPERS
|
||||
extern IPlayerManager *playerhelpers;
|
||||
#endif //SMEXT_ENABLE_PLAYERHELPERS
|
||||
#if defined SMEXT_ENABLE_DBMANAGER
|
||||
extern IDBManager *dbi;
|
||||
#endif //SMEXT_ENABLE_DBMANAGER
|
||||
#if defined SMEXT_ENABLE_GAMECONF
|
||||
extern IGameConfigManager *gameconfs;
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_MEMUTILS
|
||||
extern IMemoryUtils *memutils;
|
||||
#endif
|
||||
|
||||
#if defined SMEXT_CONF_METAMOD
|
||||
PLUGIN_GLOBALVARS();
|
||||
@ -192,7 +228,7 @@ extern IServerGameDLL *gamedll;
|
||||
{ \
|
||||
if (error) \
|
||||
{ \
|
||||
snprintf(error, maxlength, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \
|
||||
snprintf(error, maxlength, "Could not find interface: %s (version: %d)", SMINTERFACE_##prefix##_NAME, SMINTERFACE_##prefix##_VERSION); \
|
||||
return false; \
|
||||
} \
|
||||
}
|
||||
|
136
extensions/sdktools/vcallbuilder.cpp
Normal file
136
extensions/sdktools/vcallbuilder.cpp
Normal file
@ -0,0 +1,136 @@
|
||||
#include "vcallbuilder.h"
|
||||
#include "extension.h"
|
||||
|
||||
ValveCall::~ValveCall()
|
||||
{
|
||||
while (!stk.empty())
|
||||
{
|
||||
unsigned char *ptr = stk.front();
|
||||
delete [] ptr;
|
||||
stk.pop();
|
||||
}
|
||||
call->Destroy();
|
||||
delete [] retbuf;
|
||||
delete [] vparams;
|
||||
}
|
||||
|
||||
unsigned char *ValveCall::stk_get()
|
||||
{
|
||||
unsigned char *ptr;
|
||||
if (stk.empty())
|
||||
{
|
||||
ptr = new unsigned char[stackSize];
|
||||
} else {
|
||||
ptr = stk.front();
|
||||
stk.pop();
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void ValveCall::stk_put(unsigned char *ptr)
|
||||
{
|
||||
stk.push(ptr);
|
||||
}
|
||||
|
||||
ValveCall *CreateValveVCall(unsigned int vtableIdx,
|
||||
ValveCallType vcalltype,
|
||||
const ValvePassInfo *retInfo,
|
||||
const ValvePassInfo *params,
|
||||
unsigned int numParams)
|
||||
{
|
||||
if (numParams > 32)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ValveCall *vc = new ValveCall;
|
||||
|
||||
size_t size = 0;
|
||||
vc->stackSize = 0;
|
||||
|
||||
/* Get return information - encode only*/
|
||||
PassInfo retBuf;
|
||||
size_t retBufSize = 0;
|
||||
if (retInfo)
|
||||
{
|
||||
if ((size = ValveParamToBinParam(retInfo->vtype, retInfo->type, retInfo->flags, &retBuf)) == 0)
|
||||
{
|
||||
delete vc;
|
||||
return NULL;
|
||||
}
|
||||
retBufSize = size;
|
||||
}
|
||||
|
||||
/* Get parameter info */
|
||||
PassInfo paramBuf[32];
|
||||
for (unsigned int i=0; i<numParams; i++)
|
||||
{
|
||||
if ((size = ValveParamToBinParam(params[i].vtype, params[i].type, params[i].flags, ¶mBuf[i])) == 0)
|
||||
{
|
||||
delete vc;
|
||||
return NULL;
|
||||
}
|
||||
vc->stackSize += size;
|
||||
}
|
||||
|
||||
/* Now we can try creating the call */
|
||||
if ((vc->call = g_pBinTools->CreateVCall(vtableIdx,
|
||||
0,
|
||||
0,
|
||||
(retInfo ? &retBuf : NULL),
|
||||
paramBuf,
|
||||
numParams))
|
||||
== NULL)
|
||||
{
|
||||
if (!vc->call)
|
||||
{
|
||||
delete vc;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate extra space for thisptr AND ret buffer, even if we don't use it */
|
||||
vc->vparams = new ValvePassInfo[numParams + 2];
|
||||
|
||||
/* We've got the call and everything is encoded.
|
||||
* It's time to save the valve specific information and helper variables.
|
||||
*/
|
||||
if (retInfo)
|
||||
{
|
||||
/* Allocate and copy */
|
||||
vc->retinfo = &(vc->vparams[numParams]);
|
||||
*vc->retinfo = *retInfo;
|
||||
vc->retinfo->offset = 0;
|
||||
/* Allocate stack space */
|
||||
vc->retbuf = new unsigned char[retBufSize];
|
||||
} else {
|
||||
vc->retinfo = NULL;
|
||||
vc->retbuf = NULL;
|
||||
}
|
||||
|
||||
/* Save the this info for the dynamic decoder */
|
||||
vc->thisinfo = &(vc->vparams[numParams + 1]);
|
||||
vc->thisinfo->type = PassType_Basic;
|
||||
if (vcalltype == ValveCall_Entity)
|
||||
{
|
||||
vc->thisinfo->vtype = Valve_CBaseEntity;
|
||||
vc->thisinfo->decflags |= VDECODE_FLAG_ALLOWWORLD;
|
||||
} else if (vcalltype == ValveCall_Player) {
|
||||
vc->thisinfo->vtype = Valve_CBasePlayer;
|
||||
vc->thisinfo->decflags = 0;
|
||||
}
|
||||
vc->thisinfo->encflags = 0;
|
||||
vc->thisinfo->flags = PASSFLAG_BYVAL;
|
||||
vc->thisinfo->offset = 0;
|
||||
vc->stackSize += sizeof(void *);
|
||||
|
||||
/* Now, save info about each parameter. */
|
||||
for (unsigned int i=0; i<numParams; i++)
|
||||
{
|
||||
/* Copy */
|
||||
vc->vparams[i] = params[i];
|
||||
vc->vparams[i].offset = vc->call->GetParamInfo(i)->offset;
|
||||
}
|
||||
|
||||
return vc;
|
||||
}
|
58
extensions/sdktools/vcallbuilder.h
Normal file
58
extensions/sdktools/vcallbuilder.h
Normal file
@ -0,0 +1,58 @@
|
||||
#ifndef _INCLUDE_SOURCEMOD_VALVE_CALLER_H_
|
||||
#define _INCLUDE_SOURCEMOD_VALVE_CALLER_H_
|
||||
|
||||
#include <sh_stack.h>
|
||||
#include <extensions/IBinTools.h>
|
||||
#include "vdecoder.h"
|
||||
|
||||
using namespace SourceMod;
|
||||
using namespace SourceHook;
|
||||
|
||||
/**
|
||||
* @brief Valve pre-defined calling types
|
||||
*/
|
||||
enum ValveCallType
|
||||
{
|
||||
ValveCall_Static, /**< Static call */
|
||||
ValveCall_Entity, /**< Thiscall (CBaseEntity implicit first parameter) */
|
||||
ValveCall_Player, /**< Thiscall (CBasePlayer implicit first parameter) */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Valve parameter info
|
||||
*/
|
||||
struct ValvePassInfo
|
||||
{
|
||||
ValveType vtype; /**< IN: Valve type */
|
||||
unsigned int decflags; /**< IN: VDECODE_FLAG_* */
|
||||
unsigned int encflags; /**< IN: VENCODE_FLAG_* */
|
||||
PassType type; /**< IN: Pass information */
|
||||
unsigned int flags; /**< IN: Pass flags */
|
||||
size_t offset; /**< OUT: stack offset */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Info necessary to call a Valve function
|
||||
*/
|
||||
struct ValveCall
|
||||
{
|
||||
ICallWrapper *call; /**< From IBinTools */
|
||||
ValvePassInfo *vparams; /**< Valve parameter info */
|
||||
ValvePassInfo *retinfo; /**< Return buffer info */
|
||||
ValvePassInfo *thisinfo; /**< Thiscall info */
|
||||
size_t stackSize; /**< Stack size */
|
||||
unsigned char *retbuf; /**< Return buffer */
|
||||
CStack<unsigned char *> stk; /**< Parameter stack */
|
||||
|
||||
unsigned char *stk_get();
|
||||
void stk_put(unsigned char *ptr);
|
||||
~ValveCall();
|
||||
};
|
||||
|
||||
ValveCall *CreateValveVCall(unsigned int vtableIdx,
|
||||
ValveCallType vcalltype,
|
||||
const ValvePassInfo *retInfo,
|
||||
const ValvePassInfo *params,
|
||||
unsigned int numParams);
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_VALVE_CALLER_H_
|
376
extensions/sdktools/vcaller.cpp
Normal file
376
extensions/sdktools/vcaller.cpp
Normal file
@ -0,0 +1,376 @@
|
||||
#include "extension.h"
|
||||
#include "vcallbuilder.h"
|
||||
|
||||
enum SDKLibrary
|
||||
{
|
||||
SDKLibrary_Server, /**< server.dll/server_i486.so */
|
||||
SDKLibrary_Engine, /**< engine.dll/engine_*.so */
|
||||
};
|
||||
|
||||
enum SDKPassMethod
|
||||
{
|
||||
SDKPass_Pointer, /**< Pass as a pointer */
|
||||
SDKPass_Plain, /**< Pass as plain data */
|
||||
SDKPass_ByValue, /**< Pass an object by value */
|
||||
SDKPass_ByRef, /**< Pass an object by reference */
|
||||
};
|
||||
|
||||
int s_vtbl_index = 0;
|
||||
void *s_call_addr = NULL;
|
||||
ValveCallType s_vcalltype = ValveCall_Static;
|
||||
bool s_has_return = false;
|
||||
ValvePassInfo s_return;
|
||||
unsigned int s_numparams = 0;
|
||||
ValvePassInfo s_params[SP_MAX_EXEC_PARAMS];
|
||||
|
||||
inline void DecodePassMethod(ValveType vtype, SDKPassMethod method, PassType &type, unsigned int &flags)
|
||||
{
|
||||
if (method == SDKPass_Pointer)
|
||||
{
|
||||
type = PassType_Basic;
|
||||
if (vtype == Valve_POD
|
||||
|| vtype == Valve_Float)
|
||||
{
|
||||
flags = PASSFLAG_BYREF;
|
||||
} else {
|
||||
flags = PASSFLAG_BYVAL;
|
||||
}
|
||||
} else if (method == SDKPass_Plain) {
|
||||
type = PassType_Basic;
|
||||
flags = PASSFLAG_BYVAL;
|
||||
} else if (method == SDKPass_ByValue) {
|
||||
if (vtype == Valve_Vector
|
||||
|| vtype == Valve_QAngle)
|
||||
{
|
||||
type = PassType_Object;
|
||||
} else {
|
||||
type = PassType_Basic;
|
||||
}
|
||||
flags = PASSFLAG_BYVAL;
|
||||
} else if (method == SDKPass_ByRef) {
|
||||
if (vtype == Valve_Vector
|
||||
|| vtype == Valve_QAngle)
|
||||
{
|
||||
type = PassType_Object;
|
||||
} else {
|
||||
type = PassType_Basic;
|
||||
}
|
||||
flags = PASSFLAG_BYREF;
|
||||
}
|
||||
}
|
||||
|
||||
static cell_t StartPrepSDKCall(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
s_numparams = 0;
|
||||
s_vtbl_index = 0;
|
||||
s_call_addr = NULL;
|
||||
s_has_return = false;
|
||||
s_vcalltype = (ValveCallType)params[1];
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t PrepSDKCall_SetVirtual(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
s_vtbl_index = params[1];
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t PrepSDKCall_SetSignature(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
void *addrInBase = NULL;
|
||||
if (params[1] == SDKLibrary_Server)
|
||||
{
|
||||
addrInBase = g_SMAPI->serverFactory(false);
|
||||
} else if (params[1] == SDKLibrary_Engine) {
|
||||
addrInBase = g_SMAPI->engineFactory(false);
|
||||
}
|
||||
if (addrInBase == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *sig;
|
||||
pContext->LocalToString(params[2], &sig);
|
||||
|
||||
#if defined PLATFORM_LINUX
|
||||
if (sig[0] == '@')
|
||||
{
|
||||
Dl_info info;
|
||||
if (dladdr(addrInBase, &info) == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
void *handle = dlopen(info.dli_fname, RTLD_NOW);
|
||||
if (!handle)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
s_call_addr = dlsym(handle, &sig[1]);
|
||||
dlclose(handle);
|
||||
|
||||
return (s_call_addr != NULL) ? 1 : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
s_call_addr = memutils->FindPattern(addrInBase, sig, params[3]);
|
||||
|
||||
return (s_call_addr != NULL) ? 1 : 0;
|
||||
}
|
||||
|
||||
static cell_t PrepSDKCall_SetFromConf(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IGameConfig *conf;
|
||||
|
||||
if (params[1] == BAD_HANDLE)
|
||||
{
|
||||
conf = g_pGameConf;
|
||||
} else {
|
||||
HandleError err;
|
||||
if ((conf = gameconfs->ReadHandle(params[1], pContext->GetIdentity(), &err)) == NULL)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err);
|
||||
}
|
||||
}
|
||||
|
||||
char *key;
|
||||
pContext->LocalToString(params[3], &key);
|
||||
|
||||
if (params[2] == 0)
|
||||
{
|
||||
return conf->GetOffset(key, &s_vtbl_index) ? 1 : 0;
|
||||
} else if (params[2] == 1) {
|
||||
bool result = conf->GetMemSig(key, &s_call_addr) ? 1 : 0;
|
||||
return (result && s_call_addr != NULL) ? 1 : 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cell_t PrepSDKCall_SetReturnInfo(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
s_has_return = true;
|
||||
s_return.vtype = (ValveType)params[1];
|
||||
DecodePassMethod(s_return.vtype, (SDKPassMethod)params[2], s_return.type, s_return.flags);
|
||||
s_return.decflags = params[3];
|
||||
s_return.encflags = params[4];
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t PrepSDKCall_AddParameter(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
if (s_numparams >= SP_MAX_EXEC_PARAMS)
|
||||
{
|
||||
return pContext->ThrowNativeError("Parameter limit for SDK calls reached");
|
||||
}
|
||||
|
||||
ValvePassInfo *info = &s_params[s_numparams++];
|
||||
info->vtype = (ValveType)params[1];
|
||||
DecodePassMethod(info->vtype, (SDKPassMethod)params[2], info->type, info->flags);
|
||||
info->decflags = params[3];
|
||||
info->encflags = params[4];
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t EndPrepSDKCall(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
ValveCall *vc = NULL;
|
||||
if (s_vtbl_index)
|
||||
{
|
||||
vc = CreateValveVCall(s_vtbl_index, s_vcalltype, s_has_return ? &s_return : NULL, s_params, s_numparams);
|
||||
}
|
||||
|
||||
if (!vc)
|
||||
{
|
||||
return BAD_HANDLE;
|
||||
}
|
||||
|
||||
Handle_t hndl = handlesys->CreateHandle(g_CallHandle, vc, pContext->GetIdentity(), myself->GetIdentity(), NULL);
|
||||
if (!hndl)
|
||||
{
|
||||
delete vc;
|
||||
}
|
||||
|
||||
return hndl;
|
||||
}
|
||||
|
||||
static cell_t SDKCall(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
ValveCall *vc;
|
||||
HandleError err;
|
||||
HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
|
||||
|
||||
if ((err = handlesys->ReadHandle(params[1], g_CallHandle, &sec, (void **)&vc)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err);
|
||||
}
|
||||
|
||||
unsigned char *ptr = vc->stk_get();
|
||||
|
||||
unsigned int numparams = (unsigned)params[0];
|
||||
unsigned int startparam = 2;
|
||||
/* Do we need to write a thispointer? */
|
||||
|
||||
if (vc->thisinfo &&
|
||||
(vc->thisinfo->vtype == Valve_CBaseEntity
|
||||
|| vc->thisinfo->vtype == Valve_CBasePlayer))
|
||||
{
|
||||
if (startparam > numparams)
|
||||
{
|
||||
vc->stk_put(ptr);
|
||||
return pContext->ThrowNativeError("Expected 1 parameter for entity pointer; found none");
|
||||
}
|
||||
if (DecodeValveParam(pContext,
|
||||
params[startparam],
|
||||
vc->thisinfo->vtype,
|
||||
vc->thisinfo->decflags | VDECODE_FLAG_BYREF,
|
||||
vc->thisinfo->type,
|
||||
ptr) == Data_Fail)
|
||||
{
|
||||
vc->stk_put(ptr);
|
||||
return 0;
|
||||
}
|
||||
startparam++;
|
||||
}
|
||||
|
||||
/* See if we need to skip any more parameters */
|
||||
unsigned int retparam = startparam;
|
||||
if (vc->retinfo)
|
||||
{
|
||||
if (vc->retinfo->vtype == Valve_String)
|
||||
{
|
||||
startparam += 2;
|
||||
} else if (vc->retinfo->vtype == Valve_Vector
|
||||
|| vc->retinfo->vtype == Valve_QAngle)
|
||||
{
|
||||
startparam += 1;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int callparams = vc->call->GetParamCount();
|
||||
bool will_copyback = false;
|
||||
for (unsigned int i=0; i<callparams; i++)
|
||||
{
|
||||
unsigned int p = startparam + i;
|
||||
if (p > numparams)
|
||||
{
|
||||
vc->stk_put(ptr);
|
||||
return pContext->ThrowNativeError("Expected %dth parameter, found none", p);
|
||||
}
|
||||
if (DecodeValveParam(pContext,
|
||||
params[p],
|
||||
vc->vparams[i].vtype,
|
||||
vc->vparams[i].decflags | VDECODE_FLAG_BYREF,
|
||||
vc->vparams[i].type,
|
||||
ptr + vc->vparams[i].offset) == Data_Fail)
|
||||
{
|
||||
vc->stk_put(ptr);
|
||||
return 0;
|
||||
}
|
||||
if (vc->vparams[i].encflags & VENCODE_FLAG_COPYBACK)
|
||||
{
|
||||
will_copyback = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make the actual call */
|
||||
vc->call->Execute(ptr, vc->retbuf);
|
||||
|
||||
/* Do we need to copy anything back? */
|
||||
if (will_copyback)
|
||||
{
|
||||
for (unsigned int i=0; i<callparams; i++)
|
||||
{
|
||||
if (vc->vparams[i].encflags & VENCODE_FLAG_COPYBACK)
|
||||
{
|
||||
if (EncodeValveParam(pContext,
|
||||
startparam + i,
|
||||
vc->vparams[i].vtype,
|
||||
vc->vparams[i].type,
|
||||
ptr + vc->vparams[i].offset) == Data_Fail)
|
||||
{
|
||||
vc->stk_put(ptr);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Save stack once and for all */
|
||||
vc->stk_put(ptr);
|
||||
|
||||
/* Figure out how to decode the return information */
|
||||
if (vc->retinfo)
|
||||
{
|
||||
if (vc->retinfo->vtype == Valve_String)
|
||||
{
|
||||
if (numparams < 3)
|
||||
{
|
||||
return pContext->ThrowNativeError("Expected arguments (2,3) for string storage");
|
||||
}
|
||||
cell_t *addr;
|
||||
size_t written;
|
||||
pContext->LocalToPhysAddr(params[retparam+1], &addr);
|
||||
pContext->StringToLocalUTF8(params[retparam], *addr, *(char **)vc->retbuf, &written);
|
||||
return (cell_t)written;
|
||||
} else if (vc->retinfo->vtype == Valve_Vector
|
||||
|| vc->retinfo->vtype == Valve_QAngle)
|
||||
{
|
||||
if (numparams < 2)
|
||||
{
|
||||
return pContext->ThrowNativeError("Expected argument (2) for Float[3] storage");
|
||||
}
|
||||
if (EncodeValveParam(pContext, params[retparam], vc->retinfo->vtype, vc->retinfo->type, vc->retbuf)
|
||||
== Data_Fail)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
} else if (vc->retinfo->vtype == Valve_CBaseEntity
|
||||
|| vc->retinfo->vtype == Valve_CBasePlayer)
|
||||
{
|
||||
CBaseEntity *pEntity = *(CBaseEntity **)(vc->retbuf);
|
||||
if (!pEntity)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
edict_t *pEdict = gameents->BaseEntityToEdict(pEntity);
|
||||
if (!pEdict || pEdict->IsFree())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return engine->IndexOfEdict(pEdict);
|
||||
} else if (vc->retinfo->vtype == Valve_Edict) {
|
||||
edict_t *pEdict = *(edict_t **)(vc->retbuf);
|
||||
if (!pEdict || pEdict->IsFree())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return engine->IndexOfEdict(pEdict);
|
||||
} else {
|
||||
cell_t *addr = (cell_t *)vc->retbuf;
|
||||
if (vc->retinfo->flags & PASSFLAG_BYREF)
|
||||
{
|
||||
addr = *(cell_t **)addr;
|
||||
}
|
||||
return *addr;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sp_nativeinfo_t g_CallNatives[] =
|
||||
{
|
||||
{"StartPrepSDKCall", StartPrepSDKCall},
|
||||
{"PrepSDKCall_SetVirtual", PrepSDKCall_SetVirtual},
|
||||
{"PrepSDKCall_SetSignature", PrepSDKCall_SetSignature},
|
||||
{"PrepSDKCall_SetFromConf", PrepSDKCall_SetFromConf},
|
||||
{"PrepSDKCall_SetReturnInfo", PrepSDKCall_SetReturnInfo},
|
||||
{"PrepSDKCall_AddParameter", PrepSDKCall_AddParameter},
|
||||
{"EndPrepSDKCall", EndPrepSDKCall},
|
||||
{"SDKCall", SDKCall},
|
||||
{NULL, NULL},
|
||||
};
|
505
extensions/sdktools/vdecoder.cpp
Normal file
505
extensions/sdktools/vdecoder.cpp
Normal file
@ -0,0 +1,505 @@
|
||||
#include "smsdk_ext.h"
|
||||
#include "extension.h"
|
||||
#include "vdecoder.h"
|
||||
|
||||
using namespace SourceMod;
|
||||
using namespace SourcePawn;
|
||||
|
||||
/**
|
||||
* For object pointers, the data looks like this instead:
|
||||
* 4 bytes: POINTER TO NEXT FOUR BYTES
|
||||
* + bytes: Object internal data
|
||||
*
|
||||
* We use the virtual stack as extra fake stack space and create a temp object.
|
||||
* If these objects had destructors, we'd need to fake destroy toom of course.
|
||||
* Of course, BinTools only reads the first four bytes and passes the pointer.
|
||||
*/
|
||||
|
||||
size_t ValveParamToBinParam(ValveType type,
|
||||
PassType pass,
|
||||
unsigned int flags,
|
||||
PassInfo *info)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Valve_Vector:
|
||||
{
|
||||
size_t mySize = sizeof(Vector *);
|
||||
if (pass == PassType_Basic)
|
||||
{
|
||||
if (info->flags & PASSFLAG_BYREF)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
info->type = PassType_Basic;
|
||||
info->flags = flags;
|
||||
info->size = sizeof(Vector *);
|
||||
mySize += sizeof(Vector);
|
||||
} else if (pass == PassType_Object) {
|
||||
info->type = PassType_Object;
|
||||
info->flags = flags | PASSFLAG_OASSIGNOP | PASSFLAG_OCTOR;
|
||||
info->size = sizeof(Vector);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return mySize;
|
||||
}
|
||||
case Valve_QAngle:
|
||||
{
|
||||
size_t mySize = sizeof(QAngle *);
|
||||
if (pass == PassType_Basic)
|
||||
{
|
||||
if (info->flags & PASSFLAG_BYREF)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
info->type = PassType_Basic;
|
||||
info->flags = flags;
|
||||
info->size = sizeof(QAngle *);
|
||||
mySize += sizeof(QAngle);
|
||||
} else if (pass == PassType_Object) {
|
||||
info->type = PassType_Object;
|
||||
info->flags = flags | PASSFLAG_OASSIGNOP | PASSFLAG_OCTOR;
|
||||
info->size = sizeof(QAngle);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return mySize;
|
||||
}
|
||||
case Valve_CBaseEntity:
|
||||
case Valve_CBasePlayer:
|
||||
case Valve_POD:
|
||||
case Valve_Edict:
|
||||
case Valve_String:
|
||||
{
|
||||
if (pass != PassType_Basic
|
||||
|| (info->flags & PASSFLAG_BYREF))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
info->type = PassType_Basic;
|
||||
info->flags = flags;
|
||||
info->size = sizeof(void *);
|
||||
return sizeof(void *);
|
||||
}
|
||||
case Valve_Float:
|
||||
{
|
||||
info->type = PassType_Float;
|
||||
info->flags = flags;
|
||||
info->size = sizeof(float);
|
||||
return sizeof(float);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DataStatus EncodeValveParam(IPluginContext *pContext,
|
||||
cell_t param,
|
||||
ValveType type,
|
||||
PassType pass,
|
||||
const void *buffer)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Valve_Vector:
|
||||
{
|
||||
Vector *v = NULL;
|
||||
|
||||
if (pass == PassType_Basic)
|
||||
{
|
||||
v = *(Vector **)((unsigned char *)buffer + sizeof(Vector *));
|
||||
} else if (pass == PassType_Object) {
|
||||
v = (Vector *)buffer;
|
||||
}
|
||||
|
||||
cell_t *addr;
|
||||
pContext->LocalToPhysAddr(param, &addr);
|
||||
|
||||
addr[0] = v->x;
|
||||
addr[1] = v->y;
|
||||
addr[2] = v->z;
|
||||
|
||||
return Data_Okay;
|
||||
}
|
||||
case Valve_QAngle:
|
||||
{
|
||||
QAngle *q = NULL;
|
||||
|
||||
if (pass == PassType_Basic)
|
||||
{
|
||||
q = *(QAngle **)((unsigned char *)buffer + sizeof(QAngle *));
|
||||
} else if (pass == PassType_Object) {
|
||||
q = (QAngle *)buffer;
|
||||
}
|
||||
|
||||
cell_t *addr;
|
||||
pContext->LocalToPhysAddr(param, &addr);
|
||||
|
||||
addr[0] = q->x;
|
||||
addr[1] = q->y;
|
||||
addr[2] = q->z;
|
||||
|
||||
return Data_Okay;
|
||||
}
|
||||
case Valve_CBaseEntity:
|
||||
case Valve_CBasePlayer:
|
||||
{
|
||||
cell_t *addr;
|
||||
pContext->LocalToPhysAddr(param, &addr);
|
||||
|
||||
CBaseEntity *pEntity = *(CBaseEntity **)buffer;
|
||||
if (pEntity)
|
||||
{
|
||||
edict_t *pEdict = gameents->BaseEntityToEdict(pEntity);
|
||||
*addr = engine->IndexOfEdict(pEdict);
|
||||
} else {
|
||||
*addr = -1;
|
||||
}
|
||||
|
||||
return Data_Okay;
|
||||
}
|
||||
case Valve_Edict:
|
||||
{
|
||||
cell_t *addr;
|
||||
pContext->LocalToPhysAddr(param, &addr);
|
||||
|
||||
edict_t *pEdict = *(edict_t **)buffer;
|
||||
if (pEdict)
|
||||
{
|
||||
*addr = engine->IndexOfEdict(pEdict);
|
||||
} else {
|
||||
*addr = -1;
|
||||
}
|
||||
|
||||
return Data_Okay;
|
||||
}
|
||||
case Valve_POD:
|
||||
case Valve_Float:
|
||||
{
|
||||
cell_t *addr;
|
||||
pContext->LocalToPhysAddr(param, &addr);
|
||||
|
||||
*addr = *(cell_t *)buffer;
|
||||
|
||||
return Data_Okay;
|
||||
}
|
||||
}
|
||||
|
||||
return Data_Fail;
|
||||
}
|
||||
|
||||
DataStatus DecodeValveParam(IPluginContext *pContext,
|
||||
cell_t param,
|
||||
ValveType vtype,
|
||||
unsigned int vflags,
|
||||
PassType type,
|
||||
void *buffer)
|
||||
{
|
||||
switch (vtype)
|
||||
{
|
||||
case Valve_Vector:
|
||||
{
|
||||
cell_t *addr;
|
||||
int err;
|
||||
err = pContext->LocalToPhysAddr(param, &addr);
|
||||
|
||||
unsigned char *mem = (unsigned char *)buffer;
|
||||
if (type == PassType_Basic)
|
||||
{
|
||||
/* Store the object in the next N bytes, and store
|
||||
* a pointer to that object right beforehand.
|
||||
*/
|
||||
Vector **realPtr = (Vector **)buffer;
|
||||
|
||||
if (addr == pContext->GetNullRef(SP_NULL_VECTOR))
|
||||
{
|
||||
if (vflags & VDECODE_FLAG_ALLOWNULL)
|
||||
{
|
||||
*realPtr = NULL;
|
||||
return Data_Okay;
|
||||
} else {
|
||||
pContext->ThrowNativeError("NULL not allowed");
|
||||
return Data_Fail;
|
||||
}
|
||||
} else {
|
||||
mem += sizeof(Vector *);
|
||||
*realPtr = (Vector *)mem;
|
||||
}
|
||||
}
|
||||
|
||||
if (err != SP_ERROR_NONE)
|
||||
{
|
||||
pContext->ThrowNativeErrorEx(err, "Could not read plugin data");
|
||||
return Data_Fail;
|
||||
}
|
||||
|
||||
/* Use placement new to initialize the object cleanly
|
||||
* This has no destructor so we don't need to do
|
||||
* DestroyValveParam() or something :]
|
||||
*/
|
||||
Vector *v = new (mem) Vector(
|
||||
sp_ctof(addr[0]),
|
||||
sp_ctof(addr[1]),
|
||||
sp_ctof(addr[2]));
|
||||
|
||||
return Data_Okay;
|
||||
}
|
||||
case Valve_QAngle:
|
||||
{
|
||||
cell_t *addr;
|
||||
int err;
|
||||
err = pContext->LocalToPhysAddr(param, &addr);
|
||||
|
||||
unsigned char *mem = (unsigned char *)buffer;
|
||||
if (type == PassType_Basic)
|
||||
{
|
||||
/* Store the object in the next N bytes, and store
|
||||
* a pointer to that object right beforehand.
|
||||
*/
|
||||
QAngle **realPtr = (QAngle **)buffer;
|
||||
|
||||
if (addr == pContext->GetNullRef(SP_NULL_VECTOR))
|
||||
{
|
||||
if (!(vflags & VDECODE_FLAG_ALLOWNULL))
|
||||
{
|
||||
pContext->ThrowNativeError("NULL not allowed");
|
||||
return Data_Fail;
|
||||
} else {
|
||||
*realPtr = NULL;
|
||||
return Data_Okay;
|
||||
}
|
||||
} else {
|
||||
mem += sizeof(QAngle *);
|
||||
*realPtr = (QAngle *)mem;
|
||||
}
|
||||
}
|
||||
|
||||
if (err != SP_ERROR_NONE)
|
||||
{
|
||||
pContext->ThrowNativeErrorEx(err, "Could not read plugin data");
|
||||
return Data_Fail;
|
||||
}
|
||||
|
||||
/* Use placement new to initialize the object cleanly
|
||||
* This has no destructor so we don't need to do
|
||||
* DestroyValveParam() or something :]
|
||||
*/
|
||||
QAngle *v = new (mem) QAngle(
|
||||
sp_ctof(addr[0]),
|
||||
sp_ctof(addr[1]),
|
||||
sp_ctof(addr[2]));
|
||||
|
||||
return Data_Okay;
|
||||
}
|
||||
case Valve_CBasePlayer:
|
||||
{
|
||||
edict_t *pEdict;
|
||||
if (vflags & VDECODE_FLAG_BYREF)
|
||||
{
|
||||
cell_t *addr;
|
||||
pContext->LocalToPhysAddr(param, &addr);
|
||||
param = *addr;
|
||||
}
|
||||
if (param >= 1 && param <= playerhelpers->GetMaxClients())
|
||||
{
|
||||
IGamePlayer *player = playerhelpers->GetGamePlayer(param);
|
||||
if ((vflags & VDECODE_FLAG_ALLOWNOTINGAME)
|
||||
&& !player->IsConnected())
|
||||
{
|
||||
pContext->ThrowNativeError("Client %d is not connected", param);
|
||||
return Data_Fail;
|
||||
} else if (!player->IsInGame()) {
|
||||
pContext->ThrowNativeError("Client %d is not in game", param);
|
||||
return Data_Fail;
|
||||
}
|
||||
pEdict = player->GetEdict();
|
||||
} else if (param == -1) {
|
||||
if (vflags & VDECODE_FLAG_ALLOWNULL)
|
||||
{
|
||||
pEdict = NULL;
|
||||
} else {
|
||||
pContext->ThrowNativeError("NULL not allowed");
|
||||
return Data_Fail;
|
||||
}
|
||||
} else if (param == 0) {
|
||||
if (vflags & VDECODE_FLAG_ALLOWWORLD)
|
||||
{
|
||||
pEdict = engine->PEntityOfEntIndex(0);
|
||||
} else {
|
||||
pContext->ThrowNativeError("World not allowed");
|
||||
return Data_Fail;
|
||||
}
|
||||
} else {
|
||||
pContext->ThrowNativeError("Entity index %d is not a valid client", param);
|
||||
return Data_Fail;
|
||||
}
|
||||
CBaseEntity *pEntity;
|
||||
if (pEdict)
|
||||
{
|
||||
IServerUnknown *pUnknown = pEdict->GetUnknown();
|
||||
if (!pUnknown)
|
||||
{
|
||||
pContext->ThrowNativeError("Entity %d is a not an IServerUnknown");
|
||||
return Data_Fail;
|
||||
}
|
||||
pEntity = pUnknown->GetBaseEntity();
|
||||
if (!pEntity)
|
||||
{
|
||||
pContext->ThrowNativeError("Entity %d is not a CBaseEntity");
|
||||
return Data_Fail;
|
||||
}
|
||||
} else {
|
||||
pEdict = NULL;
|
||||
}
|
||||
|
||||
CBaseEntity **ebuf = (CBaseEntity **)buffer;
|
||||
*ebuf = pEntity;
|
||||
|
||||
return Data_Okay;
|
||||
}
|
||||
case Valve_CBaseEntity:
|
||||
{
|
||||
edict_t *pEdict;
|
||||
if (vflags & VDECODE_FLAG_BYREF)
|
||||
{
|
||||
cell_t *addr;
|
||||
pContext->LocalToPhysAddr(param, &addr);
|
||||
param = *addr;
|
||||
}
|
||||
if (param >= 1 && param <= playerhelpers->GetMaxClients())
|
||||
{
|
||||
IGamePlayer *player = playerhelpers->GetGamePlayer(param);
|
||||
if ((vflags & VDECODE_FLAG_ALLOWNOTINGAME)
|
||||
&& !player->IsConnected())
|
||||
{
|
||||
pContext->ThrowNativeError("Client %d is not connected", param);
|
||||
return Data_Fail;
|
||||
} else if (!player->IsInGame()) {
|
||||
pContext->ThrowNativeError("Client %d is not in game", param);
|
||||
return Data_Fail;
|
||||
}
|
||||
pEdict = player->GetEdict();
|
||||
} else if (param == -1) {
|
||||
if (vflags & VDECODE_FLAG_ALLOWNULL)
|
||||
{
|
||||
pEdict = NULL;
|
||||
} else {
|
||||
pContext->ThrowNativeError("NULL not allowed");
|
||||
return Data_Fail;
|
||||
}
|
||||
} else if (param == 0) {
|
||||
if (vflags & VDECODE_FLAG_ALLOWWORLD)
|
||||
{
|
||||
pEdict = engine->PEntityOfEntIndex(0);
|
||||
} else {
|
||||
pContext->ThrowNativeError("World not allowed");
|
||||
return Data_Fail;
|
||||
}
|
||||
} else {
|
||||
pEdict = engine->PEntityOfEntIndex(param);
|
||||
if (!pEdict || pEdict->IsFree())
|
||||
{
|
||||
pContext->ThrowNativeError("Entity %d is not valid or is freed", param);
|
||||
return Data_Fail;
|
||||
}
|
||||
}
|
||||
CBaseEntity *pEntity;
|
||||
if (pEdict)
|
||||
{
|
||||
IServerUnknown *pUnknown = pEdict->GetUnknown();
|
||||
if (!pUnknown)
|
||||
{
|
||||
pContext->ThrowNativeError("Entity %d is a not an IServerUnknown");
|
||||
return Data_Fail;
|
||||
}
|
||||
pEntity = pUnknown->GetBaseEntity();
|
||||
if (!pEntity)
|
||||
{
|
||||
pContext->ThrowNativeError("Entity %d is not a CBaseEntity");
|
||||
return Data_Fail;
|
||||
}
|
||||
} else {
|
||||
pEdict = NULL;
|
||||
}
|
||||
|
||||
CBaseEntity **ebuf = (CBaseEntity **)buffer;
|
||||
*ebuf = pEntity;
|
||||
|
||||
return Data_Okay;
|
||||
}
|
||||
case Valve_Edict:
|
||||
{
|
||||
edict_t *pEdict;
|
||||
if (vflags & VDECODE_FLAG_BYREF)
|
||||
{
|
||||
cell_t *addr;
|
||||
pContext->LocalToPhysAddr(param, &addr);
|
||||
param = *addr;
|
||||
}
|
||||
if (param >= 1 && param <= playerhelpers->GetMaxClients())
|
||||
{
|
||||
IGamePlayer *player = playerhelpers->GetGamePlayer(param);
|
||||
if ((vflags & VDECODE_FLAG_ALLOWNOTINGAME)
|
||||
&& !player->IsConnected())
|
||||
{
|
||||
pContext->ThrowNativeError("Client %d is not connected", param);
|
||||
return Data_Fail;
|
||||
} else if (!player->IsInGame()) {
|
||||
pContext->ThrowNativeError("Client %d is not in game", param);
|
||||
return Data_Fail;
|
||||
}
|
||||
pEdict = player->GetEdict();
|
||||
} else if (param == -1) {
|
||||
if (vflags & VDECODE_FLAG_ALLOWNULL)
|
||||
{
|
||||
pEdict = NULL;
|
||||
} else {
|
||||
pContext->ThrowNativeError("NULL not allowed");
|
||||
return Data_Fail;
|
||||
}
|
||||
} else if (param == 0) {
|
||||
if (vflags & VDECODE_FLAG_ALLOWWORLD)
|
||||
{
|
||||
pEdict = engine->PEntityOfEntIndex(0);
|
||||
} else {
|
||||
pContext->ThrowNativeError("World not allowed");
|
||||
return Data_Fail;
|
||||
}
|
||||
} else {
|
||||
pEdict = engine->PEntityOfEntIndex(param);
|
||||
if (!pEdict || pEdict->IsFree())
|
||||
{
|
||||
pContext->ThrowNativeError("Entity %d is not valid or is freed", param);
|
||||
return Data_Fail;
|
||||
}
|
||||
}
|
||||
|
||||
edict_t **ebuf = (edict_t **)buffer;
|
||||
*ebuf = pEdict;
|
||||
|
||||
return Data_Okay;
|
||||
}
|
||||
case Valve_POD:
|
||||
case Valve_Float:
|
||||
{
|
||||
if (vflags & VDECODE_FLAG_BYREF)
|
||||
{
|
||||
cell_t *addr;
|
||||
pContext->LocalToPhysAddr(param, &addr);
|
||||
param = *addr;
|
||||
}
|
||||
*(cell_t *)buffer = param;
|
||||
return Data_Okay;
|
||||
}
|
||||
case Valve_String:
|
||||
{
|
||||
char *addr;
|
||||
pContext->LocalToString(param, &addr);
|
||||
*(char **)buffer = addr;
|
||||
return Data_Okay;
|
||||
}
|
||||
}
|
||||
|
||||
return Data_Fail;
|
||||
}
|
93
extensions/sdktools/vdecoder.h
Normal file
93
extensions/sdktools/vdecoder.h
Normal file
@ -0,0 +1,93 @@
|
||||
#ifndef _INCLUDE_SOURCEMOD_VDECODER_H_
|
||||
#define _INCLUDE_SOURCEMOD_VDECODER_H_
|
||||
|
||||
#include <sm_platform.h>
|
||||
#include <sp_vm_api.h>
|
||||
#include <extensions/IBinTools.h>
|
||||
|
||||
using namespace SourceMod;
|
||||
using namespace SourcePawn;
|
||||
|
||||
/**
|
||||
* @brief Encapsulates types from the SDK
|
||||
*/
|
||||
enum ValveType
|
||||
{
|
||||
Valve_CBaseEntity, /**< CBaseEntity */
|
||||
Valve_CBasePlayer, /**< CBasePlayer (disallow normal ents) */
|
||||
Valve_Vector, /**< Vector */
|
||||
Valve_QAngle, /**< QAngle */
|
||||
Valve_POD, /**< Plain old data */
|
||||
Valve_Float, /**< Float */
|
||||
Valve_Edict, /**< Edict */
|
||||
Valve_String, /**< String */
|
||||
};
|
||||
|
||||
enum DataStatus
|
||||
{
|
||||
Data_Fail = 0,
|
||||
Data_Okay = 1,
|
||||
};
|
||||
|
||||
#define VDECODE_FLAG_ALLOWNULL (1<<0) /**< Allow NULL for pointers */
|
||||
#define VDECODE_FLAG_ALLOWNOTINGAME (1<<1) /**< Allow players not in game */
|
||||
#define VDECODE_FLAG_ALLOWWORLD (1<<2) /**< Allow World entity */
|
||||
#define VDECODE_FLAG_BYREF (1<<3) /**< Floats/ints by reference */
|
||||
|
||||
#define VENCODE_FLAG_COPYBACK (1<<0) /**< Copy back data */
|
||||
|
||||
/**
|
||||
* @brief Converts a valve parameter to a bintools parameter.
|
||||
*
|
||||
* @param type Valve type.
|
||||
* @param pass Either basic or object.
|
||||
* @param flags Either BYVAL or BYREF.
|
||||
* @param info Buffer to store param info in.
|
||||
* @return Number of bytes this will use in the virtual stack,
|
||||
* or 0 if conversion was impossible.
|
||||
*/
|
||||
size_t ValveParamToBinParam(ValveType type,
|
||||
PassType pass,
|
||||
unsigned int flags,
|
||||
PassInfo *info);
|
||||
|
||||
/**
|
||||
* @brief Decodes data from a plugin to native data.
|
||||
*
|
||||
* Note: If you're going to return false, make sure to
|
||||
* throw an error.
|
||||
*
|
||||
* @param pContext Plugin context.
|
||||
* @param param Parameter value from params array.
|
||||
* @param type Valve type.
|
||||
* @param pass Pass info from bin tools.
|
||||
* @param buffer Buffer space in the virutal stack.
|
||||
* @return True on success, false otherwise.
|
||||
*/
|
||||
DataStatus DecodeValveParam(IPluginContext *pContext,
|
||||
cell_t param,
|
||||
ValveType type,
|
||||
unsigned int vflags,
|
||||
PassType pass,
|
||||
void *buffer);
|
||||
|
||||
/**
|
||||
* @brief Encodes native data back into a plugin.
|
||||
*
|
||||
* Note: If you're going to return false, make sure to
|
||||
* throw an error.
|
||||
*
|
||||
* @param pContext Plugin context.
|
||||
* @param param Parameter value from params array.
|
||||
* @param type Valve type.
|
||||
* @param pass Pass info from bin tools.
|
||||
* @param buffer Buffer space in the virutal stack.
|
||||
* @return True on success, false otherwise.
|
||||
*/
|
||||
DataStatus EncodeValveParam(IPluginContext *pContext,
|
||||
cell_t param,
|
||||
ValveType type,
|
||||
PassType pass,
|
||||
const void *buffer);
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_VDECODER_H_
|
Loading…
Reference in New Issue
Block a user