diff --git a/.github/workflows/compile.yml b/.github/workflows/compile.yml index a061a2c..1727a1e 100644 --- a/.github/workflows/compile.yml +++ b/.github/workflows/compile.yml @@ -8,7 +8,7 @@ jobs: strategy: matrix: - version: ["1.12"] + version: ["1.13"] steps: - name: Checkout diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index 4bca70d..7b0c5d4 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -14,7 +14,7 @@ jobs: - name: Environments run: | - echo "SM_VERSION=1.12" >> $GITHUB_ENV + echo "SM_VERSION=1.13" >> $GITHUB_ENV echo "PLUGIN_VERSION_REVISION<> $GITHUB_ENV git rev-list --count HEAD >> $GITHUB_ENV echo 'EOF' >> $GITHUB_ENV diff --git a/README.md b/README.md index 7066d9e..7f148a9 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Currently supports the following games: All builds can be found in [releases](https://github.com/FortyTwoFortyTwo/VScript/releases) page, auto-built on every commits done in main branch. ## Requirements -- At least SourceMod version 1.12.0.6924 +- At least SourceMod version 1.13.0.7278 - [sourcescramble](https://forums.alliedmods.net/showthread.php?p=2657347) ## Features diff --git a/gamedata/vscript.txt b/gamedata/vscript.txt index 4586dab..afd0502 100644 --- a/gamedata/vscript.txt +++ b/gamedata/vscript.txt @@ -10,11 +10,7 @@ "windows" "windows" } - "IGameSystem" "CVScriptGameSystem" - "IScriptVM" "CSquirrelVM" - // Extra virtual functions that exists for each games - "IGameSystem::ExtraOffsets" "" "IScriptVM::ExtraOffsets" "" "AllowResetScriptVM" "1" @@ -32,10 +28,60 @@ "FIELD_QANGLE" "39" } + "Signatures" + { + "g_pScriptVM" + { + "linux" "@g_pScriptVM" + } + } + + "Addresses" + { + "g_pScriptVM" + { + "signature" "g_pScriptVM" + } + } + "Offsets" { // All offsets are based on any game with smallest offset numbers, of which a large amount of it is based from sdk2013 + // CUtlVector + + "CUtlVector::m_pMemory" + { + "linux" "0" + "windows" "0" + } + + "CUtlVector::m_nAllocationCount" + { + "linux" "4" + "windows" "4" + } + + "CUtlVector::m_nGrowSize" + { + "linux" "8" + "windows" "8" + } + + "CUtlVector::m_Size" + { + "linux" "12" + "windows" "12" + } + + "CUtlVector::m_pElements" + { + "linux" "16" + "windows" "16" + } + + // ScriptClassDesc_t + "ScriptClassDesc_t::m_pszScriptName" { "linux" "0" @@ -78,6 +124,8 @@ "windows" "52" } + // ScriptFunctionBinding_t + "ScriptFunctionBinding_t::m_pszScriptName" { "linux" "0" @@ -132,6 +180,8 @@ "windows" "48" } + // ScriptVariant_t + "ScriptVariant_t::union" { "linux" "0" @@ -156,41 +206,23 @@ "windows" "4" } + // CBaseEntity + "CBaseEntity::GetScriptDesc" { "linux" "13" "windows" "12" } - "IGameSystem::LevelInitPreEntity" - { - "linux" "4" - "windows" "4" - } - - "IGameSystem::LevelShutdownPostEntity" - { - "linux" "7" - "windows" "7" - } + // CVScriptGameSystem - "IGameSystem::FrameUpdatePostEntityThink" + "sizeof(CVScriptGameSystem)" { - "linux" "15" - "windows" "14" - } - - "CVScriptGameSystem::m_bAllowEntityCreationInScripts" - { - "linux" "12" - "windows" "12" + "linux" "16" + "windows" "16" } - "IScriptVM::Init" - { - "linux" "0" - "windows" "0" - } + // IScriptVM "IScriptVM::CompileScript" // vtable dumper got it wrong { @@ -294,6 +326,25 @@ "windows" "34" } } + + "Functions" + { + "IScriptVM::Init" + { + "signature" "IScriptVM::Init" + "callconv" "cdecl" + "return" "void" + "this" "address" + } + + "CVScriptGameSystem::LevelInitPreEntity" + { + "signature" "CVScriptGameSystem::LevelInitPreEntity" + "callconv" "cdecl" + "return" "void" + "this" "address" + } + } } "#default" @@ -306,10 +357,43 @@ "game" "tf" // Team Fortress 2 } - "Keys" + "Signatures" + { + "g_pScriptVM" + { + // CVScriptGameSystem::FrameUpdatePostEntityThink + "windows" "\x8B\x0D\x2A\x2A\x2A\x2A\x85\xC9\x74\x2A\xA1\x2A\x2A\x2A\x2A\x8B\x11\x51" + } + + "CVScriptGameSystem::LevelInitPreEntity" + { + "linux" "@_ZN18CVScriptGameSystem18LevelInitPreEntityEv" + "windows" "\x80\x3D\x2A\x2A\x2A\x2A\x00\x56\x8B\xF1\x74\x2A\x8B\x0D\x2A\x2A\x2A\x2A\x85\xC9" + } + + "CVScriptGameSystem::LevelShutdownPostEntity" + { + "linux" "@_ZN18CVScriptGameSystem23LevelShutdownPostEntityEv" + "windows" "\x80\x3D\x2A\x2A\x2A\x2A\x00\x74\x2A\x8B\x0D\x2A\x2A\x2A\x2A\x85\xC9" + } + + "IScriptVM::Init" + { + "library" "vscript" + "linux" "@_ZN11CSquirrelVM4InitEv" + "windows" "\x55\x8B\xEC\x83\xEC\x08\x2A\x68\x00\x04\x00\x00" + } + } + + "Addresses" { - // 6 - IGameSystem::LevelShutdownPreClearSteamAPIContext - "IGameSystem::ExtraOffsets" "6" + "g_pScriptVM" + { + "windows" + { + "read" "2" + } + } } "Offsets" @@ -370,5 +454,44 @@ "FIELD_UINT32" "38" // +1 "FIELD_QANGLE" "40" // +1 } + + "Signatures" + { + "g_pScriptVM" + { + // CVScriptGameSystem::FrameUpdatePostEntityThink + "windows" "\x55\x8B\xEC\x8B\x0D\x2A\x2A\x2A\x2A\x83\xEC\x0C" + } + + "CVScriptGameSystem::LevelInitPreEntity" + { + "linux" "@_ZN18CVScriptGameSystem18LevelInitPreEntityEv" + "windows" "\xB9\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\x80\x3D\x2A\x2A\x2A\x2A\x00" + } + + "CVScriptGameSystem::LevelShutdownPostEntity" + { + "linux" "@_ZN18CVScriptGameSystem23LevelShutdownPostEntityEv" + "windows" "\x80\x3D\x2A\x2A\x2A\x2A\x00\x74\x2A\xE8\x2A\x2A\x2A\x2A\xC6\x05\x2A\x2A\x2A\x2A\x01" + } + + "IScriptVM::Init" + { + "library" "vscript" + "linux" "@_ZN11CSquirrelVM4InitEv" + "windows" "\x55\x8B\xEC\x83\xE4\xF8\x83\xEC\x0C\x53\x56\x57\x8B\xF9" + } + } + + "Addresses" + { + "g_pScriptVM" + { + "windows" + { + "read" "5" + } + } + } } } \ No newline at end of file diff --git a/scripting/include/vscript.inc b/scripting/include/vscript.inc index cf1f3ba..9c3fc2f 100644 --- a/scripting/include/vscript.inc +++ b/scripting/include/vscript.inc @@ -177,7 +177,7 @@ methodmap VScriptFunction < Address public native get(); } - // Gets/Sets the address of the function + // Gets/Sets the address of the function, null if function is a virtual property Address Function { public native get(); diff --git a/scripting/vscript.sp b/scripting/vscript.sp index acff49e..3815569 100644 --- a/scripting/vscript.sp +++ b/scripting/vscript.sp @@ -1,13 +1,15 @@ +#include #include #include "include/vscript.inc" -#define PLUGIN_VERSION "1.10.0" +#define PLUGIN_VERSION "2.0.0" #define PLUGIN_VERSION_REVISION "manual" char g_sOperatingSystem[16]; bool g_bWindows; bool g_bAllowResetScriptVM; +int g_iInitializing; Address g_pToScriptVM; @@ -39,14 +41,14 @@ const VScriptFunction VScriptFunction_Invalid = view_as(Address #include "vscript/hscript.sp" #include "vscript/list.sp" #include "vscript/memory.sp" +#include "vscript/scriptvm.sp" #include "vscript/util.sp" #include "vscript/variant.sp" -#include "vscript/vtable.sp" public Plugin myinfo = { name = "VScript", - author = "42", + author = "FortyTwoFortyTwo", description = "Exposes VScript features into SourceMod", version = PLUGIN_VERSION ... "." ... PLUGIN_VERSION_REVISION, url = "https://github.com/FortyTwoFortyTwo/VScript", @@ -161,7 +163,8 @@ public void OnPluginStart() g_iScriptVariant_union = hGameData.GetOffset("ScriptVariant_t::union"); g_iScriptVariant_type = hGameData.GetOffset("ScriptVariant_t::m_type"); - VTable_LoadGamedata(hGameData); + Memory_Init(); + ScriptVM_Init(); Class_LoadGamedata(hGameData); Entity_LoadGamedata(hGameData); @@ -171,16 +174,17 @@ public void OnPluginStart() GameSystem_LoadGamedata(hGameData); HScript_LoadGamedata(hGameData); List_LoadGamedata(hGameData); + Memory_LoadGamedata(hGameData); + ScriptVM_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); + g_hSDKCallCompileScript = ScriptVM_CreateSDKCall(hGameData, "CompileScript", SDKType_PlainOldData, SDKType_String, SDKType_String); + g_hSDKCallRegisterInstance = ScriptVM_CreateSDKCall(hGameData, "RegisterInstance", SDKType_PlainOldData, SDKType_PlainOldData, SDKType_String); + g_hSDKCallGetInstanceEntity = ScriptVM_CreateSDKCall(hGameData, "GetInstanceValue", SDKType_CBaseEntity, SDKType_PlainOldData, SDKType_PlainOldData); delete hGameData; List_LoadDefaults(); Binding_Init(); - Memory_Init(); } public void OnPluginEnd() @@ -219,10 +223,29 @@ public any Native_HScript_GetValueField(Handle hPlugin, int iNumParams) public any Native_HScript_GetValue(Handle hPlugin, int iNumParams) { - ScriptVariant_t pValue = HScript_NativeGetValue(SMField_Cell); - any nValue = pValue.nValue; - delete pValue; - return nValue; + ScriptVariant_t pValue = HScript_NativeGetValue(SMField_Cell|SMField_Address); + fieldtype_t nField = pValue.nType; + + switch (Field_GetSMField(nField)) + { + case SMField_Cell: + { + any nValue = pValue.nValue; + delete pValue; + return nValue; + } + case SMField_Address: + { + Address pAddress = pValue.pAddress; + delete pValue; + return pAddress; + } + default: + { + ThrowError("Unexpected condition, file a bug report."); + return 0; + } + } } public any Native_HScript_GetValueString(Handle hPlugin, int iNumParams) @@ -261,7 +284,7 @@ public any Native_HScript_IsValueNull(Handle hPlugin, int iNumParams) public any Native_HScript_SetValue(Handle hPlugin, int iNumParams) { - HScript_NativeSetValue(SMField_Cell); + HScript_NativeSetValue(SMField_Cell|SMField_Address); return 0; } diff --git a/scripting/vscript/binding.sp b/scripting/vscript/binding.sp index 3366a04..b3deed6 100644 --- a/scripting/vscript/binding.sp +++ b/scripting/vscript/binding.sp @@ -98,13 +98,13 @@ public MRESReturn Binding_Detour(DHookReturn hReturn, DHookParam hParam) switch (Field_GetSMField(Function_GetParam(info.pFunction, i))) { - case SMField_Cell: + case SMField_Cell, SMField_Address: { iSize = 1; } case SMField_String: { - Address pString = LoadFromAddress(pArguments + view_as
(i * g_iScriptVariant_sizeof + g_iScriptVariant_union), NumberType_Int32); + Address pString = LoadAddressFromAddress(pArguments + view_as
(i * g_iScriptVariant_sizeof + g_iScriptVariant_union)); iSize = LoadStringLengthFromAddress(pString); } case SMField_Vector: @@ -133,6 +133,10 @@ public MRESReturn Binding_Detour(DHookReturn hReturn, DHookParam hParam) { a[iCount][0] = nValue; } + case SMField_Address: + { + a[iCount][0] = LoadAddressFromAddress(pArguments + view_as
(i * g_iScriptVariant_sizeof + g_iScriptVariant_union)); + } case SMField_String: { LoadStringFromAddress(nValue, view_as(a[iCount]), iMaxSize); @@ -184,7 +188,11 @@ public MRESReturn Binding_Detour(DHookReturn hReturn, DHookParam hParam) if (pReturn) { StoreToAddress(pReturn + view_as
(g_iScriptVariant_type), Field_EnumToGame(nField), NumberType_Int16); - StoreToAddress(pReturn + view_as
(g_iScriptVariant_union), nResult, NumberType_Int32); + + if (Field_GetSMField(nField) == SMField_Address) + StoreAddressToAddress(pReturn + view_as
(g_iScriptVariant_union), nResult); + else + StoreToAddress(pReturn + view_as
(g_iScriptVariant_union), nResult, NumberType_Int32); } hReturn.Value = true; diff --git a/scripting/vscript/class.sp b/scripting/vscript/class.sp index 1f1be02..a0a342c 100644 --- a/scripting/vscript/class.sp +++ b/scripting/vscript/class.sp @@ -42,9 +42,9 @@ void Class_Init(VScriptClass pClass) // Set strings as empty, but not null Address pEmptyString = GetEmptyString(); - StoreToAddress(pClass + view_as
(g_iClassDesc_ScriptName), pEmptyString, NumberType_Int32); - StoreToAddress(pClass + view_as
(g_iClassDesc_ClassName), pEmptyString, NumberType_Int32); - StoreToAddress(pClass + view_as
(g_iClassDesc_Description), pEmptyString, NumberType_Int32); + StoreAddressToAddress(pClass + view_as
(g_iClassDesc_ScriptName), pEmptyString); + StoreAddressToAddress(pClass + view_as
(g_iClassDesc_ClassName), pEmptyString); + StoreAddressToAddress(pClass + view_as
(g_iClassDesc_Description), pEmptyString); // 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. @@ -56,11 +56,11 @@ void Class_Init(VScriptClass pClass) do { pOther = pNext; - pNext = LoadFromAddress(pOther + view_as
(g_iClassDesc_NextDesc), NumberType_Int32); + pNext = view_as(LoadAddressFromAddress(pOther + view_as
(g_iClassDesc_NextDesc))); } while (pNext); - StoreToAddress(pOther + view_as
(g_iClassDesc_NextDesc), pClass, NumberType_Int32); + StoreAddressToAddress(pOther + view_as
(g_iClassDesc_NextDesc), pClass); } void Class_GetScriptName(VScriptClass pClass, char[] sBuffer, int iLength) @@ -97,8 +97,8 @@ ArrayList Class_GetAllFunctions(VScriptClass pClass) { ArrayList aList = new ArrayList(); - Address pData = LoadFromAddress(pClass + view_as
(g_iClassDesc_FunctionBindings), NumberType_Int32); - int iFunctionCount = LoadFromAddress(pClass + view_as
(g_iClassDesc_FunctionBindings) + view_as
(0x0C), NumberType_Int32); + Address pData = LoadAddressFromAddress(pClass + view_as
(g_iClassDesc_FunctionBindings)); + int iFunctionCount = Memory_UtlVectorGetSize(pClass + view_as
(g_iClassDesc_FunctionBindings)); for (int i = 0; i < iFunctionCount; i++) { VScriptFunction pFunction = view_as(pData + view_as
(g_iFunctionBinding_sizeof * i)); @@ -110,18 +110,18 @@ ArrayList Class_GetAllFunctions(VScriptClass pClass) int Class_GetFunctionCount(VScriptClass pClass) { - return LoadFromAddress(pClass + view_as
(g_iClassDesc_FunctionBindings) + view_as
(0x0C), NumberType_Int32); + return Memory_UtlVectorGetSize(pClass + view_as
(g_iClassDesc_FunctionBindings)); } VScriptFunction Class_GetFunctionFromIndex(VScriptClass pClass, int iIndex) { - Address pData = LoadFromAddress(pClass + view_as
(g_iClassDesc_FunctionBindings), NumberType_Int32); + Address pData = LoadAddressFromAddress(pClass + view_as
(g_iClassDesc_FunctionBindings)); return view_as(pData + view_as
(g_iFunctionBinding_sizeof * iIndex)); } VScriptFunction Class_GetFunctionFromName(VScriptClass pClass, const char[] sName) { - Address pData = LoadFromAddress(pClass + view_as
(g_iClassDesc_FunctionBindings), NumberType_Int32); + Address pData = LoadAddressFromAddress(pClass + view_as
(g_iClassDesc_FunctionBindings)); int iFunctionCount = Class_GetFunctionCount(pClass); for (int i = 0; i < iFunctionCount; i++) { @@ -162,7 +162,7 @@ VScriptFunction Class_CreateFunction(VScriptClass pClass) VScriptClass Class_GetBaseDesc(VScriptClass pClass) { - return LoadFromAddress(pClass + view_as
(g_iClassDesc_BaseDesc), NumberType_Int32); + return view_as(LoadAddressFromAddress(pClass + view_as
(g_iClassDesc_BaseDesc))); } bool Class_IsDerivedFrom(VScriptClass pClass, VScriptClass pBase) diff --git a/scripting/vscript/entity.sp b/scripting/vscript/entity.sp index 8008bcc..e5892c2 100644 --- a/scripting/vscript/entity.sp +++ b/scripting/vscript/entity.sp @@ -27,9 +27,9 @@ void Entity_LoadGamedata(GameData hGameData) if (!g_hSDKGetScriptDesc) LogError("Failed to create SDKCall: CBaseEntity::GetScriptDesc"); - g_hSDKCallRegisterInstance = CreateSDKCall(hGameData, "IScriptVM", "RegisterInstance", SDKType_PlainOldData, SDKType_PlainOldData, SDKType_CBaseEntity); - g_hSDKCallSetInstanceUniqeId = CreateSDKCall(hGameData, "IScriptVM", "SetInstanceUniqeId", _, SDKType_PlainOldData, SDKType_String); - g_hSDKCallGenerateUniqueKey = CreateSDKCall(hGameData, "IScriptVM", "GenerateUniqueKey", SDKType_Bool, SDKType_String, SDKType_String, SDKType_PlainOldData); + g_hSDKCallRegisterInstance = ScriptVM_CreateSDKCall(hGameData, "RegisterInstance", SDKType_PlainOldData, SDKType_PlainOldData, SDKType_CBaseEntity); + g_hSDKCallSetInstanceUniqeId = ScriptVM_CreateSDKCall(hGameData, "SetInstanceUniqeId", _, SDKType_PlainOldData, SDKType_String); + g_hSDKCallGenerateUniqueKey = ScriptVM_CreateSDKCall(hGameData, "GenerateUniqueKey", SDKType_Bool, SDKType_String, SDKType_String, SDKType_PlainOldData); } void Entity_LoadOffsets(int iEntity) @@ -41,7 +41,7 @@ void Entity_LoadOffsets(int iEntity) if (g_iOffsetScriptScope == -1) ThrowError("Could not get offset for CBaseEntity::m_ScriptScope, file a bug report."); else - g_iOffsetScriptScope += 4; + g_iOffsetScriptScope += view_as(PointerSize); } if (g_iOffsetScriptInstance == -1 || g_iOffsetScriptModelKeyValues == -1) @@ -51,8 +51,8 @@ void Entity_LoadOffsets(int iEntity) if (iOffset == -1) ThrowError("Could not get offset for CBaseEntity::m_hScriptInstance, file a bug report."); - g_iOffsetScriptInstance = iOffset - 4; - g_iOffsetScriptModelKeyValues = iOffset + 4; + g_iOffsetScriptInstance = iOffset - view_as(PointerSize); + g_iOffsetScriptModelKeyValues = iOffset + view_as(PointerSize); } } diff --git a/scripting/vscript/execute.sp b/scripting/vscript/execute.sp index 71a256d..bd5ad05 100644 --- a/scripting/vscript/execute.sp +++ b/scripting/vscript/execute.sp @@ -3,7 +3,7 @@ enum struct ExecuteParam { fieldtype_t nType; - any nValue; // int + any nValue; // int and address float vecValue[3]; // vector int iStringCount; // Amount of array indexs used to store string value } @@ -20,7 +20,7 @@ static Handle g_hSDKCallExecuteFunction; void Execute_LoadGamedata(GameData hGameData) { - g_hSDKCallExecuteFunction = CreateSDKCall(hGameData, "IScriptVM", "ExecuteFunction", SDKType_PlainOldData, SDKType_PlainOldData, SDKType_PlainOldData, SDKType_PlainOldData, SDKType_PlainOldData, SDKType_PlainOldData, SDKType_Bool); + g_hSDKCallExecuteFunction = ScriptVM_CreateSDKCall(hGameData, "ExecuteFunction", SDKType_PlainOldData, SDKType_PlainOldData, SDKType_PlainOldData, SDKType_PlainOldData, SDKType_PlainOldData, SDKType_PlainOldData, SDKType_Bool); } VScriptExecute Execute_Create(HSCRIPT pHScript, HSCRIPT hScope) @@ -175,6 +175,10 @@ ScriptStatus_t Execute_Execute(VScriptExecute aExecute) { nValue = param.nValue; } + case SMField_Address: + { + ThrowError("Not Supported yet"); + } case SMField_String: { int iLength = Execute_GetParamStringCount(aExecute, iParam + 1) * (sizeof(Execute) - 1) + 1; @@ -191,6 +195,7 @@ ScriptStatus_t Execute_Execute(VScriptExecute aExecute) } } + // TODO store to offset for SMField_Address hArgs.StoreToOffset((iParam * g_iScriptVariant_sizeof) + g_iScriptVariant_type, Field_EnumToGame(param.nType), NumberType_Int16); hArgs.StoreToOffset((iParam * g_iScriptVariant_sizeof) + g_iScriptVariant_union, nValue, NumberType_Int32); } @@ -205,7 +210,7 @@ ScriptStatus_t Execute_Execute(VScriptExecute aExecute) { execute.nReturn.nValue = 0; } - case SMField_Cell: + case SMField_Cell, SMField_Address: { execute.nReturn.nValue = pReturn.nValue; } diff --git a/scripting/vscript/field.sp b/scripting/vscript/field.sp index d4542bb..f66acae 100644 --- a/scripting/vscript/field.sp +++ b/scripting/vscript/field.sp @@ -1,10 +1,11 @@ enum SMField { - SMField_Unknwon, - SMField_Void, - SMField_Cell, - SMField_String, - SMField_Vector, + SMField_Invalid = 0, + SMField_Void = (1 << 0), + SMField_Cell = (1 << 1), + SMField_Address = (1 << 2), + SMField_String = (1 << 3), + SMField_Vector = (1 << 4), } const int FIELD_MAX = view_as(FIELD_UINT32) + 1; @@ -17,7 +18,7 @@ enum struct FieldInfo SDKPassMethod nSDKPassMethod; ReturnType nReturnType; HookParamType nHookParamType; - int iSize; + int iSize; // if initialized as 0, set it to PointerSize int iGameValue; } @@ -28,10 +29,10 @@ static FieldInfo g_FieldInfos[FIELD_MAX] = { { "FIELD_VECTOR", SMField_Vector, SDKType_Vector, SDKPass_ByValue, ReturnType_VectorPtr, HookParamType_Object, 12 }, { "FIELD_INTEGER", SMField_Cell, SDKType_PlainOldData, SDKPass_Plain, ReturnType_Int, HookParamType_Int, 4 }, { "FIELD_BOOLEAN", SMField_Cell, SDKType_Bool, SDKPass_Plain, ReturnType_Bool, HookParamType_Bool, 4 }, - { "FIELD_TYPEUNKNOWN", SMField_Unknwon, SDKType_Unknown, SDKPass_Unknown, ReturnType_Unknown, HookParamType_Unknown, -1 }, - { "FIELD_CSTRING", SMField_String, SDKType_String, SDKPass_Pointer, ReturnType_CharPtr, HookParamType_CharPtr, 4 }, - { "FIELD_HSCRIPT", SMField_Cell, SDKType_PlainOldData, SDKPass_Plain, ReturnType_Int, HookParamType_Int, 4 }, - { "FIELD_VARIANT", SMField_Unknwon, SDKType_Unknown, SDKPass_Unknown, ReturnType_Unknown, HookParamType_Unknown, -1 }, + { "FIELD_TYPEUNKNOWN", SMField_Invalid, SDKType_Unknown, SDKPass_Unknown, ReturnType_Unknown, HookParamType_Unknown, -1 }, + { "FIELD_CSTRING", SMField_String, SDKType_String, SDKPass_Pointer, ReturnType_CharPtr, HookParamType_CharPtr, 0 }, // TODO is it a pointer? + { "FIELD_HSCRIPT", SMField_Address, SDKType_VirtualAddress, SDKPass_Plain, ReturnType_Unknown, HookParamType_Unknown, 0 }, + { "FIELD_VARIANT", SMField_Invalid, SDKType_Unknown, SDKPass_Unknown, ReturnType_Unknown, HookParamType_Unknown, -1 }, { "FIELD_QANGLE", SMField_Vector, SDKType_QAngle, SDKPass_ByValue, ReturnType_VectorPtr, HookParamType_Object, 12 }, { "FIELD_UINT32", SMField_Cell, SDKType_PlainOldData, SDKPass_Plain, ReturnType_Int, HookParamType_Int, 4 }, }; @@ -43,6 +44,9 @@ void Field_LoadGamedata(GameData hGameData) char sKeyValue[12]; hGameData.GetKeyValue(g_FieldInfos[i].sName, sKeyValue, sizeof(sKeyValue)); g_FieldInfos[i].iGameValue = StringToInt(sKeyValue); + + if (g_FieldInfos[i].iSize == 0) + g_FieldInfos[i].iSize = PointerSize; } } @@ -68,11 +72,11 @@ char[] Field_GetName(fieldtype_t nField) SMField Field_GetSMField(fieldtype_t nField) { - if (g_FieldInfos[nField].nSMField != SMField_Unknwon) + if (g_FieldInfos[nField].nSMField != SMField_Invalid) return g_FieldInfos[nField].nSMField; ThrowError("Invalid field type '%s'", Field_GetName(nField)); - return SMField_Unknwon; + return SMField_Invalid; } SDKType Field_GetSDKType(fieldtype_t nField) diff --git a/scripting/vscript/function.sp b/scripting/vscript/function.sp index e71df38..cf1acb4 100644 --- a/scripting/vscript/function.sp +++ b/scripting/vscript/function.sp @@ -27,7 +27,7 @@ void Function_LoadGamedata(GameData hGameData) g_iFunctionBinding_Flags = hGameData.GetOffset("ScriptFunctionBinding_t::m_flags"); g_iFunctionBinding_sizeof = hGameData.GetOffset("sizeof(ScriptFunctionBinding_t)"); - g_hSDKCallRegisterFunction = CreateSDKCall(hGameData, "IScriptVM", "RegisterFunction", _, SDKType_PlainOldData); + g_hSDKCallRegisterFunction = ScriptVM_CreateSDKCall(hGameData, "RegisterFunction", _, SDKType_PlainOldData); } VScriptFunction Function_Create() @@ -51,9 +51,9 @@ void Function_Init(VScriptFunction pFunction, bool bClass) // Set strings as empty, but not null Address pEmptyString = GetEmptyString(); - StoreToAddress(pFunction + view_as
(g_iFunctionBinding_ScriptName), pEmptyString, NumberType_Int32); - StoreToAddress(pFunction + view_as
(g_iFunctionBinding_FunctionName), pEmptyString, NumberType_Int32); - StoreToAddress(pFunction + view_as
(g_iFunctionBinding_Description), pEmptyString, NumberType_Int32); + StoreAddressToAddress(pFunction + view_as
(g_iFunctionBinding_ScriptName), pEmptyString); + StoreAddressToAddress(pFunction + view_as
(g_iFunctionBinding_FunctionName), pEmptyString); + StoreAddressToAddress(pFunction + view_as
(g_iFunctionBinding_Description), pEmptyString); // Right now just need to set flags, currently we can only support member functions if (bClass) @@ -82,7 +82,7 @@ void Function_SetFunctionName(VScriptFunction pFunction, int iParam) Address Function_GetDescription(VScriptFunction pFunction, char[] sBuffer, int iLength) { - Address pString = LoadFromAddress(pFunction + view_as
(g_iFunctionBinding_Description), NumberType_Int32); + Address pString = LoadAddressFromAddress(pFunction + view_as
(g_iFunctionBinding_Description)); LoadStringFromAddress(pString, sBuffer, iLength); return pString; } @@ -104,7 +104,7 @@ void Function_SetReturnType(VScriptFunction pFunction, fieldtype_t nField) fieldtype_t Function_GetParam(VScriptFunction pFunction, int iPosition) { - Address pData = LoadFromAddress(pFunction + view_as
(g_iFunctionBinding_Parameters), NumberType_Int32); + Address pData = LoadAddressFromAddress(pFunction + view_as
(g_iFunctionBinding_Parameters)); return Field_GameToEnum(LoadFromAddress(pData + view_as
(4 * iPosition), NumberType_Int32)); } @@ -113,23 +113,23 @@ void Function_SetParam(VScriptFunction pFunction, int iPosition, fieldtype_t nFi // Create any new needed params Memory_UtlVectorSetSize(pFunction + view_as
(g_iFunctionBinding_Parameters), 4, iPosition + 1); - Address pData = LoadFromAddress(pFunction + view_as
(g_iFunctionBinding_Parameters), NumberType_Int32); + Address pData = LoadAddressFromAddress(pFunction + view_as
(g_iFunctionBinding_Parameters)); StoreToAddress(pData + view_as
(4 * iPosition), Field_EnumToGame(nField), NumberType_Int32); } int Function_GetParamCount(VScriptFunction pFunction) { - return LoadFromAddress(pFunction + view_as
(g_iFunctionBinding_Parameters) + view_as
(0x0C), NumberType_Int32); + return Memory_UtlVectorGetSize(pFunction + view_as
(g_iFunctionBinding_Parameters)); } Address Function_GetBinding(VScriptFunction pFunction) { - return LoadFromAddress(pFunction + view_as
(g_iFunctionBinding_Binding), NumberType_Int32); + return LoadAddressFromAddress(pFunction + view_as
(g_iFunctionBinding_Binding)); } void Function_SetBinding(VScriptFunction pFunction, Address pBinding) { - StoreToAddress(pFunction + view_as
(g_iFunctionBinding_Binding), pBinding, NumberType_Int32); + StoreAddressToAddress(pFunction + view_as
(g_iFunctionBinding_Binding), pBinding); } Address Function_GetFunction(VScriptFunction pFunction) @@ -138,39 +138,36 @@ Address Function_GetFunction(VScriptFunction pFunction) if (iOffset == -1) { // Simple function address - return LoadFromAddress(pFunction + view_as
(g_iFunctionBinding_Function), NumberType_Int32); + return LoadAddressFromAddress(pFunction + view_as
(g_iFunctionBinding_Function)); } else { // Virtual function - char sClass[64]; - VScriptClass pClass = List_GetClassFromFunction(pFunction); - Class_GetScriptName(pClass, sClass, sizeof(sClass)); - return VTable_GetAddressFromOffset(sClass, iOffset); + return Address_Null; } } void Function_SetFunction(VScriptFunction pFunction, Address pFunc) { - for (int iOffset = 4; iOffset < g_iScriptFunctionBinding_sizeof; iOffset++) // Fill any extra empty space as nothing + for (int iOffset = PointerSize; iOffset < g_iScriptFunctionBinding_sizeof; iOffset++) // Fill any extra empty space as nothing StoreToAddress(pFunction + view_as
(g_iFunctionBinding_Function + iOffset), 0x00, NumberType_Int8); - StoreToAddress(pFunction + view_as
(g_iFunctionBinding_Function), pFunc, NumberType_Int32); + StoreAddressToAddress(pFunction + view_as
(g_iFunctionBinding_Function), pFunc); } int Function_GetOffset(VScriptFunction pFunction) { - Address pAddress = LoadFromAddress(pFunction + view_as
(g_iFunctionBinding_Function), NumberType_Int32); + Address pAddress = LoadAddressFromAddress(pFunction + view_as
(g_iFunctionBinding_Function)); // This function could be virtual, check it int iOffset; if (g_bWindows) { - if (g_iScriptFunctionBinding_sizeof > 4 && LoadFromAddress(pFunction + view_as
(g_iFunctionBinding_Function + 4), NumberType_Int32) != 0) + if (g_iScriptFunctionBinding_sizeof > view_as(PointerSize) && LoadFromAddress(pFunction + view_as
(g_iFunctionBinding_Function) + PointerSize, NumberType_Int32) != 0) return -1; // It's a virtual in linux, but not windows // Windows only gives function address that directly calls a virtual, load the instruction - Address pInstruction = LoadFromAddress(pAddress, NumberType_Int32); + Address pInstruction = LoadAddressFromAddress(pAddress); int iRead = RoundToFloor(float(view_as(pInstruction)) / float(0x01000000)); if (iRead < 0) @@ -183,6 +180,7 @@ int Function_GetOffset(VScriptFunction pFunction) switch (iRead) { + // TODO whenever to keep 4 or PointerSize, and whatever for 64 bit support // 1-byte read case 0x60: iOffset = LoadFromAddress(pAddress + view_as
(4), NumberType_Int8); @@ -204,12 +202,12 @@ int Function_GetOffset(VScriptFunction pFunction) { // pAddress is an offset iOffset = view_as(pAddress) - 1; - if (iOffset < 0 || iOffset >= 0x01000000) + if (iOffset < 0 || iOffset >= 0x01000000) // TODO still 0x01000000? return -1; // normal function } // Its a virtual function - return RoundToFloor(float(iOffset) / 4.0); + return RoundToFloor(float(iOffset) / view_as(PointerSize)); } @@ -247,7 +245,7 @@ Handle Function_CreateSDKCall(VScriptFunction pFunction, bool bEntity = true, bo else if (bEntity && Class_IsDerivedFrom(List_GetClassFromFunction(pFunction), List_GetClass("CBaseEntity"))) StartPrepSDKCall(SDKCall_Entity); else - StartPrepSDKCall(SDKCall_Raw); + StartPrepSDKCall(SDKCall_VirtualAddress); int iOffset = Function_GetOffset(pFunction); if (iOffset != -1) diff --git a/scripting/vscript/gamesystem.sp b/scripting/vscript/gamesystem.sp index 369aeb7..4c37c8b 100644 --- a/scripting/vscript/gamesystem.sp +++ b/scripting/vscript/gamesystem.sp @@ -1,67 +1,46 @@ -// Could've used sig to get VScriptServerInit and VScriptServerTerm, but were doing viruals only so it's more easier to work with multiple games +static GlobalForward g_fOnScriptVMInitialized; static Handle g_hSDKCallLevelInitPreEntity; static Handle g_hSDKCallLevelShutdownPostEntity; -static int g_iGameSystem_AllowEntityCreationInScripts; +static int g_iGameSystem_sizeof; void GameSystem_LoadGamedata(GameData hGameData) { - g_iGameSystem_AllowEntityCreationInScripts = hGameData.GetOffset("CVScriptGameSystem::m_bAllowEntityCreationInScripts"); + g_fOnScriptVMInitialized = new GlobalForward("VScript_OnScriptVMInitialized", ET_Ignore); - g_hSDKCallLevelInitPreEntity = CreateSDKCall(hGameData, "IGameSystem", "LevelInitPreEntity"); - g_hSDKCallLevelShutdownPostEntity = CreateSDKCall(hGameData, "IGameSystem", "LevelShutdownPostEntity"); + g_hSDKCallLevelInitPreEntity = CreateSignatureCall(hGameData, "CVScriptGameSystem::LevelInitPreEntity"); + g_hSDKCallLevelShutdownPostEntity = CreateSignatureCall(hGameData, "CVScriptGameSystem::LevelShutdownPostEntity"); - // Figure out where g_pScriptVM is stored by searching through IGameSystem::FrameUpdatePostEntityThink and finding the correct instructions + g_iGameSystem_sizeof = hGameData.GetOffset("sizeof(CVScriptGameSystem)"); - Address pFunction = VTable_GetAddressFromName(hGameData, "IGameSystem", "FrameUpdatePostEntityThink"); - - int iOffset; - for (iOffset = 0; iOffset <= 100; iOffset++) + DynamicDetour hDetour = DynamicDetour.FromConf(hGameData, "CVScriptGameSystem::LevelInitPreEntity"); + hDetour.Enable(Hook_Post, GameSystem_LevelInitPreEntity); +} + +MRESReturn GameSystem_LevelInitPreEntity(Address pGameSystem, DHookReturn hReturn) +{ + if (g_iInitializing == 1) { - Address pInstruction = LoadFromAddress(pFunction + view_as
(iOffset), NumberType_Int8); - - if (g_bWindows) - { - // Windows need "8B 0D" - Address pNext = LoadFromAddress(pFunction + view_as
(iOffset + 1), NumberType_Int8); - if (pInstruction == view_as
(0x8B) && pNext == view_as
(0x0D)) - { - iOffset += 2; - break; - } - } - else - { - // Linux just need "A1" - if (pInstruction == view_as
(0xA1)) - { - iOffset++; - break; - } - } - - if (pInstruction == view_as
(0xCC) || iOffset >= 100) - { - LogError("Could not find address to get g_pScriptVM"); - return; - } + g_iInitializing = 0; + Call_StartForward(g_fOnScriptVMInitialized); + Call_Finish(); } - g_pToScriptVM = LoadFromAddress(pFunction + view_as
(iOffset), NumberType_Int32); + return MRES_Ignored; } void GameSystem_ServerInit() { // m_bAllowEntityCreationInScripts is touched, but we don't really care unless if CreateSceneEntity is actually used - MemoryBlock pMemory = new MemoryBlock(g_iGameSystem_AllowEntityCreationInScripts + 4); + MemoryBlock pMemory = new MemoryBlock(g_iGameSystem_sizeof); SDKCall(g_hSDKCallLevelInitPreEntity, pMemory.Address); delete pMemory; } void GameSystem_ServerTerm() { - MemoryBlock pMemory = new MemoryBlock(g_iGameSystem_AllowEntityCreationInScripts + 4); + MemoryBlock pMemory = new MemoryBlock(g_iGameSystem_sizeof); SDKCall(g_hSDKCallLevelShutdownPostEntity, pMemory.Address); delete pMemory; } diff --git a/scripting/vscript/hscript.sp b/scripting/vscript/hscript.sp index c303268..35c45c1 100644 --- a/scripting/vscript/hscript.sp +++ b/scripting/vscript/hscript.sp @@ -12,17 +12,17 @@ static Handle g_hSDKCallReleaseScript; void HScript_LoadGamedata(GameData hGameData) { - g_hSDKCallCreateScope = CreateSDKCall(hGameData, "IScriptVM", "CreateScope", SDKType_PlainOldData, SDKType_String, SDKType_PlainOldData); - g_hSDKCallCreateTable = CreateSDKCall(hGameData, "IScriptVM", "CreateTable", _, SDKType_PlainOldData); - g_hSDKCallGetKeyValue = CreateSDKCall(hGameData, "IScriptVM", "GetKeyValue", SDKType_PlainOldData, SDKType_PlainOldData, SDKType_PlainOldData, SDKType_PlainOldData, SDKType_PlainOldData); - g_hSDKCallGetValue = CreateSDKCall(hGameData, "IScriptVM", "GetValue", SDKType_Bool, SDKType_PlainOldData, SDKType_String, SDKType_PlainOldData); - g_hSDKCallSetValue = CreateSDKCall(hGameData, "IScriptVM", "SetValue", SDKType_Bool, SDKType_PlainOldData, SDKType_String, SDKType_PlainOldData); - g_hSDKCallReleaseValue = CreateSDKCall(hGameData, "IScriptVM", "ReleaseValue", _, SDKType_PlainOldData); - g_hSDKCallClearValue = CreateSDKCall(hGameData, "IScriptVM", "ClearValue", SDKType_Bool, SDKType_PlainOldData, SDKType_String); - g_hSDKCallRegisterInstance = CreateSDKCall(hGameData, "IScriptVM", "RegisterInstance", SDKType_PlainOldData, SDKType_PlainOldData, SDKType_PlainOldData); - g_hSDKCallGetInstanceValue = CreateSDKCall(hGameData, "IScriptVM", "GetInstanceValue", SDKType_PlainOldData, SDKType_PlainOldData, SDKType_PlainOldData); - g_hSDKCallReleaseScope = CreateSDKCall(hGameData, "IScriptVM", "ReleaseScope", _, SDKType_PlainOldData); - g_hSDKCallReleaseScript = CreateSDKCall(hGameData, "IScriptVM", "ReleaseScript", _, SDKType_PlainOldData); + g_hSDKCallCreateScope = ScriptVM_CreateSDKCall(hGameData, "CreateScope", SDKType_PlainOldData, SDKType_String, SDKType_PlainOldData); + g_hSDKCallCreateTable = ScriptVM_CreateSDKCall(hGameData, "CreateTable", _, SDKType_PlainOldData); + g_hSDKCallGetKeyValue = ScriptVM_CreateSDKCall(hGameData, "GetKeyValue", SDKType_PlainOldData, SDKType_PlainOldData, SDKType_PlainOldData, SDKType_PlainOldData, SDKType_PlainOldData); + g_hSDKCallGetValue = ScriptVM_CreateSDKCall(hGameData, "GetValue", SDKType_Bool, SDKType_PlainOldData, SDKType_String, SDKType_PlainOldData); + g_hSDKCallSetValue = ScriptVM_CreateSDKCall(hGameData, "SetValue", SDKType_Bool, SDKType_PlainOldData, SDKType_String, SDKType_PlainOldData); + g_hSDKCallReleaseValue = ScriptVM_CreateSDKCall(hGameData, "ReleaseValue", _, SDKType_PlainOldData); + g_hSDKCallClearValue = ScriptVM_CreateSDKCall(hGameData, "ClearValue", SDKType_Bool, SDKType_PlainOldData, SDKType_String); + g_hSDKCallRegisterInstance = ScriptVM_CreateSDKCall(hGameData, "RegisterInstance", SDKType_PlainOldData, SDKType_PlainOldData, SDKType_PlainOldData); + g_hSDKCallGetInstanceValue = ScriptVM_CreateSDKCall(hGameData, "GetInstanceValue", SDKType_PlainOldData, SDKType_PlainOldData, SDKType_PlainOldData); + g_hSDKCallReleaseScope = ScriptVM_CreateSDKCall(hGameData, "ReleaseScope", _, SDKType_PlainOldData); + g_hSDKCallReleaseScript = ScriptVM_CreateSDKCall(hGameData, "ReleaseScript", _, SDKType_PlainOldData); } HSCRIPT HScript_CreateScope(const char[] sName, HSCRIPT pParent) @@ -76,7 +76,7 @@ bool HScript_GetValue(HSCRIPT pHScript, const char[] sKey, ScriptVariant_t pValu return SDKCall(g_hSDKCallGetValue, GetScriptVM(), pHScript, sKey, pValue.Address); } -ScriptVariant_t HScript_NativeGetValue(SMField nSMField = SMField_Unknwon) +ScriptVariant_t HScript_NativeGetValue(SMField nSMField = SMField_Invalid) { int iLength; GetNativeStringLength(2, iLength); @@ -93,11 +93,11 @@ ScriptVariant_t HScript_NativeGetValue(SMField nSMField = SMField_Unknwon) ThrowNativeError(SP_ERROR_NATIVE, "Key name '%s' either don't exist or value is null", sBuffer); } - if (nSMField == SMField_Unknwon) + if (nSMField == SMField_Invalid) return pValue; // skip field check fieldtype_t nField = pValue.nType; - if (Field_GetSMField(nField) != nSMField) + if (Field_GetSMField(nField) & nSMField == SMField_Invalid) { delete pValue; ThrowNativeError(SP_ERROR_NATIVE, "Invalid field use '%s'", Field_GetName(nField)); @@ -160,7 +160,7 @@ void HScript_NativeSetValue(SMField nSMField) if (nSMField != SMField_Void) { nField = GetNativeCell(3); - if (Field_GetSMField(nField) != nSMField) + if (Field_GetSMField(nField) & nSMField == SMField_Invalid) ThrowNativeError(SP_ERROR_NATIVE, "Invalid field use '%s'", Field_GetName(nField)); } @@ -169,12 +169,16 @@ void HScript_NativeSetValue(SMField nSMField) MemoryBlock hMemory; - switch (nSMField) + switch (Field_GetSMField(nField)) { case SMField_Cell: { pValue.nValue = GetNativeCell(4); } + case SMField_Address: + { + pValue.pAddress = GetNativeCell(4); + } case SMField_String: { GetNativeStringLength(4, iLength); diff --git a/scripting/vscript/list.sp b/scripting/vscript/list.sp index 8f0fcd1..37c0031 100644 --- a/scripting/vscript/list.sp +++ b/scripting/vscript/list.sp @@ -1,26 +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); - hDetour.Enable(Hook_Pre, List_Init); - - hDetour = VTable_CreateDetour(hGameData, "IScriptVM", "RegisterFunction", _, HookParamType_Int); - hDetour.Enable(Hook_Post, List_RegisterFunction); + DynamicDetour hDetour = DynamicDetour.FromConf(hGameData, "IScriptVM::Init"); + hDetour.Enable(Hook_Pre, ScriptVM_Detour); - 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); + ScriptVM_CreateHook(hGameData, "RegisterFunction", Hook_Post, List_RegisterFunction, _, HookParamType_Int); + ScriptVM_CreateHook(hGameData, "RegisterClass", Hook_Post, List_RegisterClass, ReturnType_Bool, HookParamType_Int); } void List_LoadDefaults() @@ -46,13 +33,16 @@ void List_LoadDefaults() List_AddEntityScriptDesc(iEntity); } -MRESReturn List_Init(Address pScriptVM, DHookReturn hReturn) +MRESReturn ScriptVM_Detour(Address pThis) { + ScriptVM_UpdateHooks(); + if (g_iInitializing == 0) g_iInitializing = 1; g_aGlobalFunctions.Clear(); g_aClasses.Clear(); + return MRES_Ignored; } @@ -76,18 +66,6 @@ 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); diff --git a/scripting/vscript/memory.sp b/scripting/vscript/memory.sp index 070e128..6ebb11a 100644 --- a/scripting/vscript/memory.sp +++ b/scripting/vscript/memory.sp @@ -1,10 +1,25 @@ static StringMap g_mMemoryBlocks; +static int g_iUtlVector_Memory; +static int g_iUtlVector_AllocationCount; +//static int g_iUtlVector_GrowSize; +static int g_iUtlVector_Size; +static int g_iUtlVector_Elements; + void Memory_Init() { g_mMemoryBlocks = new StringMap(); } +void Memory_LoadGamedata(GameData hGameData) +{ + g_iUtlVector_Memory = hGameData.GetOffset("CUtlVector::m_pMemory"); + g_iUtlVector_AllocationCount = hGameData.GetOffset("CUtlVector::m_nAllocationCount"); + //g_iUtlVector_GrowSize = hGameData.GetOffset("CUtlVector::m_nGrowSize"); + g_iUtlVector_Size = hGameData.GetOffset("CUtlVector::m_Size"); + g_iUtlVector_Elements = hGameData.GetOffset("CUtlVector::m_pElements"); +} + void Memory_DeleteAddress(Address pAddress) { MemoryBlock hMemory; @@ -18,7 +33,7 @@ void Memory_DeleteAddress(Address pAddress) void Memory_SetAddress(Address pAddress, MemoryBlock hMemory) { Memory_DeleteAddress(pAddress); - StoreToAddress(pAddress, hMemory.Address, NumberType_Int32); + StoreAddressToAddress(pAddress, hMemory.Address); g_mMemoryBlocks.SetValue(Memory_AddressToString(pAddress), hMemory); } @@ -45,37 +60,32 @@ char[] Memory_AddressToString(Address pAddress) return sBuffer; } -/* -CUtlVector { - Data *m_pMemory; // +0 Ptr to items - int m_nAllocationCount; // +4 Amount of allocated space - int m_nGrowSize; // +8 Size by which memory grows - int m_Size; // +12 Number of items in vector - Data *m_pElements; // +16 Same as m_pMemory, used for debugging +int Memory_UtlVectorGetSize(Address pUtlVector) +{ + return LoadFromAddress(pUtlVector + view_as
(g_iUtlVector_Size), NumberType_Int32); } -*/ void Memory_UtlVectorSetSize(Address pUtlVector, int iSize, int iCount) { - int iAllocationCount = LoadFromAddress(pUtlVector + view_as
(4), NumberType_Int32); - int iCurrentCount = LoadFromAddress(pUtlVector + view_as
(12), NumberType_Int32); + int iAllocationCount = LoadFromAddress(pUtlVector + view_as
(g_iUtlVector_AllocationCount), NumberType_Int32); + int iCurrentCount = LoadFromAddress(pUtlVector + view_as
(g_iUtlVector_Size), NumberType_Int32); if (iCurrentCount < iCount) - StoreToAddress(pUtlVector + view_as
(12), iCount, NumberType_Int32); + StoreToAddress(pUtlVector + view_as
(g_iUtlVector_Size), iCount, NumberType_Int32); if (iAllocationCount < iCount) { - Address pData = LoadFromAddress(pUtlVector + view_as
(0), NumberType_Int32); + Address pData = LoadAddressFromAddress(pUtlVector + view_as
(g_iUtlVector_Memory)); MemoryBlock hMemory = new MemoryBlock(iSize * iCount); for (int i = 0; i < iAllocationCount * iSize; i++) hMemory.StoreToOffset(i, LoadFromAddress(pData + view_as
(i), NumberType_Int8), NumberType_Int8); iAllocationCount = iCount; - StoreToAddress(pUtlVector + view_as
(4), iAllocationCount, NumberType_Int32); + StoreToAddress(pUtlVector + view_as
(g_iUtlVector_AllocationCount), iAllocationCount, NumberType_Int32); - Memory_SetAddress(pUtlVector + view_as
(0), hMemory); - StoreToAddress(pUtlVector + view_as
(16), hMemory.Address, NumberType_Int32); + Memory_SetAddress(pUtlVector + view_as
(g_iUtlVector_Memory), hMemory); + StoreAddressToAddress(pUtlVector + view_as
(g_iUtlVector_Elements), hMemory.Address); } } diff --git a/scripting/vscript/scriptvm.sp b/scripting/vscript/scriptvm.sp new file mode 100644 index 0000000..ff4aee0 --- /dev/null +++ b/scripting/vscript/scriptvm.sp @@ -0,0 +1,130 @@ +enum struct ScriptVMHook +{ + int iOffset; + int iHookId; + HookMode nHookMode; + DHookCallback fCallback; + DynamicHook hHook; +} + +static int g_iScriptVMExtraOffsets[16]; +static ArrayList g_aScriptVMHooks; + +HSCRIPT GetScriptVM() +{ + return view_as(LoadAddressFromAddress(g_pToScriptVM)); +} + +void SetScriptVM(HSCRIPT pScript) +{ + StoreAddressToAddress(g_pToScriptVM, pScript); +} + +void ScriptVM_Init() +{ + g_aScriptVMHooks = new ArrayList(sizeof(ScriptVMHook)); +} + +void ScriptVM_LoadGamedata(GameData hGameData) +{ + g_pToScriptVM = hGameData.GetAddress("g_pScriptVM"); + if (!g_pToScriptVM) + LogError("Could not find address of g_pToScriptVM"); + + char sExtraOffsets[64]; + hGameData.GetKeyValue("IScriptVM::ExtraOffsets", sExtraOffsets, sizeof(sExtraOffsets)); + + char sValues[sizeof(g_iScriptVMExtraOffsets)][12]; + int iCount = ExplodeString(sExtraOffsets, " ", sValues, sizeof(sValues), sizeof(sValues[])); + + for (int i = 0; i < iCount; i++) + g_iScriptVMExtraOffsets[i] = StringToInt(sValues[i]); +} + +int ScriptVM_GetOffsetFromName(GameData hGameData, const char[] sFunction) +{ + char sOffset[256]; + Format(sOffset, sizeof(sOffset), "IScriptVM::%s", sFunction); + + int iOffset = hGameData.GetOffset(sOffset); + if (iOffset == -1) + LogError("Could not get offset '%s'", sOffset); + + // Check if game has extra offsets between + for (int i = 0; i < sizeof(g_iScriptVMExtraOffsets); i++) + if (g_iScriptVMExtraOffsets[i] && iOffset >= g_iScriptVMExtraOffsets[i]) + iOffset++; + + return iOffset; +} + +Handle ScriptVM_CreateSDKCall(GameData hGameData, const char[] sFunction, SDKType nReturn = SDKType_Unknown, SDKType nParam1 = SDKType_Unknown, SDKType nParam2 = SDKType_Unknown, SDKType nParam3 = SDKType_Unknown, SDKType nParam4 = SDKType_Unknown, SDKType nParam5 = SDKType_Unknown, SDKType nParam6 = SDKType_Unknown) +{ + StartPrepSDKCall(SDKCall_VirtualAddress); + + PrepSDKCall_SetVirtual(ScriptVM_GetOffsetFromName(hGameData, sFunction)); + + SDKAddParameter(nParam1); + SDKAddParameter(nParam2); + SDKAddParameter(nParam3); + SDKAddParameter(nParam4); + SDKAddParameter(nParam5); + SDKAddParameter(nParam6); + + if (nReturn == SDKType_CBaseEntity || nReturn == SDKType_String) + PrepSDKCall_SetReturnInfo(nReturn, SDKPass_Pointer); + else if (nReturn != SDKType_Unknown) + PrepSDKCall_SetReturnInfo(nReturn, SDKPass_Plain); + + Handle hSDKCall = EndPrepSDKCall(); + if (!hSDKCall) + LogError("Failed to create SDKCall: IScriptVM::%s", sFunction); + + return hSDKCall; +} + +static void SDKAddParameter(SDKType nParam) +{ + if (nParam == SDKType_Unknown) + return; + + if (nParam == SDKType_CBaseEntity || nParam == SDKType_String) + PrepSDKCall_AddParameter(nParam, SDKPass_Pointer, VDECODE_FLAG_ALLOWNULL|VDECODE_FLAG_ALLOWNOTINGAME|VDECODE_FLAG_ALLOWWORLD); // Don't want VENCODE_FLAG_COPYBACK here + else + PrepSDKCall_AddParameter(nParam, SDKPass_Plain); +} + +void ScriptVM_CreateHook(GameData hGameData, const char[] sFunction, HookMode nHookMode, DHookCallback fCallback, ReturnType nReturn = ReturnType_Void, HookParamType nParam1 = HookParamType_Unknown, HookParamType nParam2 = HookParamType_Unknown) +{ + ScriptVMHook hook; + hook.iOffset = ScriptVM_GetOffsetFromName(hGameData, sFunction); + hook.nHookMode = nHookMode; + hook.fCallback = fCallback; + + hook.hHook = new DynamicHook(ScriptVM_GetOffsetFromName(hGameData, sFunction), HookType_Raw, nReturn, ThisPointer_Address); + + if (nParam1 != HookParamType_Unknown) + hook.hHook.AddParam(nParam1); + + if (nParam2 != HookParamType_Unknown) + hook.hHook.AddParam(nParam2); + + g_aScriptVMHooks.PushArray(hook); +} + +void ScriptVM_UpdateHooks() +{ + Address pScriptVM = GetScriptVM(); + + int iLength = g_aScriptVMHooks.Length; + for (int i = 0; i < iLength; i++) + { + ScriptVMHook hook; + g_aScriptVMHooks.GetArray(i, hook); + if (hook.iHookId != INVALID_HOOK_ID) + DynamicHook.RemoveHook(hook.iHookId); + + hook.iHookId = hook.hHook.HookRaw(hook.nHookMode, pScriptVM, hook.fCallback); + g_aScriptVMHooks.SetArray(i, hook); + } +} diff --git a/scripting/vscript/util.sp b/scripting/vscript/util.sp index fbe48fd..475a7a5 100644 --- a/scripting/vscript/util.sp +++ b/scripting/vscript/util.sp @@ -1,16 +1,6 @@ -HSCRIPT GetScriptVM() -{ - return view_as(LoadFromAddress(g_pToScriptVM, NumberType_Int32)); -} - -void SetScriptVM(HSCRIPT pScript) -{ - StoreToAddress(g_pToScriptVM, pScript, NumberType_Int32); -} - int LoadPointerStringFromAddress(Address pPointer, char[] sBuffer, int iMaxLen) { - Address pString = LoadFromAddress(pPointer, NumberType_Int32); + Address pString = LoadAddressFromAddress(pPointer); return LoadStringFromAddress(pString, sBuffer, iMaxLen); } @@ -31,7 +21,7 @@ int LoadStringFromAddress(Address pString, char[] sBuffer, int iMaxLen) int LoadPointerStringLengthFromAddress(Address pPointer) { - Address pString = LoadFromAddress(pPointer, NumberType_Int32); + Address pString = LoadAddressFromAddress(pPointer); return LoadStringLengthFromAddress(pString); } @@ -102,37 +92,14 @@ MemoryBlock CreateVectorMemory(float vecBuffer[3]) return hVector; } -Handle CreateSDKCall(GameData hGameData, const char[] sClass, const char[] sFunction, SDKType nReturn = SDKType_Unknown, SDKType nParam1 = SDKType_Unknown, SDKType nParam2 = SDKType_Unknown, SDKType nParam3 = SDKType_Unknown, SDKType nParam4 = SDKType_Unknown, SDKType nParam5 = SDKType_Unknown, SDKType nParam6 = SDKType_Unknown) +Handle CreateSignatureCall(GameData hGameData, const char[] sName) { - StartPrepSDKCall(SDKCall_Raw); - PrepSDKCall_SetAddress(VTable_GetAddressFromName(hGameData, sClass, sFunction)); - - SDKAddParameter(nParam1); - SDKAddParameter(nParam2); - SDKAddParameter(nParam3); - SDKAddParameter(nParam4); - SDKAddParameter(nParam5); - SDKAddParameter(nParam6); - - if (nReturn == SDKType_CBaseEntity || nReturn == SDKType_String) - PrepSDKCall_SetReturnInfo(nReturn, SDKPass_Pointer); - else if (nReturn != SDKType_Unknown) - PrepSDKCall_SetReturnInfo(nReturn, SDKPass_Plain); + StartPrepSDKCall(SDKCall_VirtualAddress); + PrepSDKCall_SetFromConf(hGameData, SDKConf_Signature, sName); Handle hSDKCall = EndPrepSDKCall(); if (!hSDKCall) - LogError("Failed to create SDKCall: %s::%s", sClass, sFunction); + LogError("Failed to create SDKCall: %s", sName); return hSDKCall; } - -static void SDKAddParameter(SDKType nParam) -{ - if (nParam == SDKType_Unknown) - return; - - if (nParam == SDKType_CBaseEntity || nParam == SDKType_String) - PrepSDKCall_AddParameter(nParam, SDKPass_Pointer, VDECODE_FLAG_ALLOWNULL|VDECODE_FLAG_ALLOWNOTINGAME|VDECODE_FLAG_ALLOWWORLD); // Don't want VENCODE_FLAG_COPYBACK here - else - PrepSDKCall_AddParameter(nParam, SDKPass_Plain); -} diff --git a/scripting/vscript/variant.sp b/scripting/vscript/variant.sp index ceb0e2c..d180ed9 100644 --- a/scripting/vscript/variant.sp +++ b/scripting/vscript/variant.sp @@ -108,6 +108,22 @@ methodmap ScriptVariant_t < MemoryBlock LoadVectorFromAddress(this.nValue, vecBuffer); } + property Address pAddress + { + public get() + { + // TODO + ThrowError("Not supported"); + return view_as
(this.LoadFromOffset(g_iScriptVariant_union, NumberType_Int32)); + } + + public set(Address pValue) + { + ThrowError("Not supported"); + this.StoreToOffset(g_iScriptVariant_union, pValue, NumberType_Int32); + } + } + property fieldtype_t nType { public get() diff --git a/scripting/vscript/vtable.sp b/scripting/vscript/vtable.sp deleted file mode 100644 index cd4bd80..0000000 --- a/scripting/vscript/vtable.sp +++ /dev/null @@ -1,277 +0,0 @@ -// Gamedata Sig? whos needs that? -// Using class name and virtual offset, get the address of the function, -// This is helpful when not needing to get sig for multiple games - -static KeyValues g_kvTempGamedata; - -enum struct VTable -{ - char sClass[64]; // Name of the class - char sLibrary[16]; // Library name to open - char sSymbol[64]; // String name of symbols from gamedata to search in TF2 - int iExtraOffsets[16]; // Extra offsets added from gamedata - Address pAddress; // The address of the VTable symbol -} - -static ArrayList g_aVTables; - -static VTable g_VTableGameData[] = { - { "IGameSystem", "server" }, - { "IScriptVM", "vscript" }, -} - -void VTable_LoadGamedata(GameData hGameData) -{ - g_aVTables = new ArrayList(sizeof(VTable)); - - for (int i = 0; i < sizeof(g_VTableGameData); i++) - { - VTable vtable; - vtable = g_VTableGameData[i]; - - hGameData.GetKeyValue(vtable.sClass, vtable.sSymbol, sizeof(vtable.sSymbol)); - VTable_CreateSymbol(vtable.sSymbol, vtable.sSymbol, sizeof(vtable.sSymbol)); - - char sName[64], sExtraOffsets[64]; - Format(sName, sizeof(sName), "%s::ExtraOffsets", vtable.sClass); - hGameData.GetKeyValue(sName, sExtraOffsets, sizeof(sExtraOffsets)); - - char sValues[sizeof(vtable.iExtraOffsets)][12]; - int iCount = ExplodeString(sExtraOffsets, " ", sValues, sizeof(sValues), sizeof(sValues[])); - - for (int j = 0; j < iCount; j++) - vtable.iExtraOffsets[j] = StringToInt(sValues[j]); - - g_aVTables.PushArray(vtable); - } - - VTable_LoadGamedataAddress(); -} - -void VTable_LoadGamedataAddress() -{ - int iLength = g_aVTables.Length; - - g_kvTempGamedata = new KeyValues("Games"); - g_kvTempGamedata.JumpToKey("#default", true); - g_kvTempGamedata.JumpToKey("Signatures", true); - - for (int i = 0; i < iLength; i++) - { - VTable vtable; - g_aVTables.GetArray(i, vtable); - VTable_SetSymbol(vtable.sSymbol, vtable.sLibrary); - } - - g_kvTempGamedata.GoBack(); - g_kvTempGamedata.GoBack(); - int iExtraOffset; - - //Not sure if these offsets is the correct method, but it worksTM for TF2 - if (g_bWindows) - { - // Extra zeros at the start to prevent possible multi-matches - VTable_LoadAddress(8, 12); - VTable_LoadAddress(0); - } - else - { - // Symbol is located 4 bytes before where vtable offset starts - iExtraOffset = 4; - } - - GameData hTempGameData = VTable_GetGamedata(); - - for (int i = 0; i < iLength; i++) - { - VTable vtable; - g_aVTables.GetArray(i, vtable); - vtable.pAddress = hTempGameData.GetMemSig(vtable.sSymbol) + view_as
(iExtraOffset); - g_aVTables.SetArray(i, vtable); - - if (!vtable.pAddress) - LogError("Could not get address of symbol '%s'", vtable.sSymbol); - } - - delete hTempGameData; - - delete g_kvTempGamedata; -} - -Address VTable_GetAddressFromName(GameData hGameData, const char[] sClass, const char[] sFunction) -{ - VTable vtable; - int iLength = g_aVTables.Length; - - for (int i = 0; i < iLength; i++) - { - g_aVTables.GetArray(i, vtable); - if (StrEqual(vtable.sClass, sClass)) - break; - - if (i + 1 == iLength) // checked all of it - LogError("Invalid class in VTable '%s'", sClass); - } - - char sOffset[256]; - Format(sOffset, sizeof(sOffset), "%s::%s", sClass, sFunction); - - int iOffset = hGameData.GetOffset(sOffset); - if (iOffset == -1) - LogError("Could not get offset '%s'", sOffset); - - // Check if game has extra offsets between - for (int i = 0; i < sizeof(vtable.iExtraOffsets); i++) - if (vtable.iExtraOffsets[i] && iOffset >= vtable.iExtraOffsets[i]) - iOffset++; - - Address pAddress = vtable.pAddress + view_as
((iOffset + 1) * 4); - return LoadFromAddress(pAddress, NumberType_Int32); -} - -Address VTable_GetAddressFromOffset(const char[] sClass, int iOffset) -{ - VTable vtable; - int iLength = g_aVTables.Length; - - for (int i = 0; i < iLength; i++) - { - g_aVTables.GetArray(i, vtable); - if (StrEqual(vtable.sClass, sClass)) - break; - - if (i + 1 == iLength) // checked all of it - { - // Create a new one to load - strcopy(vtable.sClass, sizeof(vtable.sClass), sClass); - vtable.sLibrary = "server"; - VTable_CreateSymbol(sClass, vtable.sSymbol, sizeof(vtable.sSymbol)); - - g_aVTables.PushArray(vtable); - VTable_LoadGamedataAddress(); - g_aVTables.GetArray(iLength, vtable); - } - } - - Address pAddress = vtable.pAddress + view_as
((iOffset + 1) * 4); - return LoadFromAddress(pAddress, NumberType_Int32); -} - -DynamicDetour VTable_CreateDetour(GameData hGameData, const char[] sClass, const char[] sFunction, ReturnType nReturn = ReturnType_Void, HookParamType nParam1 = HookParamType_Unknown, HookParamType nParam2 = HookParamType_Unknown) -{ - Address pFunction = VTable_GetAddressFromName(hGameData, sClass, sFunction); - - DynamicDetour hDetour = new DynamicDetour(pFunction, CallConv_THISCALL, nReturn, ThisPointer_Address); - - if (nParam1 != HookParamType_Unknown) - hDetour.AddParam(nParam1); - - if (nParam2 != HookParamType_Unknown) - hDetour.AddParam(nParam2); - - return hDetour; -} - -void VTable_SetSymbol(const char[] sSymbol, const char[] sLibrary) -{ - g_kvTempGamedata.JumpToKey(sSymbol, true); - g_kvTempGamedata.SetString("library", sLibrary); - - if (sSymbol[0] == '@') - { - g_kvTempGamedata.SetString(g_sOperatingSystem, sSymbol); - } - else - { - char sInstructions[256]; - for (int i = 0; i < strlen(sSymbol); i++) - StrCat(sInstructions, sizeof(sInstructions), VTable_GetSigValue(sSymbol[i])); - - // Null terminator at the end - StrCat(sInstructions, sizeof(sInstructions), VTable_GetSigValue(0)); - - g_kvTempGamedata.SetString(g_sOperatingSystem, sInstructions); - } - - g_kvTempGamedata.GoBack(); -} - -void VTable_LoadAddress(int iBackOffset, int iExtraZeros = 0) -{ - GameData hGameData = VTable_GetGamedata(); - - g_kvTempGamedata.JumpToKey("#default", true); - g_kvTempGamedata.JumpToKey("Signatures", true); - - VTable vtable; - int iLength = g_aVTables.Length; - - for (int i = 0; i < iLength; i++) - { - g_aVTables.GetArray(i, vtable); - Address pAddress = hGameData.GetMemSig(vtable.sSymbol); - if (pAddress) - VTable_loadAddressSymbol(vtable.sSymbol, vtable.sLibrary, pAddress - view_as
(iBackOffset), iExtraZeros); - else - LogError("Could not find VTable class '%s'", vtable.sSymbol); - } - - g_kvTempGamedata.GoBack(); - g_kvTempGamedata.GoBack(); - - delete hGameData; -} - -void VTable_loadAddressSymbol(const char[] sSymbol, const char[] sLibrary, Address pAddress, int iExtraZeros) -{ - g_kvTempGamedata.JumpToKey(sSymbol, true); - - int iTemp = view_as(pAddress); - - char sInstructions[256]; - - for (int i = 0; i < iExtraZeros; i++) // This is for adding zeros before the address in attempt to avoid multiple matches - StrCat(sInstructions, sizeof(sInstructions), VTable_GetSigValue(0)); - - for (int i = 0; i < 4; i++) - { - int iValue = iTemp % 0x100; - if (iValue < 0) - iValue += 0x100; - - StrCat(sInstructions, sizeof(sInstructions), VTable_GetSigValue(iValue)); - iTemp = RoundToNearest(float(iTemp - iValue) / float(0x100)); - } - - g_kvTempGamedata.SetString("library", sLibrary); - g_kvTempGamedata.SetString(g_sOperatingSystem, sInstructions); - - g_kvTempGamedata.GoBack(); -} - -char[] VTable_GetSigValue(int iValue) -{ - char sSig[16]; - Format(sSig, sizeof(sSig), "\\x%02X", iValue); - return sSig; -} - -void VTable_CreateSymbol(const char[] sName, char[] sBuffer, int iLength) -{ - if (g_bWindows) - Format(sBuffer, iLength, ".?AV%s@@", sName); // this is so scuffed - else - Format(sBuffer, iLength, "@_ZTV%d%s", strlen(sName), sName); // e.g. @_ZTV11CSquirrelVM -} - -GameData VTable_GetGamedata(const char[] sFile = "__vscript__") -{ - char sPath[PLATFORM_MAX_PATH]; - BuildPath(Path_SM, sPath, sizeof(sPath), "gamedata/%s.txt", sFile); - g_kvTempGamedata.ExportToFile(sPath); - - GameData hGamedata = new GameData(sFile); - DeleteFile(sPath); - - return hGamedata; -} \ No newline at end of file