Skip to content

Commit

Permalink
Add several natives for managing with class (#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
FortyTwoFortyTwo authored Oct 20, 2024
1 parent 81ad398 commit d6c8ce6
Show file tree
Hide file tree
Showing 8 changed files with 290 additions and 16 deletions.
24 changes: 24 additions & 0 deletions gamedata/vscript.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,18 @@
"windows" "0"
}

"ScriptClassDesc_t::m_pszClassname"
{
"linux" "4"
"windows" "4"
}

"ScriptClassDesc_t::m_pszDescription"
{
"linux" "8"
"windows" "8"
}

"ScriptClassDesc_t::m_pBaseDesc"
{
"linux" "12"
Expand All @@ -54,6 +66,18 @@
"windows" "16"
}

"ScriptClassDesc_t::m_pNextDesc"
{
"linux" "48"
"windows" "48"
}

"sizeof(ScriptClassDesc_t)"
{
"linux" "52"
"windows" "52"
}

"ScriptFunctionBinding_t::m_pszScriptName"
{
"linux" "0"
Expand Down
44 changes: 43 additions & 1 deletion scripting/include/vscript.inc
Original file line number Diff line number Diff line change
Expand Up @@ -254,10 +254,37 @@ methodmap VScriptClass < Address
{
// Gets the script name
//
// @param buffer Buffer to store name.
// @param buffer Buffer to store script name.
// @param length Size of buffer.
public native void GetScriptName(char[] buffer, int length);

// Sets the script name
//
// @param value Script name to set.
public native void SetScriptName(const char[] value);

// Gets the class name
//
// @param buffer Buffer to store class name.
// @param length Size of buffer.
public native void GetClassName(char[] buffer, int length);

// Sets the class name
//
// @param value Class name to set.
public native void SetClassName(const char[] value);

// Gets the description
//
// @param buffer Buffer to store name.
// @param length Size of buffer.
public native void GetDescription(char[] buffer, int length);

// Sets the description
//
// @param value Description to set.
public native void SetDescription(const char[] value);

// Get all of the functions used for this class
//
// @return Arrays of VScriptFunction, handle must be deleted when not needed.
Expand All @@ -275,6 +302,12 @@ 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.
//
// @param instance Name of an instance in script.
// @return Created HSCRIPT instance.
public native HSCRIPT RegisterInstance(const char[] instance);

// Gets the class that this is based on, Address_Null if does not have base class
property VScriptClass Base
{
Expand Down Expand Up @@ -436,6 +469,15 @@ native ArrayList VScript_GetAllClasses();
*/
native VScriptClass VScript_GetClass(const char[] className);

/**
* Gets VScriptClass from class or creates one if don't exist. VScriptClass.RegisterInstance must be called after params are filled.
*
* @param className Class name.
*
* @return Address of VScriptClass, either existing or newly created
*/
native VScriptClass VScript_CreateClass(const char[] className);

/**
* Gets VScriptFunction from class
*
Expand Down
103 changes: 101 additions & 2 deletions 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.8.7"
#define PLUGIN_VERSION "1.9.0"
#define PLUGIN_VERSION_REVISION "manual"

char g_sOperatingSystem[16];
Expand All @@ -18,6 +18,7 @@ int g_iScriptVariant_union;
int g_iScriptVariant_type;

static Handle g_hSDKCallCompileScript;
static Handle g_hSDKCallRegisterInstance;
static Handle g_hSDKCallGetInstanceEntity;

const HSCRIPT INVALID_HSCRIPT = view_as<HSCRIPT>(-1);
Expand Down Expand Up @@ -94,9 +95,15 @@ public APLRes AskPluginLoad2(Handle hMyself, bool bLate, char[] sError, int iLen
CreateNative("VScriptFunction.Class.get", Native_Function_ClassGet);

CreateNative("VScriptClass.GetScriptName", Native_Class_GetScriptName);
CreateNative("VScriptClass.SetScriptName", Native_Class_SetScriptName);
CreateNative("VScriptClass.GetClassName", Native_Class_GetClassName);
CreateNative("VScriptClass.SetClassName", Native_Class_SetClassName);
CreateNative("VScriptClass.GetDescription", Native_Class_GetDescription);
CreateNative("VScriptClass.SetDescription", Native_Class_SetDescription);
CreateNative("VScriptClass.GetAllFunctions", Native_Class_GetAllFunctions);
CreateNative("VScriptClass.GetFunction", Native_Class_GetFunction);
CreateNative("VScriptClass.CreateFunction", Native_Class_CreateFunction);
CreateNative("VScriptClass.RegisterInstance", Native_Class_RegisterInstance);
CreateNative("VScriptClass.Base.get", Native_Class_BaseGet);
CreateNative("VScriptClass.IsDerivedFrom", Native_Class_IsDerivedFrom); // legacy native, to be removed later

Expand All @@ -120,6 +127,7 @@ public APLRes AskPluginLoad2(Handle hMyself, bool bLate, char[] sError, int iLen
CreateNative("VScript_CreateTable", Native_CreateTable);
CreateNative("VScript_GetAllClasses", Native_GetAllClasses);
CreateNative("VScript_GetClass", Native_GetClass);
CreateNative("VScript_CreateClass", Native_CreateClass);
CreateNative("VScript_GetClassFunction", Native_GetClassFunction);
CreateNative("VScript_GetAllGlobalFunctions", Native_GetAllGlobalFunctions);
CreateNative("VScript_GetGlobalFunction", Native_GetGlobalFunction);
Expand Down Expand Up @@ -163,6 +171,7 @@ public void OnPluginStart()
List_LoadGamedata(hGameData);

g_hSDKCallCompileScript = CreateSDKCall(hGameData, "IScriptVM", "CompileScript", SDKType_PlainOldData, SDKType_String, SDKType_String);
g_hSDKCallRegisterInstance = CreateSDKCall(hGameData, "IScriptVM", "RegisterInstance", SDKType_PlainOldData, SDKType_PlainOldData, SDKType_String);
g_hSDKCallGetInstanceEntity = CreateSDKCall(hGameData, "IScriptVM", "GetInstanceValue", SDKType_CBaseEntity, SDKType_PlainOldData, SDKType_PlainOldData);

delete hGameData;
Expand Down Expand Up @@ -339,7 +348,7 @@ public any Native_Function_SetScriptName(Handle hPlugin, int iNumParams)
char[] sBuffer = new char[iLength + 1];
GetNativeString(2, sBuffer, iLength + 1);

// Check if script name dont already exist
// Check if script name not already exist
if (Function_GetFlags(pFunction) & SF_MEMBER_FUNC)
{
VScriptClass pClass = List_GetClassFromFunction(pFunction);
Expand Down Expand Up @@ -525,6 +534,57 @@ public any Native_Class_GetScriptName(Handle hPlugin, int iNumParams)
return 0;
}

public any Native_Class_SetScriptName(Handle hPlugin, int iNumParams)
{
VScriptClass pClass = GetNativeCell(1);

int iLength;
GetNativeStringLength(2, iLength);

char[] sBuffer = new char[iLength + 1];
GetNativeString(2, sBuffer, iLength + 1);

// Check if script name not already exist
if (List_GetClass(sBuffer))
ThrowNativeError(SP_ERROR_NATIVE, "Global function named '%s' already exists", sBuffer);

Class_SetScriptName(pClass, 2);
return 0;
}

public any Native_Class_GetClassName(Handle hPlugin, int iNumParams)
{
int iLength = GetNativeCell(3);
char[] sBuffer = new char[iLength];

Class_GetClassName(GetNativeCell(1), sBuffer, iLength);
SetNativeString(2, sBuffer, iLength);
return 0;
}

public any Native_Class_SetClassName(Handle hPlugin, int iNumParams)
{
// Could add an already exist check like SetScriptName, meh
Class_SetClassName(GetNativeCell(1), 2);
return 0;
}

public any Native_Class_GetDescription(Handle hPlugin, int iNumParams)
{
int iLength = GetNativeCell(3);
char[] sBuffer = new char[iLength];

Class_GetDescription(GetNativeCell(1), sBuffer, iLength);
SetNativeString(2, sBuffer, iLength);
return 0;
}

public any Native_Class_SetDescription(Handle hPlugin, int iNumParams)
{
Class_SetDescription(GetNativeCell(1), 2);
return 0;
}

public any Native_Class_GetAllFunctions(Handle hPlugin, int iNumParams)
{
ArrayList aList = Class_GetAllFunctions(GetNativeCell(1));
Expand All @@ -550,6 +610,26 @@ public any Native_Class_CreateFunction(Handle hPlugin, int iNumParams)
return Class_CreateFunction(GetNativeCell(1));
}

public any Native_Class_RegisterInstance(Handle hPlugin, int iNumParams)
{
int iLength;
GetNativeStringLength(2, iLength);

char[] sBuffer = new char[iLength + 1];
GetNativeString(2, sBuffer, iLength + 1);

// Second param is void *, but we can just pass string to it
HSCRIPT pInstance = SDKCall(g_hSDKCallRegisterInstance, GetScriptVM(), GetNativeCell(1), sBuffer);

// Not sure if this is the correct way to do it, but it works
ScriptVariant_t pValue = new ScriptVariant_t();
pValue.nType = FIELD_HSCRIPT;
pValue.nValue = pInstance;
HScript_SetValue(HSCRIPT_RootTable, sBuffer, pValue);

return pInstance;
}

public any Native_Class_BaseGet(Handle hPlugin, int iNumParams)
{
return Class_GetBaseDesc(GetNativeCell(1));
Expand Down Expand Up @@ -796,6 +876,25 @@ public any Native_GetClass(Handle hPlugin, int iNumParams)
return pClass;
}

public any Native_CreateClass(Handle hPlugin, int iNumParams)
{
int iLength;
GetNativeStringLength(1, iLength);

char[] sBuffer = new char[iLength + 1];
GetNativeString(1, sBuffer, iLength + 1);

VScriptClass pClass = List_GetClass(sBuffer);
if (pClass)
return pClass;

pClass = Class_Create();
Class_Init(pClass);
Class_SetScriptName(pClass, 1);
Class_SetClassName(pClass, 1);
return pClass;
}

public any Native_GetClassFunction(Handle hPlugin, int iNumParams)
{
int iClassNameLength, iFunctionNameLength;
Expand Down
77 changes: 76 additions & 1 deletion scripting/vscript/class.sp
Original file line number Diff line number Diff line change
@@ -1,23 +1,98 @@
static int g_iClassDesc_ScriptName;
static int g_iClassDesc_ClassName;
static int g_iClassDesc_Description;
static int g_iClassDesc_BaseDesc;
static int g_iClassDesc_FunctionBindings;
static int g_iClassDesc_NextDesc;
static int g_iClassDesc_sizeof;

static int g_iFunctionBinding_sizeof;

void Class_LoadGamedata(GameData hGameData)
{
g_iClassDesc_ScriptName = hGameData.GetOffset("ScriptClassDesc_t::m_pszScriptName");
g_iClassDesc_ClassName = hGameData.GetOffset("ScriptClassDesc_t::m_pszClassname");
g_iClassDesc_Description = hGameData.GetOffset("ScriptClassDesc_t::m_pszDescription");
g_iClassDesc_BaseDesc = hGameData.GetOffset("ScriptClassDesc_t::m_pBaseDesc");
g_iClassDesc_FunctionBindings = hGameData.GetOffset("ScriptClassDesc_t::m_FunctionBindings");

g_iClassDesc_NextDesc = hGameData.GetOffset("ScriptClassDesc_t::m_pNextDesc");
g_iClassDesc_sizeof = hGameData.GetOffset("sizeof(ScriptClassDesc_t)");
g_iFunctionBinding_sizeof = hGameData.GetOffset("sizeof(ScriptFunctionBinding_t)");
}

VScriptClass Class_Create()
{
// TODO proper way to handle with memory?

MemoryBlock hClass = new MemoryBlock(g_iClassDesc_sizeof);

VScriptClass pClass = view_as<VScriptClass>(hClass.Address);

hClass.Disown();
delete hClass;

List_AddClass(pClass);
return pClass;
}

void Class_Init(VScriptClass pClass)
{
for (int i = 0; i < g_iClassDesc_sizeof; i++) // Make sure that all is cleared first
StoreToAddress(pClass + view_as<Address>(i), 0, NumberType_Int8);

// Set strings as empty, but not null
Address pEmptyString = GetEmptyString();
StoreToAddress(pClass + view_as<Address>(g_iClassDesc_ScriptName), pEmptyString, NumberType_Int32);
StoreToAddress(pClass + view_as<Address>(g_iClassDesc_ClassName), pEmptyString, NumberType_Int32);
StoreToAddress(pClass + view_as<Address>(g_iClassDesc_Description), pEmptyString, NumberType_Int32);

// Add to the list for m_pNextDesc to register all.
// Correct way to do this is to fetch ScriptClassDesc_t::GetDescList and update function's retrun.
// But we can instead just look through existing list and update the last class in list to point at this class instead.

VScriptClass pOther = List_GetAllClasses().Get(0);
VScriptClass pNext = pOther;

do
{
pOther = pNext;
pNext = LoadFromAddress(pOther + view_as<Address>(g_iClassDesc_NextDesc), NumberType_Int32);
}
while (pNext);

StoreToAddress(pOther + view_as<Address>(g_iClassDesc_NextDesc), pClass, NumberType_Int32);
}

void Class_GetScriptName(VScriptClass pClass, char[] sBuffer, int iLength)
{
LoadPointerStringFromAddress(pClass + view_as<Address>(g_iClassDesc_ScriptName), sBuffer, iLength);
}

void Class_SetScriptName(VScriptClass pClass, int iParam)
{
StoreNativePointerStringToAddress(pClass + view_as<Address>(g_iClassDesc_ScriptName), iParam);
}

void Class_GetClassName(VScriptClass pClass, char[] sBuffer, int iLength)
{
LoadPointerStringFromAddress(pClass + view_as<Address>(g_iClassDesc_ClassName), sBuffer, iLength);
}

void Class_SetClassName(VScriptClass pClass, int iParam)
{
StoreNativePointerStringToAddress(pClass + view_as<Address>(g_iClassDesc_ClassName), iParam);
}

void Class_GetDescription(VScriptClass pClass, char[] sBuffer, int iLength)
{
LoadPointerStringFromAddress(pClass + view_as<Address>(g_iClassDesc_Description), sBuffer, iLength);
}

void Class_SetDescription(VScriptClass pClass, int iParam)
{
StoreNativePointerStringToAddress(pClass + view_as<Address>(g_iClassDesc_Description), iParam);
}

ArrayList Class_GetAllFunctions(VScriptClass pClass)
{
ArrayList aList = new ArrayList();
Expand Down
10 changes: 1 addition & 9 deletions scripting/vscript/function.sp
Original file line number Diff line number Diff line change
Expand Up @@ -46,19 +46,11 @@ VScriptFunction Function_Create()

void Function_Init(VScriptFunction pFunction, bool bClass)
{
static Address pEmptyString;
if (!pEmptyString)
{
MemoryBlock hMemory = new MemoryBlock(1);
pEmptyString = hMemory.Address;
hMemory.Disown();
delete hMemory;
}

for (int i = 0; i < g_iFunctionBinding_sizeof; i++) // Make sure that all is cleared first
StoreToAddress(pFunction + view_as<Address>(i), 0, NumberType_Int8);

// Set strings as empty, but not null
Address pEmptyString = GetEmptyString();
StoreToAddress(pFunction + view_as<Address>(g_iFunctionBinding_ScriptName), pEmptyString, NumberType_Int32);
StoreToAddress(pFunction + view_as<Address>(g_iFunctionBinding_FunctionName), pEmptyString, NumberType_Int32);
StoreToAddress(pFunction + view_as<Address>(g_iFunctionBinding_Description), pEmptyString, NumberType_Int32);
Expand Down
Loading

0 comments on commit d6c8ce6

Please sign in to comment.