Global arrays/tables + finding entity scope
I'd like to know if following is possible with this plugin:
- Getting an arbitrary array/table from global scope
- Determining an entity, from which scope a detoured function was called
If possible, it would be nice to have an example included either in readme or test plugin.
HSCRIPT_RootTable has all of the global variables provided that you can use.
As for determining an entity, which function are you referring to? For a game's function its already provided at readme with the entity param, but if you want to "detour" a script function from vscript itself, it's currently not possible to detour it.
- So how can one read an array from global table? For example, if one is defined during game:
::_array <- [0, 30, 0, 0, 60] - I mean scenario like this:
Create an empty global function with this plugin and detour it.
Call said function during game
DoEntFire("some_ent", "CallScriptFunction", "MyEmptyFunc", 0.0, null, self);Is it possible to determine/reference "calling" entity? Similar to usingselfinside vscript function.
HSCRIPT_RootTable.GetValue("_array") allows you to get the array object itself, however I don't think it's possible to get the individual values as HSCRIPT methodmap only support retrieving values from a table rather than an array, since vscript <-> game code only uses table to communicate eachother.
I'm not sure if CallScriptFunction supports directly calling a global function. If it does work, then there is a hack valve had put in which you may be able to make use of from HSCRIPT_RootTable.GetValue("owninginstance").
Otherwise I'm not sure what use case you'd have into creating a global function and needing a calling entity, which i'd expect VScriptClass.CreateFunction to be used instead so you can directly get the "this" entity thats being used. I suppose that should've been mentioned in readme.
Ok, so creating an empty class function worked in my case.
In L4D2, CallScriptFunction can call global functions, at least when initiated from vscript:
DoEntFire("!self", "CallScriptFunction", "SomeGlobalFunction", 0.0, null, ent);
EntFire( "worldspawn", "CallScriptFunction", "SomeGlobalFunction", 0.1 );
About class functions, I'm not sure when/where one should create and register these. According to #7, we probably can't do it on OnScriptVMInitialized/OnAllPluginsLoaded
I've tried creating them a frame after OnMapStart. They may not appear if it's the first time level has loaded.
static VScriptFunction g_vsTeleport;
public void OnMapStart()
{
RequestFrame(CreateVScriptClassFunctions);
}
void CreateVScriptClassFunctions()
{
PrintToServer("CreateVScriptClassFunctions");
g_vsTeleport = VScript_CreateClassFunction("CBaseEntity", "DoTeleport");
g_vsTeleport.SetParam(1, FIELD_VECTOR);
g_vsTeleport.Return = FIELD_BOOLEAN;
g_vsTeleport.SetFunctionEmpty();
g_vsTeleport.CreateDetour().Enable(Hook_Post, Detour_Teleport);
g_vsTeleport.Register();
}
public MRESReturn Detour_Teleport(int iEntity, DHookReturn hReturn, DHookParam hParam)
{
static float vPos[3];
//hParam.GetObjectVarVector(1, 0, ObjectValueType_VectorPtr, vPos); // btw shouldn't this work?
PrintToServer("Detour_Teleport, it's crashin' time!! %d", EntIndexToEntRef(iEntity));
for (int i = 0; i < sizeof(vPos); i++)
vPos[i] = hParam.GetObjectVar(1, i * 4, ObjectValueType_Float);
TeleportEntity(iEntity, vPos, NULL_VECTOR, NULL_VECTOR);
hReturn.Value = true;
return MRES_Supercede;
}
] script printl(Ent(75).DoTeleport)
AN ERROR HAS OCCURED [the index 'DoTeleport' does not exist]
CALLSTACK
*FUNCTION [main()] unnamed line [1]
LOCALS
[vargv] ARRAY
[this] TABLE
Even if you reload the level, server/game will crash when calling this function anyways. Is it because of a vector?
[DHOOKS] FATAL: Failed to find return address of original function. Check the arguments and return type of your detour setup.
Since a class has been modified with its new function, VScript_ResetScriptVM need to be called afterward for the function to be used.
For the crash, does running the vscript_test plugin work for you without issue? It has a BunchOfParams function test with vector usage, but i suspect the pre-post hook usage may work differently between it that may cause the crash
Quick test attempt to load vscript_test.smx crashed both game in singleplayer, and dedicated server. I use vscript.smx v1.9.1.87
Also from experience, resetting script VM tends to break vscript mods (and allegedly is problematic on Linux) so I'd avoid doing it.
Crash is probably related to #7 then.
Resetting script VM can indeed mess things up a bit, where ideally it should only be run during map start or as soon as possible. Otherwise you'll have to create a function, then start a new map for the script VM to reset itself
If possible, would be nice to have something like VScript_OnRegisterClass(const char[] className)
For now, I guess I'll redo Entity.DoTeleport(vecPos) into global TeleportEntity(iEnt, fPosX, fPosY, fPosZ)
Continuing on vectors theme, is this just not possible for now?
Action CmdTestPathW(int client, int args)
{
static float vPos[3], fDistance;
static int iTarget, iSprite;
iTarget = GetCmdArgInt(1);
fDistance = GetCmdArgFloat(2);
if (!iTarget)
iTarget = IsDedicatedServer() ? client : 1;
if (~g_iInit & INIT_VS_PATHW) InitPathWithin();
SDKCall(g_vsPathWithin, VScript_EntityToHScript(iTarget), fDistance == 0.0 ? 250.0 : fDistance, vPos);
ReplyToCommand(client, "%.2f %.2f %.2f", vPos[0], vPos[1], vPos[2]);
iSprite = MakeEnvSprite(vPos, _, "vgui/hud/autoaim.vmt", 0.5, 5);
CreateTimer(g_fSpriteTime, RemoveEnt, iSprite);
return Plugin_Handled;
}
void InitPathWithin()
{
VScriptFunction func = VScript_GetClassFunction("CTerrorPlayer", "TryGetPathableLocationWithin");
g_vsPathWithin = func.CreateSDKCall();
g_iInit |= INIT_VS_PATHW;
}
Result always comes up as 0.0 0.0 0.0. Same when trying to call CBaseAnimating's GetBoneOrigin