initial import of dynamic native code for both the JIT and plugins
note: dependency resolution is not done yet! --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40607
This commit is contained in:
parent
7ab8e2027b
commit
7c06d89b00
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="Windows-1252"?>
|
<?xml version="1.0" encoding="Windows-1252"?>
|
||||||
<VisualStudioProject
|
<VisualStudioProject
|
||||||
ProjectType="Visual C++"
|
ProjectType="Visual C++"
|
||||||
Version="8,00"
|
Version="8.00"
|
||||||
Name="sourcemod_mm"
|
Name="sourcemod_mm"
|
||||||
ProjectGUID="{E39527CD-7CAB-4420-97CC-DA1B93B260BC}"
|
ProjectGUID="{E39527CD-7CAB-4420-97CC-DA1B93B260BC}"
|
||||||
RootNamespace="sourcemod_mm"
|
RootNamespace="sourcemod_mm"
|
||||||
@ -713,6 +713,10 @@
|
|||||||
RelativePath="..\smn_events.cpp"
|
RelativePath="..\smn_events.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\smn_fakenatives.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\smn_filesystem.cpp"
|
RelativePath="..\smn_filesystem.cpp"
|
||||||
>
|
>
|
||||||
|
430
core/smn_fakenatives.cpp
Normal file
430
core/smn_fakenatives.cpp
Normal file
@ -0,0 +1,430 @@
|
|||||||
|
/**
|
||||||
|
* ===============================================================
|
||||||
|
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
|
||||||
|
* ===============================================================
|
||||||
|
*
|
||||||
|
* This file is not open source and may not be copied without explicit
|
||||||
|
* written permission of AlliedModders LLC. This file may not be redistributed
|
||||||
|
* in whole or significant part.
|
||||||
|
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
|
||||||
|
*
|
||||||
|
* Version: $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sh_list.h>
|
||||||
|
#include <sh_string.h>
|
||||||
|
#include "sm_trie.h"
|
||||||
|
#include "sm_globals.h"
|
||||||
|
#include "PluginSys.h"
|
||||||
|
#include "sourcemod.h"
|
||||||
|
#include "sm_stringutil.h"
|
||||||
|
|
||||||
|
using namespace SourceHook;
|
||||||
|
|
||||||
|
static cell_t s_curparams[SP_MAX_EXEC_PARAMS+1];
|
||||||
|
static FakeNative *s_curnative = NULL;
|
||||||
|
static IPluginContext *s_curcaller = NULL;
|
||||||
|
|
||||||
|
cell_t FakeNativeRouter(IPluginContext *pContext, const cell_t *params, void *pData)
|
||||||
|
{
|
||||||
|
FakeNative *native = (FakeNative *)pData;
|
||||||
|
|
||||||
|
/* Check if too many parameters were passed */
|
||||||
|
if (params[0] > SP_MAX_EXEC_PARAMS)
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Called native with too many parameters (%d>%d)", params[9], SP_MAX_EXEC_PARAMS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if the native is paused */
|
||||||
|
sp_context_t *pNativeCtx = native->ctx->GetContext();
|
||||||
|
if ((pNativeCtx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED)
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Plugin owning this native is currently paused.");
|
||||||
|
}
|
||||||
|
|
||||||
|
CPlugin *pCaller = g_PluginSys.GetPluginByCtx(pContext->GetContext());
|
||||||
|
|
||||||
|
/* Save any old data on the stack */
|
||||||
|
FakeNative *pSaveNative = s_curnative;
|
||||||
|
IPluginContext *pSaveCaller = s_curcaller;
|
||||||
|
cell_t save_params[SP_MAX_EXEC_PARAMS+1];
|
||||||
|
if (pSaveNative != NULL)
|
||||||
|
{
|
||||||
|
/* Copy all old parameters */
|
||||||
|
for (cell_t i=0; i<=s_curparams[0]; i++)
|
||||||
|
{
|
||||||
|
save_params[i] = s_curparams[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save the current parameters */
|
||||||
|
s_curnative = native;
|
||||||
|
s_curcaller = pContext;
|
||||||
|
for (cell_t i=0; i<=params[0]; i++)
|
||||||
|
{
|
||||||
|
s_curparams[i] = params[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Push info and execute. */
|
||||||
|
cell_t result = 0;
|
||||||
|
native->call->PushCell(pCaller->GetMyHandle());
|
||||||
|
native->call->PushCell(params[0]);
|
||||||
|
if (native->call->Execute(&result) != SP_ERROR_NONE)
|
||||||
|
{
|
||||||
|
if (pContext->GetContext()->n_err == SP_ERROR_NONE)
|
||||||
|
{
|
||||||
|
pContext->ThrowNativeError("Error encountered while processing a dynamic native");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restore everything from the stack if necessary */
|
||||||
|
if (pSaveNative != NULL)
|
||||||
|
{
|
||||||
|
s_curnative = pSaveNative;
|
||||||
|
s_curcaller = pSaveCaller;
|
||||||
|
for (cell_t i=0; i<=save_params[0]; i++)
|
||||||
|
{
|
||||||
|
s_curparams[i] = save_params[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cell_t CreateNative(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
pContext->LocalToString(params[1], &name);
|
||||||
|
|
||||||
|
IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
|
||||||
|
if (!pFunction)
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Function %x is not a valid function", params[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_PluginSys.AddFakeNative(pFunction, name, FakeNativeRouter))
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Fatal error creating dynamic native!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cell_t ThrowNativeError(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
if (!s_curnative || (s_curnative->ctx != pContext))
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Not called from inside a native function");
|
||||||
|
}
|
||||||
|
|
||||||
|
char buffer[512];
|
||||||
|
|
||||||
|
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
|
||||||
|
|
||||||
|
if (pContext->GetContext()->n_err != SP_ERROR_NONE)
|
||||||
|
{
|
||||||
|
s_curcaller->ThrowNativeError("Error encountered while processing a dynamic native");
|
||||||
|
} else {
|
||||||
|
s_curcaller->ThrowNativeErrorEx(params[1], "%s", buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cell_t GetNativeStringLength(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
if (!s_curnative || (s_curnative->ctx != pContext))
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Not called from inside a native function");
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t param = params[1];
|
||||||
|
if (param < 1 || param > s_curparams[0])
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
|
||||||
|
}
|
||||||
|
|
||||||
|
int err;
|
||||||
|
char *str;
|
||||||
|
if ((err=s_curcaller->LocalToString(s_curparams[param], &str)) != SP_ERROR_NONE)
|
||||||
|
{
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t *addr;
|
||||||
|
pContext->LocalToPhysAddr(params[2], &addr);
|
||||||
|
*addr = (cell_t)strlen(str);
|
||||||
|
|
||||||
|
return SP_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cell_t GetNativeString(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
if (!s_curnative || (s_curnative->ctx != pContext))
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Not called from inside a native function");
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t param = params[1];
|
||||||
|
if (param < 1 || param > s_curparams[0])
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
|
||||||
|
}
|
||||||
|
|
||||||
|
int err;
|
||||||
|
char *str;
|
||||||
|
if ((err=s_curcaller->LocalToString(s_curparams[param], &str)) != SP_ERROR_NONE)
|
||||||
|
{
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t bytes = 0;
|
||||||
|
pContext->StringToLocalUTF8(params[2], params[3], str, &bytes);
|
||||||
|
|
||||||
|
cell_t *addr;
|
||||||
|
pContext->LocalToPhysAddr(params[4], &addr);
|
||||||
|
*addr = (cell_t)bytes;
|
||||||
|
|
||||||
|
return SP_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cell_t SetNativeString(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
if (!s_curnative || (s_curnative->ctx != pContext))
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Not called from inside a native function");
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t param = params[1];
|
||||||
|
if (param < 1 || param > s_curparams[0])
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *str;
|
||||||
|
pContext->LocalToString(params[2], &str);
|
||||||
|
|
||||||
|
int err;
|
||||||
|
size_t bytes = 0;
|
||||||
|
if (params[4])
|
||||||
|
{
|
||||||
|
err = s_curcaller->StringToLocalUTF8(s_curparams[param], params[3], str, &bytes);
|
||||||
|
} else {
|
||||||
|
err = s_curcaller->StringToLocal(s_curparams[param], params[3], str);
|
||||||
|
/* Eww */
|
||||||
|
bytes = strlen(str);
|
||||||
|
if (bytes >= (size_t)params[3])
|
||||||
|
{
|
||||||
|
bytes = params[3] - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err != SP_ERROR_NONE)
|
||||||
|
{
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t *addr;
|
||||||
|
pContext->LocalToPhysAddr(params[5], &addr);
|
||||||
|
*addr = (cell_t)bytes;
|
||||||
|
|
||||||
|
return SP_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cell_t GetNativeCell(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
if (!s_curnative || (s_curnative->ctx != pContext))
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Not called from inside a native function");
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t param = params[1];
|
||||||
|
if (param < 1 || param > s_curparams[0])
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
|
||||||
|
}
|
||||||
|
|
||||||
|
return s_curparams[param];
|
||||||
|
}
|
||||||
|
|
||||||
|
static cell_t GetNativeCellRef(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
if (!s_curnative || (s_curnative->ctx != pContext))
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Not called from inside a native function");
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t param = params[1];
|
||||||
|
if (param < 1 || param > s_curparams[0])
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t *addr;
|
||||||
|
if (s_curcaller->LocalToPhysAddr(s_curparams[param], &addr) != SP_ERROR_NONE)
|
||||||
|
{
|
||||||
|
return s_curcaller->ThrowNativeErrorEx(SP_ERROR_INVALID_ADDRESS, "Invalid address value");
|
||||||
|
}
|
||||||
|
|
||||||
|
return *addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cell_t SetNativeCellRef(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
if (!s_curnative || (s_curnative->ctx != pContext))
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Not called from inside a native function");
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t param = params[1];
|
||||||
|
if (param < 1 || param > s_curparams[0])
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t *addr;
|
||||||
|
if (s_curcaller->LocalToPhysAddr(s_curparams[param], &addr) != SP_ERROR_NONE)
|
||||||
|
{
|
||||||
|
return s_curcaller->ThrowNativeErrorEx(SP_ERROR_INVALID_ADDRESS, "Invalid address value");
|
||||||
|
}
|
||||||
|
|
||||||
|
*addr = params[2];
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cell_t GetNativeArray(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
if (!s_curnative || (s_curnative->ctx != pContext))
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Not called from inside a native function");
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t param = params[1];
|
||||||
|
if (param < 1 || param > s_curparams[0])
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
|
||||||
|
}
|
||||||
|
|
||||||
|
int err;
|
||||||
|
cell_t *addr;
|
||||||
|
if ((err=s_curcaller->LocalToPhysAddr(s_curparams[param], &addr)) != SP_ERROR_NONE)
|
||||||
|
{
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t *src;
|
||||||
|
pContext->LocalToPhysAddr(params[2], &src);
|
||||||
|
|
||||||
|
memcpy(src, addr, sizeof(cell_t) * params[3]);
|
||||||
|
|
||||||
|
return SP_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cell_t SetNativeArray(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
if (!s_curnative || (s_curnative->ctx != pContext))
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Not called from inside a native function");
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t param = params[1];
|
||||||
|
if (param < 1 || param > s_curparams[0])
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
|
||||||
|
}
|
||||||
|
|
||||||
|
int err;
|
||||||
|
cell_t *addr;
|
||||||
|
if ((err=s_curcaller->LocalToPhysAddr(s_curparams[param], &addr)) != SP_ERROR_NONE)
|
||||||
|
{
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t *src;
|
||||||
|
pContext->LocalToPhysAddr(params[2], &src);
|
||||||
|
|
||||||
|
memcpy(addr, src, sizeof(cell_t) * params[3]);
|
||||||
|
|
||||||
|
return SP_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cell_t FormatNativeString(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
if (!s_curnative || (s_curnative->ctx != pContext))
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Not called from inside a native function");
|
||||||
|
}
|
||||||
|
|
||||||
|
int out_param = params[1];
|
||||||
|
int fmt_param = params[2];
|
||||||
|
int var_param = params[3];
|
||||||
|
|
||||||
|
/* Validate input */
|
||||||
|
if (out_param && (out_param < 1 || out_param > s_curparams[0]))
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", out_param);
|
||||||
|
}
|
||||||
|
if (fmt_param && (fmt_param < 1 || fmt_param > s_curparams[0]))
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", fmt_param);
|
||||||
|
}
|
||||||
|
if (var_param && (var_param < 1 || var_param > s_curparams[0] + 1))
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", fmt_param);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get buffer information */
|
||||||
|
int err;
|
||||||
|
char *output_buffer;
|
||||||
|
char *format_buffer;
|
||||||
|
|
||||||
|
if (out_param)
|
||||||
|
{
|
||||||
|
if ((err=s_curcaller->LocalToString(s_curparams[out_param], &output_buffer)) != SP_ERROR_NONE)
|
||||||
|
{
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pContext->LocalToString(params[6], &output_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fmt_param)
|
||||||
|
{
|
||||||
|
if ((err=s_curcaller->LocalToString(s_curparams[fmt_param], &format_buffer)) != SP_ERROR_NONE)
|
||||||
|
{
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pContext->LocalToString(params[7], &format_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get maximum length */
|
||||||
|
size_t maxlen = (size_t)params[4];
|
||||||
|
|
||||||
|
/* Do the format */
|
||||||
|
size_t written = atcprintf(output_buffer, maxlen, format_buffer, s_curcaller, s_curparams, &var_param);
|
||||||
|
|
||||||
|
cell_t *addr;
|
||||||
|
pContext->LocalToPhysAddr(params[5], &addr);
|
||||||
|
*addr = (cell_t)written;
|
||||||
|
|
||||||
|
return s_curcaller->GetContext()->n_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
//tee hee
|
||||||
|
REGISTER_NATIVES(nativeNatives)
|
||||||
|
{
|
||||||
|
{"CreateNative", CreateNative},
|
||||||
|
{"GetNativeArray", GetNativeArray},
|
||||||
|
{"GetNativeCell", GetNativeCell},
|
||||||
|
{"GetNativeCellRef", GetNativeCellRef},
|
||||||
|
{"GetNativeString", GetNativeString},
|
||||||
|
{"GetNativeStringLength", GetNativeStringLength},
|
||||||
|
{"FormatNativeString", FormatNativeString},
|
||||||
|
{"ThrowNativeError", ThrowNativeError},
|
||||||
|
{"SetNativeArray", SetNativeArray},
|
||||||
|
{"SetNativeCellRef", SetNativeCellRef},
|
||||||
|
{"SetNativeString", SetNativeString},
|
||||||
|
{NULL, NULL},
|
||||||
|
};
|
@ -588,6 +588,7 @@ CPluginManager::CPluginManager()
|
|||||||
m_LoadLookup = sm_trie_create();
|
m_LoadLookup = sm_trie_create();
|
||||||
m_AllPluginsLoaded = false;
|
m_AllPluginsLoaded = false;
|
||||||
m_MyIdent = NULL;
|
m_MyIdent = NULL;
|
||||||
|
m_pNativeLookup = sm_trie_create();
|
||||||
}
|
}
|
||||||
|
|
||||||
CPluginManager::~CPluginManager()
|
CPluginManager::~CPluginManager()
|
||||||
@ -598,9 +599,9 @@ CPluginManager::~CPluginManager()
|
|||||||
* will crash anyway. YAY
|
* will crash anyway. YAY
|
||||||
*/
|
*/
|
||||||
sm_trie_destroy(m_LoadLookup);
|
sm_trie_destroy(m_LoadLookup);
|
||||||
|
sm_trie_destroy(m_pNativeLookup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CPluginManager::LoadAll_FirstPass(const char *config, const char *basedir)
|
void CPluginManager::LoadAll_FirstPass(const char *config, const char *basedir)
|
||||||
{
|
{
|
||||||
/* First read in the database of plugin settings */
|
/* First read in the database of plugin settings */
|
||||||
@ -958,6 +959,7 @@ bool CPluginManager::RunSecondPass(CPlugin *pPlugin, char *error, size_t maxleng
|
|||||||
|
|
||||||
/* Bind all extra natives */
|
/* Bind all extra natives */
|
||||||
g_Extensions.BindAllNativesToPlugin(pPlugin);
|
g_Extensions.BindAllNativesToPlugin(pPlugin);
|
||||||
|
AddFakeNativesToPlugin(pPlugin);
|
||||||
|
|
||||||
/* Find any unbound natives
|
/* Find any unbound natives
|
||||||
* Right now, these are not allowed
|
* Right now, these are not allowed
|
||||||
@ -1013,6 +1015,32 @@ void CPluginManager::AddCoreNativesToPlugin(CPlugin *pPlugin)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CPluginManager::AddFakeNativesToPlugin(CPlugin *pPlugin)
|
||||||
|
{
|
||||||
|
IPluginContext *pContext = pPlugin->GetBaseContext();
|
||||||
|
sp_nativeinfo_t native;
|
||||||
|
|
||||||
|
List<FakeNative *>::iterator iter;
|
||||||
|
FakeNative *pNative;
|
||||||
|
sp_context_t *ctx;
|
||||||
|
for (iter = m_Natives.begin(); iter != m_Natives.end(); iter++)
|
||||||
|
{
|
||||||
|
pNative = (*iter);
|
||||||
|
ctx = pNative->ctx->GetContext();
|
||||||
|
if ((ctx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED)
|
||||||
|
{
|
||||||
|
/* Ignore natives in paused plugins */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
native.name = pNative->name.c_str();
|
||||||
|
native.func = pNative->func;
|
||||||
|
if (pContext->BindNative(&native) == SP_ERROR_NONE)
|
||||||
|
{
|
||||||
|
/* :TODO: add to dependency list */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool CPluginManager::UnloadPlugin(IPlugin *plugin)
|
bool CPluginManager::UnloadPlugin(IPlugin *plugin)
|
||||||
{
|
{
|
||||||
CPlugin *pPlugin = (CPlugin *)plugin;
|
CPlugin *pPlugin = (CPlugin *)plugin;
|
||||||
@ -1675,3 +1703,28 @@ void CPluginManager::_SetPauseState(CPlugin *pl, bool paused)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CPluginManager::AddFakeNative(IPluginFunction *pFunction, const char *name, SPVM_FAKENATIVE_FUNC func)
|
||||||
|
{
|
||||||
|
if (sm_trie_retrieve(m_pNativeLookup, name, NULL))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FakeNative *pNative = new FakeNative;
|
||||||
|
|
||||||
|
pNative->func = g_pVM->CreateFakeNative(func, pNative);
|
||||||
|
if (!pNative->func)
|
||||||
|
{
|
||||||
|
delete pNative;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pNative->call = pFunction;
|
||||||
|
pNative->name.assign(name);
|
||||||
|
pNative->ctx = pFunction->GetParentContext();
|
||||||
|
|
||||||
|
m_Natives.push_back(pNative);
|
||||||
|
sm_trie_insert(m_pNativeLookup, name,pNative);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include <sh_list.h>
|
#include <sh_list.h>
|
||||||
#include <sh_stack.h>
|
#include <sh_stack.h>
|
||||||
#include <sh_vector.h>
|
#include <sh_vector.h>
|
||||||
|
#include <sh_string.h>
|
||||||
#include "sm_globals.h"
|
#include "sm_globals.h"
|
||||||
#include "vm/sp_vm_basecontext.h"
|
#include "vm/sp_vm_basecontext.h"
|
||||||
#include "PluginInfoDatabase.h"
|
#include "PluginInfoDatabase.h"
|
||||||
@ -232,6 +233,14 @@ private:
|
|||||||
Trie *m_pProps;
|
Trie *m_pProps;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct FakeNative
|
||||||
|
{
|
||||||
|
IPluginContext *ctx;
|
||||||
|
IPluginFunction *call;
|
||||||
|
String name;
|
||||||
|
SPVM_NATIVE_FUNC func;
|
||||||
|
};
|
||||||
|
|
||||||
class CPluginManager :
|
class CPluginManager :
|
||||||
public IPluginManager,
|
public IPluginManager,
|
||||||
public SMGlobalClass,
|
public SMGlobalClass,
|
||||||
@ -380,6 +389,10 @@ protected:
|
|||||||
{
|
{
|
||||||
return m_MyIdent;
|
return m_MyIdent;
|
||||||
}
|
}
|
||||||
|
public:
|
||||||
|
bool AddFakeNative(IPluginFunction *pFunction, const char *name, SPVM_FAKENATIVE_FUNC func);
|
||||||
|
private:
|
||||||
|
void AddFakeNativesToPlugin(CPlugin *pPlugin);
|
||||||
private:
|
private:
|
||||||
List<IPluginsListener *> m_listeners;
|
List<IPluginsListener *> m_listeners;
|
||||||
List<CPlugin *> m_plugins;
|
List<CPlugin *> m_plugins;
|
||||||
@ -389,6 +402,11 @@ private:
|
|||||||
Trie *m_LoadLookup;
|
Trie *m_LoadLookup;
|
||||||
bool m_AllPluginsLoaded;
|
bool m_AllPluginsLoaded;
|
||||||
IdentityToken_t *m_MyIdent;
|
IdentityToken_t *m_MyIdent;
|
||||||
|
|
||||||
|
/* Dynamic native stuff */
|
||||||
|
List<FakeNative *> m_Natives;
|
||||||
|
Trie *m_pNativeLookup;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern CPluginManager g_PluginSys;
|
extern CPluginManager g_PluginSys;
|
||||||
|
205
plugins/include/functions.inc
Normal file
205
plugins/include/functions.inc
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
/**
|
||||||
|
* vim: set ts=4 :
|
||||||
|
* ===============================================================
|
||||||
|
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
|
||||||
|
* ===============================================================
|
||||||
|
*
|
||||||
|
* This file is part of the SourceMod/SourcePawn SDK. This file may only be used
|
||||||
|
* or modified under the Terms and Conditions of its License Agreement, which is found
|
||||||
|
* in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins
|
||||||
|
* may change at any time. To view the latest information, see:
|
||||||
|
* http://www.sourcemod.net/license.php
|
||||||
|
*
|
||||||
|
* Version: $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SP_ERROR_NONE 0 /**< No error occurred */
|
||||||
|
#define SP_ERROR_FILE_FORMAT 1 /**< File format unrecognized */
|
||||||
|
#define SP_ERROR_DECOMPRESSOR 2 /**< A decompressor was not found */
|
||||||
|
#define SP_ERROR_HEAPLOW 3 /**< Not enough space left on the heap */
|
||||||
|
#define SP_ERROR_PARAM 4 /**< Invalid parameter or parameter type */
|
||||||
|
#define SP_ERROR_INVALID_ADDRESS 5 /**< A memory address was not valid */
|
||||||
|
#define SP_ERROR_NOT_FOUND 6 /**< The object in question was not found */
|
||||||
|
#define SP_ERROR_INDEX 7 /**< Invalid index parameter */
|
||||||
|
#define SP_ERROR_STACKLOW 8 /**< Nnot enough space left on the stack */
|
||||||
|
#define SP_ERROR_NOTDEBUGGING 9 /**< Debug mode was not on or debug section not found */
|
||||||
|
#define SP_ERROR_INVALID_INSTRUCTION 10 /**< Invalid instruction was encountered */
|
||||||
|
#define SP_ERROR_MEMACCESS 11 /**< Invalid memory access */
|
||||||
|
#define SP_ERROR_STACKMIN 12 /**< Stack went beyond its minimum value */
|
||||||
|
#define SP_ERROR_HEAPMIN 13 /**< Heap went beyond its minimum value */
|
||||||
|
#define SP_ERROR_DIVIDE_BY_ZERO 14 /**< Division by zero */
|
||||||
|
#define SP_ERROR_ARRAY_BOUNDS 15 /**< Array index is out of bounds */
|
||||||
|
#define SP_ERROR_INSTRUCTION_PARAM 16 /**< Instruction had an invalid parameter */
|
||||||
|
#define SP_ERROR_STACKLEAK 17 /**< A native leaked an item on the stack */
|
||||||
|
#define SP_ERROR_HEAPLEAK 18 /**< A native leaked an item on the heap */
|
||||||
|
#define SP_ERROR_ARRAY_TOO_BIG 19 /**< A dynamic array is too big */
|
||||||
|
#define SP_ERROR_TRACKER_BOUNDS 20 /**< Tracker stack is out of bounds */
|
||||||
|
#define SP_ERROR_INVALID_NATIVE 21 /**< Native was pending or invalid */
|
||||||
|
#define SP_ERROR_PARAMS_MAX 22 /**< Maximum number of parameters reached */
|
||||||
|
#define SP_ERROR_NATIVE 23 /**< Error originates from a native */
|
||||||
|
#define SP_ERROR_NOT_RUNNABLE 24 /**< Function or plugin is not runnable */
|
||||||
|
#define SP_ERROR_ABORTED 25 /**< Function call was aborted */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a native function.
|
||||||
|
*
|
||||||
|
* It is not necessary to validate the parameter count
|
||||||
|
*
|
||||||
|
* @param plugin Handle of the calling plugin.
|
||||||
|
* @param numParams Number of parameters passed to the native.
|
||||||
|
* @return Value for the native call to return.
|
||||||
|
*/
|
||||||
|
functag NativeCall public(Handle:plugin, numParams);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a dynamic native. This should only be called in AskPluginLoad(), or
|
||||||
|
* else you risk not having your native shared with other plugins.
|
||||||
|
*
|
||||||
|
* @param name Name of the dynamic native; must be unique amongst
|
||||||
|
* all other registered dynamic native.s
|
||||||
|
* @param func Function to use as the dynamic native.
|
||||||
|
* @noreturn
|
||||||
|
*/
|
||||||
|
native CreateNative(const String:name[], NativeCall:func);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throws an error in the calling plugin of a native, instead of your own plugin.
|
||||||
|
*
|
||||||
|
* @param error Error code to use.
|
||||||
|
* @param fmt Error message format.
|
||||||
|
* @param ... Format arguments.
|
||||||
|
*/
|
||||||
|
native ThrowNativeError(error, const String:fmt[], {Handle,Float,String,_}:...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the string length from a native parameter string. This is useful
|
||||||
|
* fetching the entire string using dynamic arrays.
|
||||||
|
* @note If this function succeeds, Get/SetNativeString will also succeed.
|
||||||
|
*
|
||||||
|
* @param param Parameter number, starting from 1.
|
||||||
|
* @param length Stores the length of the string.
|
||||||
|
* @return SP_ERROR_NONE on sucecss, any other integer on failure.
|
||||||
|
* @error Invalid parameter number or calling from a non-native function.
|
||||||
|
*/
|
||||||
|
native GetNativeStringLength(param, &length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a string from a native parameter.
|
||||||
|
* @note Output conditions are undefined on failure.
|
||||||
|
*
|
||||||
|
* @param param Parameter number, starting from 1.
|
||||||
|
* @param buffer Buffer to store the string in.
|
||||||
|
* @param maxlength Maximum length of the buffer.
|
||||||
|
* @param bytes Optionally store the number of bytes written.
|
||||||
|
* @return SP_ERROR_NONE on success, any other integer on failure.
|
||||||
|
* @error Invalid parameter number or calling from a non-native function.
|
||||||
|
*/
|
||||||
|
native GetNativeString(param, String:buffer[], maxlength, &bytes=0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a string in a native parameter.
|
||||||
|
* @note Output conditions are undefined on failure.
|
||||||
|
*
|
||||||
|
* @param param Parameter number, starting from 1.
|
||||||
|
* @param source Source string to use.
|
||||||
|
* @param maxlength Maximum number of bytes to write.
|
||||||
|
* @param utf8 If false, string will not be written
|
||||||
|
* with UTF8 safety.
|
||||||
|
* @param bytes Optionally store the number of bytes written.
|
||||||
|
* @return SP_ERROR_NONE on success, any other integer on failure.
|
||||||
|
* @error Invalid parameter number or calling from a non-native function.
|
||||||
|
*/
|
||||||
|
native SetNativeString(param, const String:source[], maxlength, bool:utf8=true, &bytes=0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a cell from a native parameter.
|
||||||
|
*
|
||||||
|
* @param param Parameter number, starting from 1.
|
||||||
|
* @return Cell value at the parameter number.
|
||||||
|
* @error Invalid parameter number or calling from a non-native function.
|
||||||
|
*/
|
||||||
|
native GetNativeCell(param);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a cell from a native parameter, by reference.
|
||||||
|
*
|
||||||
|
* @param param Parameter number, starting from 1.
|
||||||
|
* @return Cell value at the parameter number.
|
||||||
|
* @error Invalid parameter number or calling from a non-native function.
|
||||||
|
*/
|
||||||
|
native GetNativeCellRef(param);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a cell from a native parameter, by reference.
|
||||||
|
*
|
||||||
|
* @param param Parameter number, starting from 1.
|
||||||
|
* @param value Cell value at the parameter number to set by reference.
|
||||||
|
* @noreturn
|
||||||
|
* @error Invalid parameter number or calling from a non-native function.
|
||||||
|
*/
|
||||||
|
native SetNativeCellRef(param, {Float,Handle,_}:value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an array from a native parameter (always by reference).
|
||||||
|
*
|
||||||
|
* @param param Parameter number, starting from 1.
|
||||||
|
* @param local Local array to copy into.
|
||||||
|
* @param size Maximum size of local array.
|
||||||
|
* @return SP_ERROR_NONE on success, anything else on failure.
|
||||||
|
* @error Invalid parameter number or calling from a non-native function.
|
||||||
|
*/
|
||||||
|
native GetNativeArray(param, {Float,Handle,_}:local[], size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies a local array into a native parameter array (always by reference).
|
||||||
|
*
|
||||||
|
* @param param Parameter number, starting from 1.
|
||||||
|
* @param local Local array to copy from.
|
||||||
|
* @param size Size of the local array to copy.
|
||||||
|
* @return SP_ERROR_NONE on success, anything else on failure.
|
||||||
|
* @error Invalid parameter number or calling from a non-native function.
|
||||||
|
*/
|
||||||
|
native SetNativeArray(param, const {Float,Handle,_}:local[], size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats a string using parameters from a native.
|
||||||
|
*
|
||||||
|
* @note All parameter indexes start at 1.
|
||||||
|
* @note If the input and output buffers overlap, the contents
|
||||||
|
* of the output buffer at the end is undefined.
|
||||||
|
*
|
||||||
|
* @param out_param Output parameter number to write to. If 0, out_string is used.
|
||||||
|
* @param fmt_param Format parameter number. If 0, fmt_string is used.
|
||||||
|
* @param vararg_param First variable parameter number.
|
||||||
|
* @param out_len Output string buffer maximum length (always required).
|
||||||
|
* @param written Optionally stores the number of bytes written.
|
||||||
|
* @param out_string Output string buffer to use if out_param is not used.
|
||||||
|
* @param fmt_string Format string to use if fmt_param is not used.
|
||||||
|
* @return SP_ERROR_NONE on success, anything else on failure.
|
||||||
|
*/
|
||||||
|
native FormatNativeString(out_param,
|
||||||
|
fmt_param,
|
||||||
|
vararg_param,
|
||||||
|
out_len,
|
||||||
|
&written=0,
|
||||||
|
String:out_string[]="",
|
||||||
|
const String:fmt_string[]="");
|
||||||
|
|
||||||
|
stock Float:GetNativeFloat(param, bool:byref)
|
||||||
|
{
|
||||||
|
if (!byref)
|
||||||
|
{
|
||||||
|
return Float:GetNativeCell(param);
|
||||||
|
} else {
|
||||||
|
return Float:GetNativeCellRef(param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stock Handle:GetNativeHandle(param, bool:byref)
|
||||||
|
{
|
||||||
|
if (!byref)
|
||||||
|
{
|
||||||
|
return Handle:GetNativeCell(param);
|
||||||
|
} else {
|
||||||
|
return Handle:GetNativeCellRef(param);
|
||||||
|
}
|
||||||
|
}
|
@ -39,6 +39,7 @@ struct Plugin
|
|||||||
#include <clients>
|
#include <clients>
|
||||||
#include <usermessages>
|
#include <usermessages>
|
||||||
#include <events>
|
#include <events>
|
||||||
|
#include <functions>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Declare this as a struct in your plugin to expose its information.
|
* Declare this as a struct in your plugin to expose its information.
|
||||||
|
85
plugins/testsuite/fakenative1.sp
Normal file
85
plugins/testsuite/fakenative1.sp
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
#include <sourcemod>
|
||||||
|
|
||||||
|
public Plugin:myinfo =
|
||||||
|
{
|
||||||
|
name = "FakeNative Testing Lab #1",
|
||||||
|
author = "AlliedModders LLC",
|
||||||
|
description = "Test suite #1 for dynamic natives",
|
||||||
|
version = "1.0.0.0",
|
||||||
|
url = "http://www.sourcemod.net/"
|
||||||
|
};
|
||||||
|
|
||||||
|
public bool:AskPluginLoad(Handle:myself, bool:late, String:error[], err_max)
|
||||||
|
{
|
||||||
|
CreateNative("TestNative1", __TestNative1);
|
||||||
|
CreateNative("TestNative2", __TestNative2);
|
||||||
|
CreateNative("TestNative3", __TestNative3);
|
||||||
|
CreateNative("TestNative4", __TestNative4);
|
||||||
|
CreateNative("TestNative5", __TestNative5);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public __TestNative1(Handle:plugin, numParams)
|
||||||
|
{
|
||||||
|
PrintToServer("TestNative1: Plugin: %x params: %d", plugin, numParams);
|
||||||
|
if (numParams == 4)
|
||||||
|
{
|
||||||
|
ThrowNativeError(SP_ERROR_NATIVE, "Four parameters ARE NOT ALLOWED lol");
|
||||||
|
}
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
public __TestNative2(Handle:plugin, numParams)
|
||||||
|
{
|
||||||
|
new String:buffer[512];
|
||||||
|
new bytes;
|
||||||
|
|
||||||
|
GetNativeString(1, buffer, sizeof(buffer), bytes);
|
||||||
|
|
||||||
|
for (new i=0; i<bytes; i++)
|
||||||
|
{
|
||||||
|
buffer[i] = buffer[i] + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetNativeString(1, buffer, bytes+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public __TestNative3(Handle:plugin, numParams)
|
||||||
|
{
|
||||||
|
new val1 = GetNativeCell(1);
|
||||||
|
new val2 = GetNativeCellRef(2);
|
||||||
|
|
||||||
|
SetNativeCellRef(2, val1+val2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public __TestNative4(Handle:plugin, numParams)
|
||||||
|
{
|
||||||
|
new size = GetNativeCell(3);
|
||||||
|
new local[size];
|
||||||
|
|
||||||
|
GetNativeArray(1, local, size);
|
||||||
|
SetNativeArray(2, local, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public __TestNative5(Handle:plugin, numParams)
|
||||||
|
{
|
||||||
|
new local = GetNativeCell(1);
|
||||||
|
|
||||||
|
if (local)
|
||||||
|
{
|
||||||
|
FormatNativeString(2, 4, 5, GetNativeCell(3));
|
||||||
|
} else {
|
||||||
|
new len = GetNativeCell(3);
|
||||||
|
new fmt_len;
|
||||||
|
new String:buffer[len];
|
||||||
|
|
||||||
|
GetNativeStringLength(4, fmt_len);
|
||||||
|
|
||||||
|
new String:format[fmt_len];
|
||||||
|
|
||||||
|
GetNativeString(2, buffer, len);
|
||||||
|
GetNativeString(4, format, fmt_len);
|
||||||
|
|
||||||
|
FormatNativeString(0, 0, 5, len, _, buffer, format);
|
||||||
|
}
|
||||||
|
}
|
87
plugins/testsuite/fakenative2.sp
Normal file
87
plugins/testsuite/fakenative2.sp
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
#include <sourcemod>
|
||||||
|
|
||||||
|
native TestNative1(gaben, ...);
|
||||||
|
native TestNative2(String:buffer[]);
|
||||||
|
native TestNative3(value1, &value2);
|
||||||
|
native TestNative4(const input[], output[], size);
|
||||||
|
native TestNative5(bool:local, String:buffer[], maxlength, const String:fmt[], {Handle,Float,String,_}:...);
|
||||||
|
|
||||||
|
public Plugin:myinfo =
|
||||||
|
{
|
||||||
|
name = "FakeNative Testing Lab #2",
|
||||||
|
author = "AlliedModders LLC",
|
||||||
|
description = "Test suite #2 for dynamic natives",
|
||||||
|
version = "1.0.0.0",
|
||||||
|
url = "http://www.sourcemod.net/"
|
||||||
|
};
|
||||||
|
|
||||||
|
public OnPluginStart()
|
||||||
|
{
|
||||||
|
RegServerCmd("test_native1", Test_Native1);
|
||||||
|
RegServerCmd("test_native2", Test_Native2);
|
||||||
|
RegServerCmd("test_native3", Test_Native3);
|
||||||
|
RegServerCmd("test_native4", Test_Native4);
|
||||||
|
RegServerCmd("test_native5", Test_Native5);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Action:Test_Native1(args)
|
||||||
|
{
|
||||||
|
PrintToServer("Returned: %d", TestNative1(1));
|
||||||
|
PrintToServer("Returned: %d", TestNative1(1,2));
|
||||||
|
PrintToServer("Returned: %d", TestNative1(1,2,3,4));
|
||||||
|
|
||||||
|
return Plugin_Handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Action:Test_Native2(args)
|
||||||
|
{
|
||||||
|
new String:buffer[] = "IBM";
|
||||||
|
|
||||||
|
PrintToServer("Before: %s", buffer);
|
||||||
|
|
||||||
|
TestNative2(buffer);
|
||||||
|
|
||||||
|
PrintToServer("AfteR: %s", buffer);
|
||||||
|
|
||||||
|
return Plugin_Handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Action:Test_Native3(args)
|
||||||
|
{
|
||||||
|
new value1 = 5, value2 = 6
|
||||||
|
|
||||||
|
PrintToServer("Before: %d, %d", value1, value2);
|
||||||
|
|
||||||
|
TestNative3(value1, value2);
|
||||||
|
|
||||||
|
PrintToServer("After: %d, %d", value1, value2);
|
||||||
|
|
||||||
|
return Plugin_Handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Action:Test_Native4(args)
|
||||||
|
{
|
||||||
|
new input[5] = {0, 1, 2, 3, 4};
|
||||||
|
new output[5];
|
||||||
|
|
||||||
|
TestNative4(input, output, 5);
|
||||||
|
|
||||||
|
PrintToServer("[0=%d] [1=%d] [2=%d] [3=%d] [4=%d]", input[0], input[1], input[2], input[3], input[4]);
|
||||||
|
PrintToServer("[0=%d] [1=%d] [2=%d] [3=%d] [4=%d]", output[0], output[1], output[2], output[3], output[4]);
|
||||||
|
|
||||||
|
return Plugin_Handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Action:Test_Native5(args)
|
||||||
|
{
|
||||||
|
new String:buffer1[512];
|
||||||
|
new String:buffer2[512];
|
||||||
|
|
||||||
|
TestNative5(true, buffer1, sizeof(buffer1), "%d gabens in the %s", 50, "gabpark");
|
||||||
|
TestNative5(true, buffer2, sizeof(buffer2), "%d gabens in the %s", 50, "gabpark");
|
||||||
|
|
||||||
|
PrintToServer("Test 1: %s", buffer1);
|
||||||
|
PrintToServer("Test 2: %s", buffer2);
|
||||||
|
|
||||||
|
return Plugin_Handled;
|
||||||
|
}
|
@ -28,7 +28,7 @@
|
|||||||
#include "sp_vm_types.h"
|
#include "sp_vm_types.h"
|
||||||
|
|
||||||
/** SourcePawn VM API Version */
|
/** SourcePawn VM API Version */
|
||||||
#define SOURCEPAWN_VM_API_VERSION 1
|
#define SOURCEPAWN_VM_API_VERSION 2
|
||||||
|
|
||||||
#if defined SOURCEMOD_BUILD
|
#if defined SOURCEMOD_BUILD
|
||||||
namespace SourceMod
|
namespace SourceMod
|
||||||
@ -820,6 +820,23 @@ namespace SourcePawn
|
|||||||
* @return True if code index is valid, false otherwise.
|
* @return True if code index is valid, false otherwise.
|
||||||
*/
|
*/
|
||||||
virtual bool FunctionPLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result) =0;
|
virtual bool FunctionPLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result) =0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a fake native and binds it to a general callback function.
|
||||||
|
*
|
||||||
|
* @param callback Callback function to bind the native to.
|
||||||
|
* @param pData Private data to pass to the callback when the native is invoked.
|
||||||
|
* @return A new fake native function as a wrapper around the callback.
|
||||||
|
*/
|
||||||
|
virtual SPVM_NATIVE_FUNC CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData) =0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destroys a fake native function wrapper.
|
||||||
|
*
|
||||||
|
* @param function Pointer to the fake native created by CreateFakeNative.
|
||||||
|
* @noreturn
|
||||||
|
*/
|
||||||
|
virtual void DestroyFakenative(SPVM_NATIVE_FUNC func) =0;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -136,6 +136,12 @@ struct sp_context_s;
|
|||||||
*/
|
*/
|
||||||
typedef cell_t (*SPVM_NATIVE_FUNC)(SourcePawn::IPluginContext *, const cell_t *);
|
typedef cell_t (*SPVM_NATIVE_FUNC)(SourcePawn::IPluginContext *, const cell_t *);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Fake native callback prototype, passed a context, parameter stack, and private data.
|
||||||
|
* A cell must be returned.
|
||||||
|
*/
|
||||||
|
typedef cell_t (*SPVM_FAKENATIVE_FUNC)(SourcePawn::IPluginContext *, const cell_t *, void *);
|
||||||
|
|
||||||
/**********************************************
|
/**********************************************
|
||||||
*** The following structures are bound to the VM/JIT.
|
*** The following structures are bound to the VM/JIT.
|
||||||
*** Changing them will result in necessary recompilation.
|
*** Changing them will result in necessary recompilation.
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
#include "dll_exports.h"
|
#include "dll_exports.h"
|
||||||
|
|
||||||
SourcePawn::ISourcePawnEngine *engine = NULL;
|
SourcePawn::ISourcePawnEngine *engine = NULL;
|
||||||
JITX86 jit;
|
JITX86 g_jit;
|
||||||
|
|
||||||
EXPORTFUNC int GiveEnginePointer(SourcePawn::ISourcePawnEngine *engine_p)
|
EXPORTFUNC int GiveEnginePointer(SourcePawn::ISourcePawnEngine *engine_p)
|
||||||
{
|
{
|
||||||
@ -45,7 +45,7 @@ EXPORTFUNC SourcePawn::IVirtualMachine *GetExport(unsigned int exportnum)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return &jit;
|
return &g_jit;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined __linux__
|
#if defined __linux__
|
||||||
|
@ -2188,6 +2188,52 @@ jit_rewind:
|
|||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SPVM_NATIVE_FUNC JITX86::CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData)
|
||||||
|
{
|
||||||
|
JitWriter jw;
|
||||||
|
JitWriter *jit = &jw;
|
||||||
|
|
||||||
|
jw.outbase = NULL;
|
||||||
|
jw.outptr = NULL;
|
||||||
|
jw.data = NULL;
|
||||||
|
|
||||||
|
/* First pass, calculate size */
|
||||||
|
rewind:
|
||||||
|
//push pData ;push pData
|
||||||
|
//push [esp+12] ;push params
|
||||||
|
//push [esp+12] ;push ctx
|
||||||
|
//call [callback] ;invoke the meta-callback
|
||||||
|
//add esp, 12 ;restore the stack
|
||||||
|
//ret ;return
|
||||||
|
IA32_Push_Imm32(jit, (jit_int32_t)pData);
|
||||||
|
IA32_Push_Rm_Disp8_ESP(jit, 12);
|
||||||
|
IA32_Push_Rm_Disp8_ESP(jit, 12);
|
||||||
|
uint32_t call = IA32_Call_Imm32(jit, 0);
|
||||||
|
IA32_Write_Jump32_Abs(jit, call, (void *)callback);
|
||||||
|
IA32_Add_Rm_Imm8(jit, REG_ESP, 12, MOD_REG);
|
||||||
|
IA32_Return(jit);
|
||||||
|
|
||||||
|
if (jw.outbase == NULL)
|
||||||
|
{
|
||||||
|
/* Second pass: Actually write */
|
||||||
|
jw.outbase = (jitcode_t)engine->ExecAlloc(jw.get_outputpos());
|
||||||
|
if (!jw.outbase)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
jw.outptr = jw.outbase;
|
||||||
|
|
||||||
|
goto rewind;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (SPVM_NATIVE_FUNC)jw.outbase;
|
||||||
|
}
|
||||||
|
|
||||||
|
void JITX86::DestroyFakenative(SPVM_NATIVE_FUNC func)
|
||||||
|
{
|
||||||
|
engine->ExecFree(func);
|
||||||
|
}
|
||||||
|
|
||||||
const char *JITX86::GetVMName()
|
const char *JITX86::GetVMName()
|
||||||
{
|
{
|
||||||
return "JIT (x86)";
|
return "JIT (x86)";
|
||||||
|
@ -98,6 +98,8 @@ public:
|
|||||||
unsigned int FunctionCount(const sp_context_t *ctx);
|
unsigned int FunctionCount(const sp_context_t *ctx);
|
||||||
const char *GetVersionString();
|
const char *GetVersionString();
|
||||||
const char *GetCPUOptimizations();
|
const char *GetCPUOptimizations();
|
||||||
|
SPVM_NATIVE_FUNC CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData);
|
||||||
|
void DestroyFakenative(SPVM_NATIVE_FUNC func);
|
||||||
};
|
};
|
||||||
|
|
||||||
cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params);
|
cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params);
|
||||||
|
@ -234,6 +234,10 @@
|
|||||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||||
>
|
>
|
||||||
|
<File
|
||||||
|
RelativePath="..\jit_version.tpl"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\opcode_switch.inc"
|
RelativePath="..\opcode_switch.inc"
|
||||||
>
|
>
|
||||||
|
Loading…
Reference in New Issue
Block a user