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