Added the ability for extensions to invoke arbitrary natives (bug 3605, r=ds,theY4Kman).
authorDavid Anderson <dvander@alliedmods.net>
Sun Feb 01 02:03:03 2009 -0500 (2009-02-01)
changeset 25459cb1a1fefc2c
parent 2544 7fab9b9222cb
child 2546 32c1d07b2038
Added the ability for extensions to invoke arbitrary natives (bug 3605, r=ds,theY4Kman).
core/Makefile
core/NativeInvoker.cpp
core/NativeInvoker.h
core/ShareSys.h
core/msvc9/sourcemod_mm.vcproj
core/sourcemod.cpp
public/INativeInvoker.h
public/sample_ext/sdk/smsdk_config.h
public/sample_ext/sdk/smsdk_ext.cpp
public/sample_ext/sdk/smsdk_ext.h
public/sourcepawn/sp_vm_api.h
sourcepawn/jit/BaseRuntime.cpp
sourcepawn/jit/BaseRuntime.h
sourcepawn/jit/engine2.cpp
sourcepawn/jit/engine2.h
sourcepawn/jit/sp_vm_basecontext.cpp
sourcepawn/jit/sp_vm_basecontext.h
     1.1 --- a/core/Makefile	Sat Jan 31 22:51:48 2009 -0500
     1.2 +++ b/core/Makefile	Sun Feb 01 02:03:03 2009 -0500
     1.3 @@ -33,7 +33,8 @@
     1.4  		   LibrarySys.cpp 			\
     1.5  		   PluginInfoDatabase.cpp 	\
     1.6  		   PluginSys.cpp 			\
     1.7 -		   ShareSys.cpp 
     1.8 +		   ShareSys.cpp				\
     1.9 +		   NativeInvoker.cpp
    1.10  OBJECTS += thread/ThreadWorker.cpp thread/BaseWorker.cpp thread/PosixThreads.cpp ThreadSupport.cpp
    1.11  
    1.12  ##############################################
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/core/NativeInvoker.cpp	Sun Feb 01 02:03:03 2009 -0500
     2.3 @@ -0,0 +1,379 @@
     2.4 +/**
     2.5 + * vim: set ts=4 :
     2.6 + * =============================================================================
     2.7 + * SourcePawn
     2.8 + * Copyright (C) 2004-2009 AlliedModders LLC.  All rights reserved.
     2.9 + * =============================================================================
    2.10 + *
    2.11 + * This program is free software; you can redistribute it and/or modify it under
    2.12 + * the terms of the GNU General Public License, version 3.0, as published by the
    2.13 + * Free Software Foundation.
    2.14 + * 
    2.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
    2.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    2.17 + * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    2.18 + * details.
    2.19 + *
    2.20 + * You should have received a copy of the GNU General Public License along with
    2.21 + * this program.  If not, see <http://www.gnu.org/licenses/>.
    2.22 + *
    2.23 + * As a special exception, AlliedModders LLC gives you permission to link the
    2.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
    2.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    2.26 + * by the Valve Corporation.  You must obey the GNU General Public License in
    2.27 + * all respects for all other code used.  Additionally, AlliedModders LLC grants
    2.28 + * this exception to all derivative works.  AlliedModders LLC defines further
    2.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    2.30 + * or <http://www.sourcemod.net/license.php>.
    2.31 + *
    2.32 + * Version: $Id$
    2.33 + */
    2.34 +
    2.35 +#include "NativeInvoker.h"
    2.36 +#include "ShareSys.h"
    2.37 +
    2.38 +NativeInterface g_NInvoke;
    2.39 +
    2.40 +NativeInvoker::NativeInvoker()
    2.41 +{
    2.42 +}
    2.43 +
    2.44 +NativeInvoker::~NativeInvoker()
    2.45 +{
    2.46 +}
    2.47 +
    2.48 +const char *NativeInterface::GetInterfaceName()
    2.49 +{
    2.50 +	return SMINTERFACE_NINVOKE_NAME;
    2.51 +}
    2.52 +
    2.53 +unsigned int NativeInterface::GetInterfaceVersion()
    2.54 +{
    2.55 +	return SMINTERFACE_NINVOKE_VERSION;
    2.56 +}
    2.57 +
    2.58 +void NativeInterface::OnSourceModAllInitialized()
    2.59 +{
    2.60 +	g_ShareSys.AddInterface(NULL, &g_NInvoke);
    2.61 +}
    2.62 +
    2.63 +IPluginRuntime *NativeInterface::CreateRuntime(const char *name, size_t bytes)
    2.64 +{
    2.65 +	return g_pSourcePawn2->CreateEmptyRuntime(name, bytes);
    2.66 +}
    2.67 +
    2.68 +INativeInvoker *NativeInterface::CreateInvoker()
    2.69 +{
    2.70 +	return new NativeInvoker();
    2.71 +}
    2.72 +
    2.73 +bool NativeInvoker::Start(IPluginContext *pContext, const char *name)
    2.74 +{
    2.75 +	NativeEntry *entry;
    2.76 +	
    2.77 +	entry = g_ShareSys.FindNative(name);
    2.78 +	if (entry == NULL)
    2.79 +	{
    2.80 +		return false;
    2.81 +	}
    2.82 +
    2.83 +	native = NULL;
    2.84 +	if (entry->replacement.owner != NULL)
    2.85 +	{
    2.86 +		native = entry->replacement.func;
    2.87 +	}
    2.88 +	else if (entry->owner != NULL)
    2.89 +	{
    2.90 +		native = entry->func;
    2.91 +	}
    2.92 +
    2.93 +	if (native == NULL)
    2.94 +	{
    2.95 +		return false;
    2.96 +	}
    2.97 +
    2.98 +	this->pContext = pContext;
    2.99 +
   2.100 +	m_curparam = 0;
   2.101 +	m_errorstate = SP_ERROR_NONE;
   2.102 +
   2.103 +	return true;
   2.104 +}
   2.105 +
   2.106 +cell_t NativeInvoker::PushCell(cell_t cell)
   2.107 +{
   2.108 +	if (m_curparam >= SP_MAX_EXEC_PARAMS)
   2.109 +	{
   2.110 +		return SetError(SP_ERROR_PARAMS_MAX);
   2.111 +	}
   2.112 +
   2.113 +	m_info[m_curparam].marked = false;
   2.114 +	m_params[m_curparam] = cell;
   2.115 +	m_curparam++;
   2.116 +
   2.117 +	return SP_ERROR_NONE;
   2.118 +}
   2.119 +
   2.120 +int NativeInvoker::PushCellByRef(cell_t *cell, int flags)
   2.121 +{
   2.122 +	return PushArray(cell, 1, flags);
   2.123 +}
   2.124 +
   2.125 +int NativeInvoker::PushFloat(float number)
   2.126 +{
   2.127 +	cell_t val = *(cell_t *)&number;
   2.128 +
   2.129 +	return PushCell(val);
   2.130 +}
   2.131 +
   2.132 +int NativeInvoker::PushFloatByRef(float *number, int flags)
   2.133 +{
   2.134 +	return PushCellByRef((cell_t *)number, flags);
   2.135 +}
   2.136 +
   2.137 +int NativeInvoker::PushArray(cell_t *inarray, unsigned int cells, int copyback)
   2.138 +{
   2.139 +	if (m_curparam >= SP_MAX_EXEC_PARAMS)
   2.140 +	{
   2.141 +		return SetError(SP_ERROR_PARAMS_MAX);
   2.142 +	}
   2.143 +
   2.144 +	ParamInfo *info = &m_info[m_curparam];
   2.145 +
   2.146 +	info->flags = inarray ? copyback : 0;
   2.147 +	info->marked = true;
   2.148 +	info->size = cells;
   2.149 +	info->str.is_sz = false;
   2.150 +	info->orig_addr = inarray;
   2.151 +
   2.152 +	m_curparam++;
   2.153 +
   2.154 +	return SP_ERROR_NONE;
   2.155 +}
   2.156 +
   2.157 +int NativeInvoker::PushString(const char *string)
   2.158 +{
   2.159 +	return _PushString(string, SM_PARAM_STRING_COPY, 0, strlen(string)+1);
   2.160 +}
   2.161 +
   2.162 +int NativeInvoker::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
   2.163 +{
   2.164 +	return _PushString(buffer, sz_flags, cp_flags, length);
   2.165 +}
   2.166 +
   2.167 +int NativeInvoker::_PushString(const char *string, int sz_flags, int cp_flags, size_t len)
   2.168 +{
   2.169 +	if (m_curparam >= SP_MAX_EXEC_PARAMS)
   2.170 +	{
   2.171 +		return SetError(SP_ERROR_PARAMS_MAX);
   2.172 +	}
   2.173 +
   2.174 +	ParamInfo *info = &m_info[m_curparam];
   2.175 +
   2.176 +	info->marked = true;
   2.177 +	info->orig_addr = (cell_t *)string;
   2.178 +	info->flags = cp_flags;
   2.179 +	info->size = len;
   2.180 +	info->str.sz_flags = sz_flags;
   2.181 +	info->str.is_sz = true;
   2.182 +
   2.183 +	m_curparam++;
   2.184 +
   2.185 +	return SP_ERROR_NONE;
   2.186 +}
   2.187 +
   2.188 +void NativeInvoker::Cancel()
   2.189 +{
   2.190 +	if (pContext == NULL)
   2.191 +	{
   2.192 +		return;
   2.193 +	}
   2.194 +
   2.195 +	m_errorstate = SP_ERROR_NONE;
   2.196 +	m_curparam = 0;
   2.197 +	pContext = NULL;
   2.198 +	native = NULL;
   2.199 +}
   2.200 +
   2.201 +int NativeInvoker::SetError(int err)
   2.202 +{
   2.203 +	m_errorstate = err;
   2.204 +	return err;
   2.205 +}
   2.206 +
   2.207 +int NativeInvoker::Invoke(cell_t *result)
   2.208 +{
   2.209 +	int err = SP_ERROR_NONE;
   2.210 +
   2.211 +	if (pContext == NULL)
   2.212 +	{
   2.213 +		return SP_ERROR_INVALID_NATIVE;
   2.214 +	}
   2.215 +
   2.216 +	if (m_errorstate != SP_ERROR_NONE)
   2.217 +	{
   2.218 +		err = m_errorstate;
   2.219 +		Cancel();
   2.220 +		return err;
   2.221 +	}
   2.222 +
   2.223 +	cell_t tresult;
   2.224 +
   2.225 +	if (result == NULL)
   2.226 +	{
   2.227 +		result = &tresult;
   2.228 +	}
   2.229 +
   2.230 +	//This is for re-entrancy!
   2.231 +	IPluginContext *ctx = pContext;
   2.232 +	cell_t _temp_params[SP_MAX_EXEC_PARAMS + 1];
   2.233 +	cell_t *temp_params = &_temp_params[1];
   2.234 +	ParamInfo temp_info[SP_MAX_EXEC_PARAMS];
   2.235 +	unsigned int numparams = m_curparam;
   2.236 +	unsigned int i;
   2.237 +	bool docopies = true;
   2.238 +
   2.239 +	if (numparams)
   2.240 +	{
   2.241 +		//Save the info locally, then reset it for re-entrant calls.
   2.242 +		memcpy(temp_info, m_info, numparams * sizeof(ParamInfo));
   2.243 +	}
   2.244 +	m_curparam = 0;
   2.245 +	pContext = NULL;
   2.246 +
   2.247 +	/* Initialize 0th parameter */
   2.248 +	_temp_params[0] = numparams;
   2.249 +
   2.250 +	/* Browse the parameters and build arrays */
   2.251 +	for (i = 0; i < numparams; i++)
   2.252 +	{
   2.253 +		/* Is this marked as an array? */
   2.254 +		if (temp_info[i].marked)
   2.255 +		{
   2.256 +			if (!temp_info[i].str.is_sz)
   2.257 +			{
   2.258 +				/* Allocate a normal/generic array */
   2.259 +				if ((err = ctx->HeapAlloc(temp_info[i].size, 
   2.260 +										  &temp_info[i].local_addr,
   2.261 +										  &temp_info[i].phys_addr))
   2.262 +					!= SP_ERROR_NONE)
   2.263 +				{
   2.264 +					break;
   2.265 +				}
   2.266 +				if (temp_info[i].orig_addr)
   2.267 +				{
   2.268 +					memcpy(temp_info[i].phys_addr, temp_info[i].orig_addr, sizeof(cell_t) * temp_info[i].size);
   2.269 +				}
   2.270 +			}
   2.271 +			else
   2.272 +			{
   2.273 +				/* Calculate cells required for the string */
   2.274 +				size_t cells = (temp_info[i].size + sizeof(cell_t) - 1) / sizeof(cell_t);
   2.275 +
   2.276 +				/* Allocate the buffer */
   2.277 +				if ((err = ctx->HeapAlloc(cells,
   2.278 +										  &temp_info[i].local_addr,
   2.279 +										  &temp_info[i].phys_addr))
   2.280 +					!= SP_ERROR_NONE)
   2.281 +				{
   2.282 +					break;
   2.283 +				}
   2.284 +				/* Copy original string if necessary */
   2.285 +				if ((temp_info[i].str.sz_flags & SM_PARAM_STRING_COPY) && (temp_info[i].orig_addr != NULL))
   2.286 +				{
   2.287 +					/* Cut off UTF-8 properly */
   2.288 +					if (temp_info[i].str.sz_flags & SM_PARAM_STRING_UTF8)
   2.289 +					{
   2.290 +						if ((err = ctx->StringToLocalUTF8(temp_info[i].local_addr, 
   2.291 +														  temp_info[i].size, 
   2.292 +														  (const char *)temp_info[i].orig_addr,
   2.293 +														  NULL))
   2.294 +							!= SP_ERROR_NONE)
   2.295 +						{
   2.296 +							break;
   2.297 +						}
   2.298 +					}
   2.299 +					/* Copy a binary blob */
   2.300 +					else if (temp_info[i].str.sz_flags & SM_PARAM_STRING_BINARY)
   2.301 +					{
   2.302 +						memmove(temp_info[i].phys_addr, temp_info[i].orig_addr, temp_info[i].size);
   2.303 +					}
   2.304 +					/* Copy ASCII characters */
   2.305 +					else
   2.306 +					{
   2.307 +						if ((err = ctx->StringToLocal(temp_info[i].local_addr,
   2.308 +													  temp_info[i].size,
   2.309 +													  (const char *)temp_info[i].orig_addr))
   2.310 +							!= SP_ERROR_NONE)
   2.311 +						{
   2.312 +							break;
   2.313 +						}
   2.314 +					}
   2.315 +				}
   2.316 +			} /* End array/string calculation */
   2.317 +			/* Update the pushed parameter with the byref local address */
   2.318 +			temp_params[i] = temp_info[i].local_addr;
   2.319 +		}
   2.320 +		else
   2.321 +		{
   2.322 +			/* Just copy the value normally */
   2.323 +			temp_params[i] = m_params[i];
   2.324 +		}
   2.325 +	}
   2.326 +
   2.327 +	/* Make the call if we can */
   2.328 +	if (err == SP_ERROR_NONE)
   2.329 +	{
   2.330 +		*result = native(ctx, _temp_params);
   2.331 +		if (ctx->GetLastNativeError() != SP_ERROR_NONE)
   2.332 +		{
   2.333 +			docopies = false;
   2.334 +			ctx->ClearLastNativeError();
   2.335 +		}
   2.336 +	}
   2.337 +	else
   2.338 +	{
   2.339 +		docopies = false;
   2.340 +	}
   2.341 +
   2.342 +	/* i should be equal to the last valid parameter + 1 */
   2.343 +	while (i--)
   2.344 +	{
   2.345 +		if (!temp_info[i].marked)
   2.346 +		{
   2.347 +			continue;
   2.348 +		}
   2.349 +
   2.350 +		if (docopies && (temp_info[i].flags & SM_PARAM_COPYBACK))
   2.351 +		{
   2.352 +			if (temp_info[i].orig_addr)
   2.353 +			{
   2.354 +				if (temp_info[i].str.is_sz)
   2.355 +				{
   2.356 +					memcpy(temp_info[i].orig_addr, temp_info[i].phys_addr, temp_info[i].size);
   2.357 +
   2.358 +				}
   2.359 +				else
   2.360 +				{
   2.361 +					if (temp_info[i].size == 1)
   2.362 +					{
   2.363 +						*temp_info[i].orig_addr = *(temp_info[i].phys_addr);
   2.364 +					}
   2.365 +					else
   2.366 +					{
   2.367 +						memcpy(temp_info[i].orig_addr, 
   2.368 +							temp_info[i].phys_addr, 
   2.369 +							temp_info[i].size * sizeof(cell_t));
   2.370 +					}
   2.371 +				}
   2.372 +			}
   2.373 +		}
   2.374 +
   2.375 +		if ((err = ctx->HeapPop(temp_info[i].local_addr)) != SP_ERROR_NONE)
   2.376 +		{
   2.377 +			return err;
   2.378 +		}
   2.379 +	}
   2.380 +
   2.381 +	return err;
   2.382 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/core/NativeInvoker.h	Sun Feb 01 02:03:03 2009 -0500
     3.3 @@ -0,0 +1,98 @@
     3.4 +/**
     3.5 + * vim: set ts=4 :
     3.6 + * =============================================================================
     3.7 + * SourceMod
     3.8 + * Copyright (C) 2004-2009 AlliedModders LLC.  All rights reserved.
     3.9 + * =============================================================================
    3.10 + *
    3.11 + * This program is free software; you can redistribute it and/or modify it under
    3.12 + * the terms of the GNU General Public License, version 3.0, as published by the
    3.13 + * Free Software Foundation.
    3.14 + * 
    3.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
    3.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    3.17 + * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    3.18 + * details.
    3.19 + *
    3.20 + * You should have received a copy of the GNU General Public License along with
    3.21 + * this program.  If not, see <http://www.gnu.org/licenses/>.
    3.22 + *
    3.23 + * As a special exception, AlliedModders LLC gives you permission to link the
    3.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
    3.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    3.26 + * by the Valve Corporation.  You must obey the GNU General Public License in
    3.27 + * all respects for all other code used.  Additionally, AlliedModders LLC grants
    3.28 + * this exception to all derivative works.  AlliedModders LLC defines further
    3.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    3.30 + * or <http://www.sourcemod.net/license.php>.
    3.31 + *
    3.32 + * Version: $Id$
    3.33 + */
    3.34 +
    3.35 +#ifndef _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_
    3.36 +#define _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_
    3.37 +
    3.38 +#include "sm_globals.h"
    3.39 +#include <INativeInvoker.h>
    3.40 +
    3.41 +struct ParamInfo
    3.42 +{
    3.43 +	int flags;			/* Copy-back flags */
    3.44 +	bool marked;		/* Whether this is marked as being used */
    3.45 +	cell_t local_addr;	/* Local address to free */
    3.46 +	cell_t *phys_addr;	/* Physical address of our copy */
    3.47 +	cell_t *orig_addr;	/* Original address to copy back to */
    3.48 +	ucell_t size;		/* Size of array in bytes */
    3.49 +	struct
    3.50 +	{
    3.51 +		bool is_sz;		/* is a string */
    3.52 +		int sz_flags;	/* has sz flags */
    3.53 +	} str;
    3.54 +};
    3.55 +
    3.56 +class NativeInvoker : public INativeInvoker
    3.57 +{
    3.58 +public:
    3.59 +	NativeInvoker();
    3.60 +	~NativeInvoker();
    3.61 +public: /* ICallable */
    3.62 +	int PushCell(cell_t cell);
    3.63 +	int PushCellByRef(cell_t *cell, int flags=SM_PARAM_COPYBACK);
    3.64 +	int PushFloat(float number);
    3.65 +	int PushFloatByRef(float *number, int flags=SM_PARAM_COPYBACK);
    3.66 +	int PushArray(cell_t *inarray, unsigned int cells, int flags=0);
    3.67 +	int PushString(const char *string);
    3.68 +	int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags);
    3.69 +	void Cancel();
    3.70 +public: /* INativeInvoker */
    3.71 +	bool Start(IPluginContext *pContext, const char *name);
    3.72 +	int Invoke(cell_t *result);
    3.73 +private:
    3.74 +	int _PushString(const char *string, int sz_flags, int cp_flags, size_t len);
    3.75 +	int SetError(int err);
    3.76 +private:
    3.77 +	IPluginContext *pContext;
    3.78 +	SPVM_NATIVE_FUNC native;
    3.79 +	cell_t m_params[SP_MAX_EXEC_PARAMS];
    3.80 +	ParamInfo m_info[SP_MAX_EXEC_PARAMS];
    3.81 +	unsigned int m_curparam;
    3.82 +	int m_errorstate;
    3.83 +};
    3.84 +
    3.85 +class NativeInterface : 
    3.86 +	public INativeInterface,
    3.87 +	public SMGlobalClass
    3.88 +{
    3.89 +public: /* SMGlobalClass */
    3.90 +	void OnSourceModAllInitialized();
    3.91 +public: /* SMInterface */
    3.92 +	unsigned int GetInterfaceVersion();
    3.93 +	const char *GetInterfaceName();
    3.94 +public: /* INativeInvoker */
    3.95 +	IPluginRuntime *CreateRuntime(const char *name, size_t bytes);
    3.96 +	INativeInvoker *CreateInvoker();
    3.97 +};
    3.98 +
    3.99 +extern NativeInterface g_NInvoke;
   3.100 +
   3.101 +#endif /* _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_ */
     4.1 --- a/core/ShareSys.h	Sat Jan 31 22:51:48 2009 -0500
     4.2 +++ b/core/ShareSys.h	Sun Feb 01 02:03:03 2009 -0500
     4.3 @@ -128,10 +128,10 @@
     4.4  	void BindNativesToPlugin(CPlugin *pPlugin, bool bCoreOnly);
     4.5  	void BindNativeToPlugin(CPlugin *pPlugin, NativeEntry *pEntry);
     4.6  	NativeEntry *AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func);
     4.7 +	NativeEntry *FindNative(const char *name);
     4.8  private:
     4.9  	NativeEntry *AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv);
    4.10  	void ClearNativeFromCache(CNativeOwner *pOwner, const char *name);
    4.11 -	NativeEntry *FindNative(const char *name);
    4.12  	void BindNativeToPlugin(CPlugin *pPlugin, 
    4.13  		sp_native_t *ntv, 
    4.14  		uint32_t index, 
     5.1 --- a/core/msvc9/sourcemod_mm.vcproj	Sat Jan 31 22:51:48 2009 -0500
     5.2 +++ b/core/msvc9/sourcemod_mm.vcproj	Sun Feb 01 02:03:03 2009 -0500
     5.3 @@ -1186,6 +1186,10 @@
     5.4  				>
     5.5  			</File>
     5.6  			<File
     5.7 +				RelativePath="..\NativeInvoker.cpp"
     5.8 +				>
     5.9 +			</File>
    5.10 +			<File
    5.11  				RelativePath="..\NativeOwner.cpp"
    5.12  				>
    5.13  			</File>
    5.14 @@ -1392,6 +1396,10 @@
    5.15  				>
    5.16  			</File>
    5.17  			<File
    5.18 +				RelativePath="..\NativeInvoker.h"
    5.19 +				>
    5.20 +			</File>
    5.21 +			<File
    5.22  				RelativePath="..\NativeOwner.h"
    5.23  				>
    5.24  			</File>
    5.25 @@ -1557,6 +1565,10 @@
    5.26  				>
    5.27  			</File>
    5.28  			<File
    5.29 +				RelativePath="..\..\public\INativeInvoker.h"
    5.30 +				>
    5.31 +			</File>
    5.32 +			<File
    5.33  				RelativePath="..\..\public\IPlayerHelpers.h"
    5.34  				>
    5.35  			</File>
     6.1 --- a/core/sourcemod.cpp	Sat Jan 31 22:51:48 2009 -0500
     6.2 +++ b/core/sourcemod.cpp	Sun Feb 01 02:03:03 2009 -0500
     6.3 @@ -200,7 +200,7 @@
     6.4  	g_pSourcePawn = getv1();
     6.5  	g_pSourcePawn2 = getv2();
     6.6  
     6.7 -	if (g_pSourcePawn2->GetAPIVersion() < 2)
     6.8 +	if (g_pSourcePawn2->GetAPIVersion() < 3)
     6.9  	{
    6.10  		g_pSourcePawn2 = NULL;
    6.11  		if (error && maxlength)
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/public/INativeInvoker.h	Sun Feb 01 02:03:03 2009 -0500
     7.3 @@ -0,0 +1,106 @@
     7.4 +/**
     7.5 + * vim: set ts=4 :
     7.6 + * =============================================================================
     7.7 + * SourceMod
     7.8 + * Copyright (C) 2004-2009 AlliedModders LLC.  All rights reserved.
     7.9 + * =============================================================================
    7.10 + *
    7.11 + * This program is free software; you can redistribute it and/or modify it under
    7.12 + * the terms of the GNU General Public License, version 3.0, as published by the
    7.13 + * Free Software Foundation.
    7.14 + * 
    7.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
    7.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    7.17 + * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    7.18 + * details.
    7.19 + *
    7.20 + * You should have received a copy of the GNU General Public License along with
    7.21 + * this program.  If not, see <http://www.gnu.org/licenses/>.
    7.22 + *
    7.23 + * As a special exception, AlliedModders LLC gives you permission to link the
    7.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
    7.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    7.26 + * by the Valve Corporation.  You must obey the GNU General Public License in
    7.27 + * all respects for all other code used.  Additionally, AlliedModders LLC grants
    7.28 + * this exception to all derivative works.  AlliedModders LLC defines further
    7.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    7.30 + * or <http://www.sourcemod.net/license.php>.
    7.31 + *
    7.32 + * Version: $Id$
    7.33 + */
    7.34 +
    7.35 +#ifndef _INCLUDE_SOURCEMOD_INATIVEINVOKER_H_
    7.36 +#define _INCLUDE_SOURCEMOD_INATIVEINVOKER_H_
    7.37 +
    7.38 +/**
    7.39 + * @file INativeInvoker.h
    7.40 + * @brief Interface for invoking natives.
    7.41 + */
    7.42 +
    7.43 +#include <IShareSys.h>
    7.44 +
    7.45 +#define SMINTERFACE_NINVOKE_NAME	"INativeInterface"
    7.46 +#define SMINTERFACE_NINVOKE_VERSION	1
    7.47 +
    7.48 +#define NINVOKE_DEFAULT_MEMORY		16384
    7.49 +
    7.50 +namespace SourceMod
    7.51 +{
    7.52 +	class INativeInvoker : public SourcePawn::ICallable
    7.53 +	{
    7.54 +	public:
    7.55 +		/**
    7.56 +		 * @brief Virtual destructor - use delete to free this.
    7.57 +		 */
    7.58 +		virtual ~INativeInvoker()
    7.59 +		{
    7.60 +		}
    7.61 +	public:
    7.62 +		/**
    7.63 +		 * @brief Begins a native call.
    7.64 +		 *
    7.65 +		 * During a call's preparation, no new calls may be started.
    7.66 +		 *
    7.67 +		 * @param pContext	Context to invoke native under.
    7.68 +		 * @param name		Name of native.
    7.69 +		 * @return			True if native was found, false otherwise.
    7.70 +		 */
    7.71 +		virtual bool Start(IPluginContext *pContext, const char *name) = 0;
    7.72 +
    7.73 +		/**
    7.74 +		 * @brief Invokes the native.  The preparation state is cleared immediately, meaning that 
    7.75 +		 * this object can be re-used after or even from inside the native being called.
    7.76 +		 *
    7.77 +		 * @param result	Optional pointer to retrieve a result.
    7.78 +		 * @return			SP_ERROR return code.
    7.79 +		 */
    7.80 +		virtual int Invoke(cell_t *result) = 0;
    7.81 +	};
    7.82 +
    7.83 +	/**
    7.84 +	 * @brief Factory for dealing with native invocations.
    7.85 +	 */
    7.86 +	class INativeInterface : public SMInterface
    7.87 +	{
    7.88 +	public:
    7.89 +		/**
    7.90 +		 * @brief Creates a virtual plugin.  This can be used as an environment to invoke natives.
    7.91 +		 *
    7.92 +		 * IPluginRuntime objects must be freed with the delete operator.
    7.93 +		 *
    7.94 +		 * @param name		Name, or NULL for anonymous.
    7.95 +		 * @param bytes		Number of bytes for memory (NINVOKE_DEFAULT_MEMORY recommended).
    7.96 +		 * @return			New runtime, or NULL on failure.
    7.97 +		 */
    7.98 +		virtual IPluginRuntime *CreateRuntime(const char *name, size_t bytes) = 0;
    7.99 +
   7.100 +		/**
   7.101 +		 * @brief Creates an object that can be used to invoke a single native code.
   7.102 +		 *
   7.103 +		 * @return			New native invoker (free with delete).
   7.104 +		 */
   7.105 +		virtual INativeInvoker *CreateInvoker() = 0;
   7.106 +	};
   7.107 +}
   7.108 +
   7.109 +#endif /* _INCLUDE_SOURCEMOD_INATIVEINVOKER_H_ */
     8.1 --- a/public/sample_ext/sdk/smsdk_config.h	Sat Jan 31 22:51:48 2009 -0500
     8.2 +++ b/public/sample_ext/sdk/smsdk_config.h	Sun Feb 01 02:03:03 2009 -0500
     8.3 @@ -76,5 +76,6 @@
     8.4  //#define SMEXT_ENABLE_TEXTPARSERS
     8.5  //#define SMEXT_ENABLE_USERMSGS
     8.6  //#define SMEXT_ENABLE_TRANSLATOR
     8.7 +//#define SMEXT_ENABLE_NINVOKE
     8.8  
     8.9  #endif // _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_
     9.1 --- a/public/sample_ext/sdk/smsdk_ext.cpp	Sat Jan 31 22:51:48 2009 -0500
     9.2 +++ b/public/sample_ext/sdk/smsdk_ext.cpp	Sun Feb 01 02:03:03 2009 -0500
     9.3 @@ -97,6 +97,9 @@
     9.4  #if defined SMEXT_ENABLE_TRANSLATOR
     9.5  ITranslator *translator = NULL;
     9.6  #endif
     9.7 +#if defined SMEXT_ENABLE_NINVOKE
     9.8 +INativeInterface *ninvoke = NULL;
     9.9 +#endif
    9.10  
    9.11  /** Exports the main interface */
    9.12  PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI()
    10.1 --- a/public/sample_ext/sdk/smsdk_ext.h	Sat Jan 31 22:51:48 2009 -0500
    10.2 +++ b/public/sample_ext/sdk/smsdk_ext.h	Sun Feb 01 02:03:03 2009 -0500
    10.3 @@ -91,6 +91,9 @@
    10.4  #if defined SMEXT_ENABLE_TRANSLATOR
    10.5  #include <ITranslator.h>
    10.6  #endif
    10.7 +#if defined SMEXT_ENABLE_NINVOKE
    10.8 +#include <INativeInvoker.h>
    10.9 +#endif
   10.10  
   10.11  #if defined SMEXT_CONF_METAMOD
   10.12  #include <ISmmPlugin.h>
   10.13 @@ -289,6 +292,9 @@
   10.14  #if defined SMEXT_ENABLE_TRANSLATOR
   10.15  extern ITranslator *translator;
   10.16  #endif
   10.17 +#if defined SMEXT_ENABLE_NINVOKE
   10.18 +extern INativeInterface *ninvoke;
   10.19 +#endif
   10.20  
   10.21  #if defined SMEXT_CONF_METAMOD
   10.22  PLUGIN_GLOBALVARS();
    11.1 --- a/public/sourcepawn/sp_vm_api.h	Sat Jan 31 22:51:48 2009 -0500
    11.2 +++ b/public/sourcepawn/sp_vm_api.h	Sun Feb 01 02:03:03 2009 -0500
    11.3 @@ -42,7 +42,7 @@
    11.4  
    11.5  /** SourcePawn Engine API Version */
    11.6  #define SOURCEPAWN_ENGINE_API_VERSION	4
    11.7 -#define SOURCEPAWN_ENGINE2_API_VERSION	2
    11.8 +#define SOURCEPAWN_ENGINE2_API_VERSION	3
    11.9  
   11.10  #if !defined SOURCEMOD_BUILD
   11.11  #define SOURCEMOD_BUILD
   11.12 @@ -876,6 +876,11 @@
   11.13  		 * @return				True on success, false on failure.
   11.14  		 */
   11.15  		virtual bool GetKey(int k, void **value) =0;
   11.16 +
   11.17 +		/**
   11.18 +		 * @brief Clears the last native error.
   11.19 +		 */
   11.20 +		virtual void ClearLastNativeError() =0;
   11.21  	};
   11.22  
   11.23  
   11.24 @@ -1252,6 +1257,15 @@
   11.25  		 * Initialize() succeeded.
   11.26  		 */
   11.27  		virtual void Shutdown() =0;
   11.28 +
   11.29 +		/**
   11.30 +		 * @brief Creates an empty plugin with a blob of memory.
   11.31 +		 *
   11.32 +		 * @param name		Name, for debugging (NULL for anonymous).
   11.33 +		 * @param bytes		Number of bytes of memory (hea+stk).
   11.34 +		 * @return			New runtime, or NULL if not enough memory.
   11.35 +		 */
   11.36 +		virtual IPluginRuntime *CreateEmptyRuntime(const char *name, uint32_t memory) =0;
   11.37  	};
   11.38  };
   11.39  
    12.1 --- a/sourcepawn/jit/BaseRuntime.cpp	Sat Jan 31 22:51:48 2009 -0500
    12.2 +++ b/sourcepawn/jit/BaseRuntime.cpp	Sun Feb 01 02:03:03 2009 -0500
    12.3 @@ -535,3 +535,21 @@
    12.4  
    12.5  	return m_NumFuncs;
    12.6  }
    12.7 +
    12.8 +int BaseRuntime::CreateBlank(uint32_t heastk)
    12.9 +{
   12.10 +	memset(m_pPlugin, 0, sizeof(sp_plugin_t));
   12.11 +
   12.12 +	/* Align to cell_t bytes */
   12.13 +	heastk += sizeof(cell_t);
   12.14 +	heastk -= heastk % sizeof(cell_t);
   12.15 +
   12.16 +	m_pPlugin->mem_size = heastk;
   12.17 +	m_pPlugin->memory = new uint8_t[heastk];
   12.18 +
   12.19 +	m_pPlugin->profiler = g_engine2.GetProfiler();
   12.20 +	m_pCtx = new BaseContext(this);
   12.21 +	m_pCo = g_Jit.StartCompilation(this);
   12.22 +
   12.23 +	return SP_ERROR_NONE;
   12.24 +}
    13.1 --- a/sourcepawn/jit/BaseRuntime.h	Sat Jan 31 22:51:48 2009 -0500
    13.2 +++ b/sourcepawn/jit/BaseRuntime.h	Sun Feb 01 02:03:03 2009 -0500
    13.3 @@ -27,6 +27,7 @@
    13.4  	BaseRuntime();
    13.5  	~BaseRuntime();
    13.6  public:
    13.7 +	virtual int CreateBlank(uint32_t heastk);
    13.8  	virtual int CreateFromMemory(sp_file_hdr_t *hdr, uint8_t *base);
    13.9  	virtual bool IsDebugging();
   13.10  	virtual IPluginDebugInfo *GetDebugInfo();
    14.1 --- a/sourcepawn/jit/engine2.cpp	Sat Jan 31 22:51:48 2009 -0500
    14.2 +++ b/sourcepawn/jit/engine2.cpp	Sun Feb 01 02:03:03 2009 -0500
    14.3 @@ -191,3 +191,22 @@
    14.4  {
    14.5  	g_Jit.ShutdownJIT();
    14.6  }
    14.7 +
    14.8 +IPluginRuntime *SourcePawnEngine2::CreateEmptyRuntime(const char *name, uint32_t memory)
    14.9 +{
   14.10 +	int err;
   14.11 +	BaseRuntime *rt;
   14.12 +
   14.13 +	rt = new BaseRuntime();
   14.14 +	if ((err = rt->CreateBlank(memory)) != SP_ERROR_NONE)
   14.15 +	{
   14.16 +		delete rt;
   14.17 +		return NULL;
   14.18 +	}
   14.19 +
   14.20 +	rt->m_pPlugin->name = strdup(name != NULL ? name : "<anonymous>");
   14.21 +
   14.22 +	rt->ApplyCompilationOptions(NULL);
   14.23 +	
   14.24 +	return rt;
   14.25 +}
    15.1 --- a/sourcepawn/jit/engine2.h	Sat Jan 31 22:51:48 2009 -0500
    15.2 +++ b/sourcepawn/jit/engine2.h	Sun Feb 01 02:03:03 2009 -0500
    15.3 @@ -25,6 +25,7 @@
    15.4  		const char *GetErrorString(int err);
    15.5  		bool Initialize();
    15.6  		void Shutdown();
    15.7 +		IPluginRuntime *CreateEmptyRuntime(const char *name, uint32_t memory);
    15.8  	public:
    15.9  		IProfiler *GetProfiler();
   15.10  	private:
    16.1 --- a/sourcepawn/jit/sp_vm_basecontext.cpp	Sat Jan 31 22:51:48 2009 -0500
    16.2 +++ b/sourcepawn/jit/sp_vm_basecontext.cpp	Sun Feb 01 02:03:03 2009 -0500
    16.3 @@ -873,3 +873,8 @@
    16.4  
    16.5  	return true;
    16.6  }
    16.7 +
    16.8 +void BaseContext::ClearLastNativeError()
    16.9 +{
   16.10 +	m_ctx.n_err = SP_ERROR_NONE;
   16.11 +}
    17.1 --- a/sourcepawn/jit/sp_vm_basecontext.h	Sat Jan 31 22:51:48 2009 -0500
    17.2 +++ b/sourcepawn/jit/sp_vm_basecontext.h	Sun Feb 01 02:03:03 2009 -0500
    17.3 @@ -93,6 +93,7 @@
    17.4  	void SetKey(int k, void *value);
    17.5  	bool GetKey(int k, void **value);
    17.6  	void Refresh();
    17.7 +	void ClearLastNativeError();
    17.8  public:
    17.9  	bool IsInExec();
   17.10  private: