Skip to content

Commit

Permalink
Add forward and native on script vm initialized (#14)
Browse files Browse the repository at this point in the history
  • Loading branch information
FortyTwoFortyTwo authored Oct 20, 2024
1 parent 9fed663 commit da56544
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 16 deletions.
14 changes: 9 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ All builds can be found [here](https://github.com/FortyTwoFortyTwo/VScript/actio

Compiles and executes a script code with params and returns, helpful when `RunScriptCode` input does not support receiving returns.
```sp
public void OnPluginStart()
public void OnAllPluginsLoaded()
{
HSCRIPT script = VScript_CompileScript("printl(\"Wow a message!\"); return 4242; function PrintMessage(param) { printl(param) }");
Expand All @@ -44,7 +44,7 @@ This allows to directly call or detour a function without needing to manually ge
```sp
Handle g_SDKCallGetAngles;
public void OnPluginStart()
public void OnAllPluginsLoaded()
{
VScriptFunction func = VScript_GetClassFunction("CBaseEntity", "GetAngles");
g_SDKCallGetAngles = func.CreateSDKCall();
Expand Down Expand Up @@ -77,18 +77,22 @@ Creates a new native function where scripts can make use of it. Does nothing by
```sp
VScriptFunction g_NewFunction;
public void OnPluginStart()
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 OnMapStart()
public void VScript_OnScriptVMInitialized()
{
// Global function need to be registered everytime g_pScriptVM has been reset, which usually happens on mapchange
// Global function need to be registered everytime g_pScriptVM has been reset, which happens right before this forward
g_NewFunction.Register();
}
```
Expand Down
19 changes: 17 additions & 2 deletions scripting/include/vscript.inc
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ methodmap VScriptFunction < Address
// @param from A function to copy from.
public native void CopyFrom(VScriptFunction from);

// Register this as a global function until when g_pScriptVM has been reset.
// Register this as a global function until when g_pScriptVM has been reset. This should be called inside VScript_OnScriptVMInitialized forward.
public native void Register();

// Creates an SDKCall with parameters auto filled
Expand Down Expand Up @@ -302,7 +302,7 @@ methodmap VScriptClass < Address
// @return Address of VScriptFunction.
public native VScriptFunction CreateFunction();

// Register this class as an instance. This does not require calling VScript_ResetScriptVM unless if modifications were made afterward.
// Register this class as an instance. This should be used inside VScript_OnScriptVMInitialized forward.
//
// @param instance Name of an instance in script.
// @return Created HSCRIPT instance.
Expand Down Expand Up @@ -410,6 +410,20 @@ methodmap VScriptExecute < Handle
public native void GetReturnVector(float buffer[3]);
}


/**
* Called when g_pScriptVM has been fully initialized, this is where VScriptClass.RegisterInstance and VScriptFunction.Register should be called
* @note This forward does not get called on plugin lateload, use VScript_IsScriptVMInitialized to determine whenever to manually call this forward
*/
forward void VScript_OnScriptVMInitialized();

/**
* Returns whenever g_pScriptVM has been initialized, useful for plugin start to determine whenever to call VScript_ResetScriptVM or VScript_OnScriptVMInitialized if this were to return true
*
* @return True if script vm is initialized, false otherwise
*/
native bool VScript_IsScriptVMInitialized();

/**
* Deletes g_pScriptVM and creates a new one. This should be used when VScriptClass or VScriptFunction has been modified, including adding new functions to class
*/
Expand Down Expand Up @@ -675,6 +689,7 @@ public void __pl_vscript_SetNTVOptional()
MarkNativeAsOptional("VScriptExecute.GetReturnString");
MarkNativeAsOptional("VScriptExecute.GetReturnVector");

MarkNativeAsOptional("VScript_IsScriptVMInitialized");
MarkNativeAsOptional("VScript_ResetScriptVM");
MarkNativeAsOptional("VScript_CompileScript");
MarkNativeAsOptional("VScript_CompileScriptFile");
Expand Down
8 changes: 7 additions & 1 deletion scripting/vscript.sp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#include "include/vscript.inc"

#define PLUGIN_VERSION "1.9.0"
#define PLUGIN_VERSION "1.9.1"
#define PLUGIN_VERSION_REVISION "manual"

char g_sOperatingSystem[16];
Expand Down Expand Up @@ -120,6 +120,7 @@ public APLRes AskPluginLoad2(Handle hMyself, bool bLate, char[] sError, int iLen
CreateNative("VScriptExecute.GetReturnString", Native_Execute_GetReturnString);
CreateNative("VScriptExecute.GetReturnVector", Native_Execute_GetReturnVector);

CreateNative("VScript_IsScriptVMInitialized", Native_IsScriptVMInitialized);
CreateNative("VScript_ResetScriptVM", Native_ResetScriptVM);
CreateNative("VScript_CompileScript", Native_CompileScript);
CreateNative("VScript_CompileScriptFile", Native_CompileScriptFile);
Expand Down Expand Up @@ -763,6 +764,11 @@ public any Native_Execute_GetReturnVector(Handle hPlugin, int iNumParams)
return 0;
}

public any Native_IsScriptVMInitialized(Handle hPlugin, int iNumParams)
{
return GetScriptVM() != Address_Null;
}

public any Native_ResetScriptVM(Handle hPlugin, int iNumParams)
{
if (!g_bAllowResetScriptVM)
Expand Down
25 changes: 25 additions & 0 deletions scripting/vscript/list.sp
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
static int g_iInitializing;
static GlobalForward g_fOnScriptVMInitialized;

static ArrayList g_aGlobalFunctions;
static ArrayList g_aClasses;

void List_LoadGamedata(GameData hGameData)
{
g_fOnScriptVMInitialized = new GlobalForward("VScript_OnScriptVMInitialized", ET_Ignore);

DynamicDetour hDetour;

hDetour = VTable_CreateDetour(hGameData, "IScriptVM", "Init", ReturnType_Bool);
Expand All @@ -13,6 +18,9 @@ void List_LoadGamedata(GameData hGameData)

hDetour = VTable_CreateDetour(hGameData, "IScriptVM", "RegisterClass", ReturnType_Bool, HookParamType_Int);
hDetour.Enable(Hook_Post, List_RegisterClass);

hDetour = VTable_CreateDetour(hGameData, "IGameSystem", "LevelInitPreEntity", ReturnType_Bool);
hDetour.Enable(Hook_Post, List_LevelInitPreEntity);
}

void List_LoadDefaults()
Expand All @@ -26,10 +34,12 @@ void List_LoadDefaults()
HSCRIPT pScriptVM = GetScriptVM();

// Create new vscriptvm and set back, so we can collect all of the default stuffs
g_iInitializing = -1; // Don't want to call forward from this
SetScriptVM(view_as<HSCRIPT>(Address_Null));
GameSystem_ServerInit();
GameSystem_ServerTerm();
SetScriptVM(pScriptVM);
g_iInitializing = 0;

int iEntity = INVALID_ENT_REFERENCE;
while ((iEntity = FindEntityByClassname(iEntity, "*")) != INVALID_ENT_REFERENCE)
Expand All @@ -38,6 +48,9 @@ void List_LoadDefaults()

MRESReturn List_Init(Address pScriptVM, DHookReturn hReturn)
{
if (g_iInitializing == 0)
g_iInitializing = 1;

g_aGlobalFunctions.Clear();
g_aClasses.Clear();
return MRES_Ignored;
Expand All @@ -63,6 +76,18 @@ MRESReturn List_RegisterClass(Address pScriptVM, DHookReturn hReturn, DHookParam
return MRES_Ignored;
}

MRESReturn List_LevelInitPreEntity(Address pGameSystem, DHookReturn hReturn)
{
if (g_iInitializing == 1)
{
g_iInitializing = 0;
Call_StartForward(g_fOnScriptVMInitialized);
Call_Finish();
}

return MRES_Ignored;
}

void List_AddEntityScriptDesc(int iEntity)
{
VScriptClass pClass = Entity_GetScriptDesc(iEntity);
Expand Down
27 changes: 19 additions & 8 deletions scripting/vscript_test.sp
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,15 @@ public Plugin myinfo =
url = "https://github.com/FortyTwoFortyTwo/VScript",
};

public void OnMapStart()
public void OnAllPluginsLoaded()
{
VScriptFunction pFunction;
VScriptExecute hExecute;
int iValue;
char sBuffer[256];
float vecResult[3];
// Best to do it in OnAllPluginsLoaded, to ensure that vscript plugin is fully loaded

/*
* Test member call with bunch of params, this first because of resetting g_pScriptVM
*/

pFunction = VScript_CreateClassFunction("CBaseEntity", "BunchOfParams");
VScriptFunction pFunction = VScript_CreateClassFunction("CBaseEntity", "BunchOfParams");
pFunction.SetParam(1, FIELD_INTEGER);
pFunction.SetParam(2, FIELD_FLOAT);
pFunction.SetParam(3, FIELD_BOOLEAN);
Expand All @@ -45,8 +41,22 @@ public void OnMapStart()

pFunction.Return = FIELD_FLOAT;
pFunction.SetFunctionEmpty();
VScript_ResetScriptVM();

// If script vm is already initialized, force reset it as we can use modified CBaseEntity.
// If were only calling VScriptClass.RegisterInstance or VScriptFunction.Register, only need to manually call VScript_OnScriptVMInitialized() without resetting it.
if (VScript_IsScriptVMInitialized())
VScript_ResetScriptVM();
}

public void VScript_OnScriptVMInitialized()
{
VScriptFunction pFunction;
VScriptExecute hExecute;
int iValue;
char sBuffer[256];
float vecResult[3];

// BunchOfParams created at OnAllPluginsLoaded
RunScript("function BunchOfParams(entity, param1, param2, param3, param4, param5) { return entity.BunchOfParams(param1, param2, param3, param4, param5) }");

// Setup VScript Call
Expand All @@ -63,6 +73,7 @@ public void OnMapStart()
AssertInt(FIELD_VOID, hExecute.ReturnType);

// Now detour the newly created function
pFunction = VScript_GetClassFunction("CBaseEntity", "BunchOfParams");
pFunction.CreateDetour().Enable(Hook_Pre, Detour_BunchOfParams);

// Test again
Expand Down

0 comments on commit da56544

Please sign in to comment.