SourceMod plugin that exposes many VScript features to make use of it. Currently supports L4D2 and TF2.
All builds can be found here. To download latest build version, select latest package then "Artifacts" section underneath.
- At least SourceMod version 1.12.0.6924
- sourcescramble
vscript.inc and vscript_test.sp should give enough documentation on how to make use of it, but below gives some basic examples on common features:
Compiles and executes a script code with params and returns, helpful when RunScriptCode
input does not support receiving returns.
public void OnAllPluginsLoaded()
{
HSCRIPT script = VScript_CompileScript("printl(\"Wow a message!\"); return 4242; function PrintMessage(param) { printl(param) }");
VScriptExecute execute = new VScriptExecute(script);
execute.Execute();
int ret = execute.ReturnValue;
PrintToServer("%d", ret); // Expected to print 4242
delete execute;
// Call a PrintMessage function
execute = new VScriptExecute(HSCRIPT_RootTable.GetValue("PrintMessage"));
execute.SetParamString(1, FIELD_CSTRING, "Hello!");
execute.Execute();
delete execute;
script.ReleaseScript();
}
This allows to directly call or detour a function without needing to manually get gamedata signatures. Parameters and returns are automatically set to the handle.
Handle g_SDKCallGetAngles;
public void OnAllPluginsLoaded()
{
VScriptFunction func = VScript_GetClassFunction("CBaseEntity", "GetAngles");
g_SDKCallGetAngles = func.CreateSDKCall();
DynamicDetour detour = func.CreateDetour();
detour.Enable(Hook_Post, Detour_GetAngles);
RegConsoleCmd("sm_getangles", Command_GetAngles);
}
Action Command_GetAngles(int client, int args)
{
float angles[3];
SDKCall(g_SDKCallGetAngles, client, angles);
ReplyToCommand(client, "result: x = %.2f, y = %.2f, z = %.2f", angles[0], angles[1], angles[2]);
return Plugin_Handled;
}
MRESReturn Detour_GetAngles(int entity, DHookReturn ret)
{
float angles[3];
ret.GetVector(angles);
PrintToServer("entity %d angles: x = %.2f, y = %.2f, z = %.2f", entity, angles[0], angles[1], angles[2]);
return MRES_Ignored;
}
Creates a new native function where scripts can make use of it. Does nothing by default but can use VScriptFunction.CreateDetour
above to do actions and set return.
VScriptFunction g_NewFunction;
public void OnAllPluginsLoaded()
{
// Create a new function, or get an existing one if name already exists
g_NewFunction = VScript_CreateGlobalFunction("NewFunction");
g_NewFunction.SetParam(1, FIELD_FLOAT);
g_NewFunction.Return = FIELD_INTEGER;
g_NewFunction.SetFunctionEmpty();
// If plugin were to be lateloaded and that script vm is already initialized, just manually call it.
if (VScript_IsScriptVMInitialized())
VScript_OnScriptVMInitialized();
}
public void VScript_OnScriptVMInitialized()
{
// Global function need to be registered everytime g_pScriptVM has been reset, which happens right before this forward
g_NewFunction.Register();
}
VScript uses FIELD_HSCRIPT to interact with entities, so VScript_EntityToHScript
and VScript_HScriptToEntity
are helpful functions to convert between entity index and hscript object to manage with it.
In L4D2 linux, attempting to reset g_pScriptVM will eventually cause a crash. For now a plugin prevents any attempts to reset such, meaning that not everything may work properly until a mapchange occurs.