diff --git a/core/logic/smn_functions.cpp b/core/logic/smn_functions.cpp index 0a2f685e..0ff3cb1d 100644 --- a/core/logic/smn_functions.cpp +++ b/core/logic/smn_functions.cpp @@ -33,6 +33,8 @@ #include #include #include +#include +#include HandleType_t g_GlobalFwdType = 0; HandleType_t g_PrivateFwdType = 0; @@ -589,6 +591,63 @@ static cell_t sm_CallCancel(IPluginContext *pContext, const cell_t *params) return 1; } +struct SMFrameActionData +{ + SMFrameActionData(Handle_t handle, Handle_t ownerhandle, cell_t data) : handle(handle), ownerhandle(ownerhandle), data(data) + { + }; + Handle_t handle; + Handle_t ownerhandle; + cell_t data; +}; + +static void PawnFrameAction(void *pData) +{ + ke::AutoPtr frame(reinterpret_cast(pData)); + IPlugin *pPlugin = pluginsys->PluginFromHandle(frame->ownerhandle, NULL); + if (!pPlugin) + { + return; + } + + IChangeableForward *pForward; + HandleSecurity sec(pPlugin->GetIdentity(), g_pCoreIdent); + if (handlesys->ReadHandle(frame->handle, g_PrivateFwdType, &sec, (void **)&pForward) != HandleError_None) + { + return; + } + + pForward->PushCell(frame->data); + pForward->Execute(NULL); + + handlesys->FreeHandle(frame->handle, &sec); +} + +static cell_t sm_AddFrameAction(IPluginContext *pContext, const cell_t *params) +{ + IPlugin *pPlugin = pluginsys->FindPluginByContext(pContext->GetContext()); + IPluginFunction *pFunction = pPlugin->GetBaseContext()->GetFunctionById(params[1]); + if (!pFunction) + { + return pContext->ThrowNativeError("Invalid function id (%X)", params[1]); + } + + IChangeableForward *pForward = forwardsys->CreateForwardEx(NULL, ET_Ignore, 1, NULL, Param_Cell); + IdentityToken_t *pIdentity = pContext->GetIdentity(); + Handle_t Handle = handlesys->CreateHandle(g_PrivateFwdType, pForward, pIdentity, g_pCoreIdent, NULL); + if (Handle == BAD_HANDLE) + { + delete pForward; + return 0; + } + + pForward->AddFunction(pFunction); + + SMFrameActionData *pData = new SMFrameActionData(Handle, pPlugin->GetMyHandle(), params[2]); + g_pSM->AddFrameAction(PawnFrameAction, pData); + return 1; +} + REGISTER_NATIVES(functionNatives) { {"GetFunctionByName", sm_GetFunctionByName}, @@ -610,5 +669,6 @@ REGISTER_NATIVES(functionNatives) {"Call_PushStringEx", sm_CallPushStringEx}, {"Call_Finish", sm_CallFinish}, {"Call_Cancel", sm_CallCancel}, + {"RequestFrame", sm_AddFrameAction}, {NULL, NULL}, }; diff --git a/plugins/include/functions.inc b/plugins/include/functions.inc index 8434c4f7..e030a044 100644 --- a/plugins/include/functions.inc +++ b/plugins/include/functions.inc @@ -492,3 +492,20 @@ native FormatNativeString(out_param, &written=0, String:out_string[]="", const String:fmt_string[]=""); + +/** + * Defines a RequestFrame Callback. + * + * @param data Data passed to the RequestFrame native. + * @noreturn + */ +functag public RequestFrameCallback(any:data); + +/** + * Creates a single use Next Frame hook. + * + * @param Function Function to call on the next frame. + * @param data Value to be passed on the invocation of the Function. + * @noreturn + */ +native RequestFrame(RequestFrameCallback:Function, any:data=0);