You can register your own hooks or methods in Sven Co-op AngelScript engine.
// Include this header file : "metamod-fallguys\asext\include\asext_api.h"
#include "asext_api.h"
// Define this macro in meta_api.cpp
IMPORT_ASEXT_API_DEFINE();// Add the following code in meta_api.cpp->Meta_Attach
void *asextHandle = NULL;
#ifdef _WIN32
LOAD_PLUGIN(PLID, "addons/metamod/dlls/asext.dll", PLUG_LOADTIME::PT_ANYTIME, &asextHandle);
#else
LOAD_PLUGIN(PLID, "addons/metamod/dlls/asext.so", PLUG_LOADTIME::PT_ANYTIME, &asextHandle);
#endif
if (!asextHandle)
{
LOG_ERROR(PLID, "asext dll handle not found!");
return FALSE;
}
IMPORT_ASEXT_API(asext);
int SC_SERVER_DECL CASEngineFuncs__TestFunc(void* pthis SC_SERVER_DUMMYARG_NOCOMMA)
{
return 114514;
}
//Must be registered before AS initialization, Meta_Attach is okay
ASEXT_RegisterDocInitCallback([](void *pASDoc) {
ASEXT_RegisterObjectMethod(pASDoc,
"A Test Function", "CEngineFuncs", "int TestFunc()",
(void *)CASEngineFuncs__TestFunc, 3);
});
Now call g_EngineFuncs.TestFunc from angelscript, you will get test = 114514 if the registeration works fine
int test = g_EngineFuncs.TestFunc();// Define a global var
void *g_PlayerPostThinkPostHook = NULL;
//Must be registered before AS initialization, Meta_Attach is okay
g_PlayerPostThinkPostHook = ASEXT_RegisterHook("Post call of gEntityInterface.pfnPlayerPostThink", StopMode_CALL_ALL, 2, ASHookFlag_MapScript | ASHookFlag_Plugin, "Player", "PlayerPostThinkPost", "CBasePlayer@ pPlayer");
//Add to where you would like to call AngelScript hooks
void NewPlayerPostThink_Post(edict_t *pEntity)
{
if(ASEXT_CallHook)//The second arg must be zero, the third, 4th, 5th, 6th... args are the real args pass to AngelScript VM.
(*ASEXT_CallHook)(g_PlayerPostThinkPostHook, 0, pEntity->pvPrivateData);
SET_META_RESULT(MRES_IGNORED);
}Now you can register hook from AngelScript map script or plugin :
void MapInit()
{
g_Hooks.RegisterHook(Hooks::Player::PlayerPostThinkPost, @PlayerPostThinkPost);
}
void RegisterAngelScriptMethods(void)
{
ASEXT_RegisterScriptBuilderDefineCallback([](CScriptBuilder *pScriptBuilder) {
ASEXT_CScriptBuilder_DefineWord(pScriptBuilder, "METAMOD_PLUGIN_FALLGUYS");
});
}Starting from v20260208d, asext requires the angelscript.h. Add the following include directory to your CMake configuration:
include_directories(
${CMAKE_SOURCE_DIR}/hlsdk/common
${CMAKE_SOURCE_DIR}/hlsdk/dlls
${CMAKE_SOURCE_DIR}/hlsdk/pm_shared
${CMAKE_SOURCE_DIR}/hlsdk/engine
${CMAKE_SOURCE_DIR}/metamod
${CMAKE_SOURCE_DIR}/thirdparty/angelscript-sdk/angelscript/include # Mandatory for asext
)Alternatively, you can copy /thirdparty/angelscript-sdk/angelscript/include/angelscript.h into your project (not recommended).
void ASEXT_SetDefaultNamespace(CASDocumentation* pthis, const char* ns);Use this to register global properties (or other symbols) under a custom namespace.
ASEXT_SetDefaultNamespace(pASDoc, "MyNameSpace");
ASEXT_RegisterGlobalProperty(pASDoc, "zzz", "xxx", &whatever);
ASEXT_SetDefaultNamespace(pASDoc, "");The following APIs allow iterating over entries in an AngelScript dictionary object from C++:
void ASEXT_CScriptDictionary_CIterator_begin(CScriptDictionary *pScriptDictionary, CScriptDictionary_CIterator *it);
void ASEXT_CScriptDictionary_CIterator_end(CScriptDictionary *pScriptDictionary, CScriptDictionary_CIterator *it);
bool ASEXT_CScriptDictionary_CIterator_operator_NE(CScriptDictionary_CIterator *a1, CScriptDictionary_CIterator *a2);
bool ASEXT_CScriptDictionary_CIterator_GetValue(CScriptDictionary_CIterator *it, void *data, int typeId);
const char *ASEXT_CScriptDictionary_CIterator_GetKey(CScriptDictionary_CIterator *it);
void ASEXT_CScriptDictionary_CIterator_operator_PP(CScriptDictionary_CIterator *it);
asITypeInfo* ASEXT_CASBaseManager_GetTypeInfoByName(CASServerManager* pthis, const sc_stdstring *name); if ( !ASEXT_CScriptDictionary_IsEmpty(pScriptDictionary) )
{
std_string typeName{};
typeName.assign("string");
asITypeInfo* pStringTypeInfo = ASEXT_CASBaseManager_GetTypeInfoByName(ASEXT_GetServerManager(), &typeName);
CScriptDictionary_CIterator it{}, itend{};
ASEXT_CScriptDictionary_begin(pScriptDictionary, &it)
ASEXT_CScriptDictionary_end(pScriptDictionary, &itend);
for(; ASEXT_CScriptDictionary_CIterator_operator_NE(it, itend); ASEXT_CScriptDictionary_CIterator_operator_PP(&it) ) // Counter part of "it = begin; it != end; it++"
{
CString value{};
value.assign("", 0);
if ( ASEXT_CScriptDictionary_CIterator_GetValue(it, &value, pStringTypeInfo->GetTypeId() ) )
{
const CString*key = ASEXT_CScriptDictionary_CIterator_GetKey(it);
//You have both "key" and "value" as angelscript strings now.
}
value.dtor();
}
}