diff --git a/core/Makefile b/core/Makefile index 2b883445..995f425b 100644 --- a/core/Makefile +++ b/core/Makefile @@ -33,7 +33,8 @@ OBJECTS += ExtensionSys.cpp \ LibrarySys.cpp \ PluginInfoDatabase.cpp \ PluginSys.cpp \ - ShareSys.cpp + ShareSys.cpp \ + NativeInvoker.cpp OBJECTS += thread/ThreadWorker.cpp thread/BaseWorker.cpp thread/PosixThreads.cpp ThreadSupport.cpp ############################################## diff --git a/core/NativeInvoker.cpp b/core/NativeInvoker.cpp new file mode 100644 index 00000000..3759684c --- /dev/null +++ b/core/NativeInvoker.cpp @@ -0,0 +1,379 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourcePawn + * Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#include "NativeInvoker.h" +#include "ShareSys.h" + +NativeInterface g_NInvoke; + +NativeInvoker::NativeInvoker() +{ +} + +NativeInvoker::~NativeInvoker() +{ +} + +const char *NativeInterface::GetInterfaceName() +{ + return SMINTERFACE_NINVOKE_NAME; +} + +unsigned int NativeInterface::GetInterfaceVersion() +{ + return SMINTERFACE_NINVOKE_VERSION; +} + +void NativeInterface::OnSourceModAllInitialized() +{ + g_ShareSys.AddInterface(NULL, &g_NInvoke); +} + +IPluginRuntime *NativeInterface::CreateRuntime(const char *name, size_t bytes) +{ + return g_pSourcePawn2->CreateEmptyRuntime(name, bytes); +} + +INativeInvoker *NativeInterface::CreateInvoker() +{ + return new NativeInvoker(); +} + +bool NativeInvoker::Start(IPluginContext *pContext, const char *name) +{ + NativeEntry *entry; + + entry = g_ShareSys.FindNative(name); + if (entry == NULL) + { + return false; + } + + native = NULL; + if (entry->replacement.owner != NULL) + { + native = entry->replacement.func; + } + else if (entry->owner != NULL) + { + native = entry->func; + } + + if (native == NULL) + { + return false; + } + + this->pContext = pContext; + + m_curparam = 0; + m_errorstate = SP_ERROR_NONE; + + return true; +} + +cell_t NativeInvoker::PushCell(cell_t cell) +{ + if (m_curparam >= SP_MAX_EXEC_PARAMS) + { + return SetError(SP_ERROR_PARAMS_MAX); + } + + m_info[m_curparam].marked = false; + m_params[m_curparam] = cell; + m_curparam++; + + return SP_ERROR_NONE; +} + +int NativeInvoker::PushCellByRef(cell_t *cell, int flags) +{ + return PushArray(cell, 1, flags); +} + +int NativeInvoker::PushFloat(float number) +{ + cell_t val = *(cell_t *)&number; + + return PushCell(val); +} + +int NativeInvoker::PushFloatByRef(float *number, int flags) +{ + return PushCellByRef((cell_t *)number, flags); +} + +int NativeInvoker::PushArray(cell_t *inarray, unsigned int cells, int copyback) +{ + if (m_curparam >= SP_MAX_EXEC_PARAMS) + { + return SetError(SP_ERROR_PARAMS_MAX); + } + + ParamInfo *info = &m_info[m_curparam]; + + info->flags = inarray ? copyback : 0; + info->marked = true; + info->size = cells; + info->str.is_sz = false; + info->orig_addr = inarray; + + m_curparam++; + + return SP_ERROR_NONE; +} + +int NativeInvoker::PushString(const char *string) +{ + return _PushString(string, SM_PARAM_STRING_COPY, 0, strlen(string)+1); +} + +int NativeInvoker::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags) +{ + return _PushString(buffer, sz_flags, cp_flags, length); +} + +int NativeInvoker::_PushString(const char *string, int sz_flags, int cp_flags, size_t len) +{ + if (m_curparam >= SP_MAX_EXEC_PARAMS) + { + return SetError(SP_ERROR_PARAMS_MAX); + } + + ParamInfo *info = &m_info[m_curparam]; + + info->marked = true; + info->orig_addr = (cell_t *)string; + info->flags = cp_flags; + info->size = len; + info->str.sz_flags = sz_flags; + info->str.is_sz = true; + + m_curparam++; + + return SP_ERROR_NONE; +} + +void NativeInvoker::Cancel() +{ + if (pContext == NULL) + { + return; + } + + m_errorstate = SP_ERROR_NONE; + m_curparam = 0; + pContext = NULL; + native = NULL; +} + +int NativeInvoker::SetError(int err) +{ + m_errorstate = err; + return err; +} + +int NativeInvoker::Invoke(cell_t *result) +{ + int err = SP_ERROR_NONE; + + if (pContext == NULL) + { + return SP_ERROR_INVALID_NATIVE; + } + + if (m_errorstate != SP_ERROR_NONE) + { + err = m_errorstate; + Cancel(); + return err; + } + + cell_t tresult; + + if (result == NULL) + { + result = &tresult; + } + + //This is for re-entrancy! + IPluginContext *ctx = pContext; + cell_t _temp_params[SP_MAX_EXEC_PARAMS + 1]; + cell_t *temp_params = &_temp_params[1]; + ParamInfo temp_info[SP_MAX_EXEC_PARAMS]; + unsigned int numparams = m_curparam; + unsigned int i; + bool docopies = true; + + if (numparams) + { + //Save the info locally, then reset it for re-entrant calls. + memcpy(temp_info, m_info, numparams * sizeof(ParamInfo)); + } + m_curparam = 0; + pContext = NULL; + + /* Initialize 0th parameter */ + _temp_params[0] = numparams; + + /* Browse the parameters and build arrays */ + for (i = 0; i < numparams; i++) + { + /* Is this marked as an array? */ + if (temp_info[i].marked) + { + if (!temp_info[i].str.is_sz) + { + /* Allocate a normal/generic array */ + if ((err = ctx->HeapAlloc(temp_info[i].size, + &temp_info[i].local_addr, + &temp_info[i].phys_addr)) + != SP_ERROR_NONE) + { + break; + } + if (temp_info[i].orig_addr) + { + memcpy(temp_info[i].phys_addr, temp_info[i].orig_addr, sizeof(cell_t) * temp_info[i].size); + } + } + else + { + /* Calculate cells required for the string */ + size_t cells = (temp_info[i].size + sizeof(cell_t) - 1) / sizeof(cell_t); + + /* Allocate the buffer */ + if ((err = ctx->HeapAlloc(cells, + &temp_info[i].local_addr, + &temp_info[i].phys_addr)) + != SP_ERROR_NONE) + { + break; + } + /* Copy original string if necessary */ + if ((temp_info[i].str.sz_flags & SM_PARAM_STRING_COPY) && (temp_info[i].orig_addr != NULL)) + { + /* Cut off UTF-8 properly */ + if (temp_info[i].str.sz_flags & SM_PARAM_STRING_UTF8) + { + if ((err = ctx->StringToLocalUTF8(temp_info[i].local_addr, + temp_info[i].size, + (const char *)temp_info[i].orig_addr, + NULL)) + != SP_ERROR_NONE) + { + break; + } + } + /* Copy a binary blob */ + else if (temp_info[i].str.sz_flags & SM_PARAM_STRING_BINARY) + { + memmove(temp_info[i].phys_addr, temp_info[i].orig_addr, temp_info[i].size); + } + /* Copy ASCII characters */ + else + { + if ((err = ctx->StringToLocal(temp_info[i].local_addr, + temp_info[i].size, + (const char *)temp_info[i].orig_addr)) + != SP_ERROR_NONE) + { + break; + } + } + } + } /* End array/string calculation */ + /* Update the pushed parameter with the byref local address */ + temp_params[i] = temp_info[i].local_addr; + } + else + { + /* Just copy the value normally */ + temp_params[i] = m_params[i]; + } + } + + /* Make the call if we can */ + if (err == SP_ERROR_NONE) + { + *result = native(ctx, _temp_params); + if (ctx->GetLastNativeError() != SP_ERROR_NONE) + { + docopies = false; + ctx->ClearLastNativeError(); + } + } + else + { + docopies = false; + } + + /* i should be equal to the last valid parameter + 1 */ + while (i--) + { + if (!temp_info[i].marked) + { + continue; + } + + if (docopies && (temp_info[i].flags & SM_PARAM_COPYBACK)) + { + if (temp_info[i].orig_addr) + { + if (temp_info[i].str.is_sz) + { + memcpy(temp_info[i].orig_addr, temp_info[i].phys_addr, temp_info[i].size); + + } + else + { + if (temp_info[i].size == 1) + { + *temp_info[i].orig_addr = *(temp_info[i].phys_addr); + } + else + { + memcpy(temp_info[i].orig_addr, + temp_info[i].phys_addr, + temp_info[i].size * sizeof(cell_t)); + } + } + } + } + + if ((err = ctx->HeapPop(temp_info[i].local_addr)) != SP_ERROR_NONE) + { + return err; + } + } + + return err; +} diff --git a/core/NativeInvoker.h b/core/NativeInvoker.h new file mode 100644 index 00000000..120b7019 --- /dev/null +++ b/core/NativeInvoker.h @@ -0,0 +1,98 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod + * Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_ +#define _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_ + +#include "sm_globals.h" +#include + +struct ParamInfo +{ + int flags; /* Copy-back flags */ + bool marked; /* Whether this is marked as being used */ + cell_t local_addr; /* Local address to free */ + cell_t *phys_addr; /* Physical address of our copy */ + cell_t *orig_addr; /* Original address to copy back to */ + ucell_t size; /* Size of array in bytes */ + struct + { + bool is_sz; /* is a string */ + int sz_flags; /* has sz flags */ + } str; +}; + +class NativeInvoker : public INativeInvoker +{ +public: + NativeInvoker(); + ~NativeInvoker(); +public: /* ICallable */ + int PushCell(cell_t cell); + int PushCellByRef(cell_t *cell, int flags=SM_PARAM_COPYBACK); + int PushFloat(float number); + int PushFloatByRef(float *number, int flags=SM_PARAM_COPYBACK); + int PushArray(cell_t *inarray, unsigned int cells, int flags=0); + int PushString(const char *string); + int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags); + void Cancel(); +public: /* INativeInvoker */ + bool Start(IPluginContext *pContext, const char *name); + int Invoke(cell_t *result); +private: + int _PushString(const char *string, int sz_flags, int cp_flags, size_t len); + int SetError(int err); +private: + IPluginContext *pContext; + SPVM_NATIVE_FUNC native; + cell_t m_params[SP_MAX_EXEC_PARAMS]; + ParamInfo m_info[SP_MAX_EXEC_PARAMS]; + unsigned int m_curparam; + int m_errorstate; +}; + +class NativeInterface : + public INativeInterface, + public SMGlobalClass +{ +public: /* SMGlobalClass */ + void OnSourceModAllInitialized(); +public: /* SMInterface */ + unsigned int GetInterfaceVersion(); + const char *GetInterfaceName(); +public: /* INativeInvoker */ + IPluginRuntime *CreateRuntime(const char *name, size_t bytes); + INativeInvoker *CreateInvoker(); +}; + +extern NativeInterface g_NInvoke; + +#endif /* _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_ */ diff --git a/core/ShareSys.h b/core/ShareSys.h index ffba6b56..b600f9c2 100644 --- a/core/ShareSys.h +++ b/core/ShareSys.h @@ -128,10 +128,10 @@ public: void BindNativesToPlugin(CPlugin *pPlugin, bool bCoreOnly); void BindNativeToPlugin(CPlugin *pPlugin, NativeEntry *pEntry); NativeEntry *AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func); + NativeEntry *FindNative(const char *name); private: NativeEntry *AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv); void ClearNativeFromCache(CNativeOwner *pOwner, const char *name); - NativeEntry *FindNative(const char *name); void BindNativeToPlugin(CPlugin *pPlugin, sp_native_t *ntv, uint32_t index, diff --git a/core/msvc9/sourcemod_mm.vcproj b/core/msvc9/sourcemod_mm.vcproj index 8ee550bf..6372c961 100644 --- a/core/msvc9/sourcemod_mm.vcproj +++ b/core/msvc9/sourcemod_mm.vcproj @@ -1185,6 +1185,10 @@ RelativePath="..\MenuVoting.cpp" > + + @@ -1391,6 +1395,10 @@ RelativePath="..\MenuVoting.h" > + + @@ -1556,6 +1564,10 @@ RelativePath="..\..\public\IMenuManager.h" > + + diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 20a4cd36..b61abcd9 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -200,7 +200,7 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t maxlength, bool late g_pSourcePawn = getv1(); g_pSourcePawn2 = getv2(); - if (g_pSourcePawn2->GetAPIVersion() < 2) + if (g_pSourcePawn2->GetAPIVersion() < 3) { g_pSourcePawn2 = NULL; if (error && maxlength) diff --git a/public/INativeInvoker.h b/public/INativeInvoker.h new file mode 100644 index 00000000..1c7025b5 --- /dev/null +++ b/public/INativeInvoker.h @@ -0,0 +1,106 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod + * Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_INATIVEINVOKER_H_ +#define _INCLUDE_SOURCEMOD_INATIVEINVOKER_H_ + +/** + * @file INativeInvoker.h + * @brief Interface for invoking natives. + */ + +#include + +#define SMINTERFACE_NINVOKE_NAME "INativeInterface" +#define SMINTERFACE_NINVOKE_VERSION 1 + +#define NINVOKE_DEFAULT_MEMORY 16384 + +namespace SourceMod +{ + class INativeInvoker : public SourcePawn::ICallable + { + public: + /** + * @brief Virtual destructor - use delete to free this. + */ + virtual ~INativeInvoker() + { + } + public: + /** + * @brief Begins a native call. + * + * During a call's preparation, no new calls may be started. + * + * @param pContext Context to invoke native under. + * @param name Name of native. + * @return True if native was found, false otherwise. + */ + virtual bool Start(IPluginContext *pContext, const char *name) = 0; + + /** + * @brief Invokes the native. The preparation state is cleared immediately, meaning that + * this object can be re-used after or even from inside the native being called. + * + * @param result Optional pointer to retrieve a result. + * @return SP_ERROR return code. + */ + virtual int Invoke(cell_t *result) = 0; + }; + + /** + * @brief Factory for dealing with native invocations. + */ + class INativeInterface : public SMInterface + { + public: + /** + * @brief Creates a virtual plugin. This can be used as an environment to invoke natives. + * + * IPluginRuntime objects must be freed with the delete operator. + * + * @param name Name, or NULL for anonymous. + * @param bytes Number of bytes for memory (NINVOKE_DEFAULT_MEMORY recommended). + * @return New runtime, or NULL on failure. + */ + virtual IPluginRuntime *CreateRuntime(const char *name, size_t bytes) = 0; + + /** + * @brief Creates an object that can be used to invoke a single native code. + * + * @return New native invoker (free with delete). + */ + virtual INativeInvoker *CreateInvoker() = 0; + }; +} + +#endif /* _INCLUDE_SOURCEMOD_INATIVEINVOKER_H_ */ diff --git a/public/sample_ext/sdk/smsdk_config.h b/public/sample_ext/sdk/smsdk_config.h index 3d4f60cc..d272d3d5 100644 --- a/public/sample_ext/sdk/smsdk_config.h +++ b/public/sample_ext/sdk/smsdk_config.h @@ -76,5 +76,6 @@ //#define SMEXT_ENABLE_TEXTPARSERS //#define SMEXT_ENABLE_USERMSGS //#define SMEXT_ENABLE_TRANSLATOR +//#define SMEXT_ENABLE_NINVOKE #endif // _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ diff --git a/public/sample_ext/sdk/smsdk_ext.cpp b/public/sample_ext/sdk/smsdk_ext.cpp index 6404a919..f31352d9 100644 --- a/public/sample_ext/sdk/smsdk_ext.cpp +++ b/public/sample_ext/sdk/smsdk_ext.cpp @@ -97,6 +97,9 @@ IUserMessages *usermsgs = NULL; #if defined SMEXT_ENABLE_TRANSLATOR ITranslator *translator = NULL; #endif +#if defined SMEXT_ENABLE_NINVOKE +INativeInterface *ninvoke = NULL; +#endif /** Exports the main interface */ PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI() diff --git a/public/sample_ext/sdk/smsdk_ext.h b/public/sample_ext/sdk/smsdk_ext.h index 115fc800..61861866 100644 --- a/public/sample_ext/sdk/smsdk_ext.h +++ b/public/sample_ext/sdk/smsdk_ext.h @@ -91,6 +91,9 @@ #if defined SMEXT_ENABLE_TRANSLATOR #include #endif +#if defined SMEXT_ENABLE_NINVOKE +#include +#endif #if defined SMEXT_CONF_METAMOD #include @@ -289,6 +292,9 @@ extern IUserMessages *usermsgs; #if defined SMEXT_ENABLE_TRANSLATOR extern ITranslator *translator; #endif +#if defined SMEXT_ENABLE_NINVOKE +extern INativeInterface *ninvoke; +#endif #if defined SMEXT_CONF_METAMOD PLUGIN_GLOBALVARS(); diff --git a/public/sourcepawn/sp_vm_api.h b/public/sourcepawn/sp_vm_api.h index 7938c12e..65e7fa3f 100644 --- a/public/sourcepawn/sp_vm_api.h +++ b/public/sourcepawn/sp_vm_api.h @@ -42,7 +42,7 @@ /** SourcePawn Engine API Version */ #define SOURCEPAWN_ENGINE_API_VERSION 4 -#define SOURCEPAWN_ENGINE2_API_VERSION 2 +#define SOURCEPAWN_ENGINE2_API_VERSION 3 #if !defined SOURCEMOD_BUILD #define SOURCEMOD_BUILD @@ -876,6 +876,11 @@ namespace SourcePawn * @return True on success, false on failure. */ virtual bool GetKey(int k, void **value) =0; + + /** + * @brief Clears the last native error. + */ + virtual void ClearLastNativeError() =0; }; @@ -1252,6 +1257,15 @@ namespace SourcePawn * Initialize() succeeded. */ virtual void Shutdown() =0; + + /** + * @brief Creates an empty plugin with a blob of memory. + * + * @param name Name, for debugging (NULL for anonymous). + * @param bytes Number of bytes of memory (hea+stk). + * @return New runtime, or NULL if not enough memory. + */ + virtual IPluginRuntime *CreateEmptyRuntime(const char *name, uint32_t memory) =0; }; }; diff --git a/sourcepawn/jit/BaseRuntime.cpp b/sourcepawn/jit/BaseRuntime.cpp index a4d88def..942eea28 100644 --- a/sourcepawn/jit/BaseRuntime.cpp +++ b/sourcepawn/jit/BaseRuntime.cpp @@ -535,3 +535,21 @@ uint32_t BaseRuntime::AddJittedFunction(JitFunction *fn) return m_NumFuncs; } + +int BaseRuntime::CreateBlank(uint32_t heastk) +{ + memset(m_pPlugin, 0, sizeof(sp_plugin_t)); + + /* Align to cell_t bytes */ + heastk += sizeof(cell_t); + heastk -= heastk % sizeof(cell_t); + + m_pPlugin->mem_size = heastk; + m_pPlugin->memory = new uint8_t[heastk]; + + m_pPlugin->profiler = g_engine2.GetProfiler(); + m_pCtx = new BaseContext(this); + m_pCo = g_Jit.StartCompilation(this); + + return SP_ERROR_NONE; +} diff --git a/sourcepawn/jit/BaseRuntime.h b/sourcepawn/jit/BaseRuntime.h index bcd797ae..2217db8f 100644 --- a/sourcepawn/jit/BaseRuntime.h +++ b/sourcepawn/jit/BaseRuntime.h @@ -27,6 +27,7 @@ public: BaseRuntime(); ~BaseRuntime(); public: + virtual int CreateBlank(uint32_t heastk); virtual int CreateFromMemory(sp_file_hdr_t *hdr, uint8_t *base); virtual bool IsDebugging(); virtual IPluginDebugInfo *GetDebugInfo(); diff --git a/sourcepawn/jit/engine2.cpp b/sourcepawn/jit/engine2.cpp index 4793611c..ad4aa9a8 100644 --- a/sourcepawn/jit/engine2.cpp +++ b/sourcepawn/jit/engine2.cpp @@ -191,3 +191,22 @@ void SourcePawnEngine2::Shutdown() { g_Jit.ShutdownJIT(); } + +IPluginRuntime *SourcePawnEngine2::CreateEmptyRuntime(const char *name, uint32_t memory) +{ + int err; + BaseRuntime *rt; + + rt = new BaseRuntime(); + if ((err = rt->CreateBlank(memory)) != SP_ERROR_NONE) + { + delete rt; + return NULL; + } + + rt->m_pPlugin->name = strdup(name != NULL ? name : ""); + + rt->ApplyCompilationOptions(NULL); + + return rt; +} diff --git a/sourcepawn/jit/engine2.h b/sourcepawn/jit/engine2.h index 6198df7a..b35410d5 100644 --- a/sourcepawn/jit/engine2.h +++ b/sourcepawn/jit/engine2.h @@ -25,6 +25,7 @@ namespace SourcePawn const char *GetErrorString(int err); bool Initialize(); void Shutdown(); + IPluginRuntime *CreateEmptyRuntime(const char *name, uint32_t memory); public: IProfiler *GetProfiler(); private: diff --git a/sourcepawn/jit/sp_vm_basecontext.cpp b/sourcepawn/jit/sp_vm_basecontext.cpp index 7fa902fe..8c91b9df 100644 --- a/sourcepawn/jit/sp_vm_basecontext.cpp +++ b/sourcepawn/jit/sp_vm_basecontext.cpp @@ -873,3 +873,8 @@ bool BaseContext::GetKey(int k, void **value) return true; } + +void BaseContext::ClearLastNativeError() +{ + m_ctx.n_err = SP_ERROR_NONE; +} diff --git a/sourcepawn/jit/sp_vm_basecontext.h b/sourcepawn/jit/sp_vm_basecontext.h index b92b33df..7bd5058a 100644 --- a/sourcepawn/jit/sp_vm_basecontext.h +++ b/sourcepawn/jit/sp_vm_basecontext.h @@ -93,6 +93,7 @@ public: //IPluginContext void SetKey(int k, void *value); bool GetKey(int k, void **value); void Refresh(); + void ClearLastNativeError(); public: bool IsInExec(); private: