From 30e67549449a0ffbb58f7fc736bdd9e4ce7ec9d5 Mon Sep 17 00:00:00 2001
From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com>
Date: Thu, 29 Jul 2021 02:57:31 +0100
Subject: add script api for mods and add temp fix for scripts.rson not loading
right
---
.../NorthstarDedicatedTest.vcxproj | 2 +
.../NorthstarDedicatedTest.vcxproj.filters | 6 +
NorthstarDedicatedTest/dllmain.cpp | 4 +-
NorthstarDedicatedTest/filesystem.cpp | 12 ++
NorthstarDedicatedTest/modmanager.cpp | 8 ++
NorthstarDedicatedTest/scriptmodmenu.cpp | 124 +++++++++++++++++++++
NorthstarDedicatedTest/scriptmodmenu.h | 3 +
NorthstarDedicatedTest/scriptsrson.cpp | 2 +-
NorthstarDedicatedTest/serverauthentication.cpp | 14 +++
NorthstarDedicatedTest/squirrel.cpp | 54 +++++++++
NorthstarDedicatedTest/squirrel.h | 42 ++++++-
11 files changed, 267 insertions(+), 4 deletions(-)
create mode 100644 NorthstarDedicatedTest/scriptmodmenu.cpp
create mode 100644 NorthstarDedicatedTest/scriptmodmenu.h
(limited to 'NorthstarDedicatedTest')
diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj
index 87ea35a2..203edbb3 100644
--- a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj
+++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj
@@ -307,6 +307,7 @@
+
@@ -332,6 +333,7 @@
Create
Create
+
diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters
index f6ff5453..71bae5bc 100644
--- a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters
+++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters
@@ -534,6 +534,9 @@
Header Files\Server\Authentication
+
+ Header Files\Client
+
@@ -590,6 +593,9 @@
Source Files\Server\Authentication
+
+ Source Files\Client
+
diff --git a/NorthstarDedicatedTest/dllmain.cpp b/NorthstarDedicatedTest/dllmain.cpp
index cc40a00c..b0040598 100644
--- a/NorthstarDedicatedTest/dllmain.cpp
+++ b/NorthstarDedicatedTest/dllmain.cpp
@@ -9,7 +9,7 @@
#include "modmanager.h"
#include "filesystem.h"
#include "serverauthentication.h"
-#include
+#include "scriptmodmenu.h"
bool initialised = false;
@@ -53,7 +53,9 @@ void InitialiseNorthstar()
if (!IsDedicated())
{
AddDllLoadCallback("client.dll", InitialiseClientSquirrel);
+
AddDllLoadCallback("client.dll", InitialiseSourceConsole);
+ AddDllLoadCallback("client.dll", InitialiseScriptModMenu);
}
AddDllLoadCallback("server.dll", InitialiseServerSquirrel);
diff --git a/NorthstarDedicatedTest/filesystem.cpp b/NorthstarDedicatedTest/filesystem.cpp
index 1a2fb993..323b8756 100644
--- a/NorthstarDedicatedTest/filesystem.cpp
+++ b/NorthstarDedicatedTest/filesystem.cpp
@@ -21,6 +21,10 @@ typedef void(*AddSearchPathType)(IFileSystem* fileSystem, const char* pPath, con
AddSearchPathType addSearchPathOriginal;
void AddSearchPathHook(IFileSystem* fileSystem, const char* pPath, const char* pathID, SearchPathAdd_t addType);
+typedef FileHandle_t(*ReadFileFromFilesystemType)(IFileSystem* filesystem, const char* pPath, const char* pOptions, int64_t a4, uint32_t a5);
+ReadFileFromFilesystemType readFileFromFilesystem;
+FileHandle_t ReadFileFromFilesystemHook(IFileSystem* filesystem, const char* pPath, const char* pOptions, int64_t a4, uint32_t a5);
+
bool readingOriginalFile;
std::string currentModPath;
SourceInterface* g_Filesystem;
@@ -34,6 +38,7 @@ void InitialiseFilesystem(HMODULE baseAddress)
ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x5CBA0, &ReadFileFromVPKHook, reinterpret_cast(&readFileFromVPK));
ENABLER_CREATEHOOK(hook, (*g_Filesystem)->m_vtable->ReadFromCache, &ReadFromCacheHook, reinterpret_cast(&readFromCache));
ENABLER_CREATEHOOK(hook, (*g_Filesystem)->m_vtable->AddSearchPath, &AddSearchPathHook, reinterpret_cast(&addSearchPathOriginal));
+ ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x15F20, &ReadFileFromFilesystemHook, reinterpret_cast(&readFileFromFilesystem));
}
std::string ReadVPKFile(const char* path)
@@ -136,4 +141,11 @@ void AddSearchPathHook(IFileSystem* fileSystem, const char* pPath, const char* p
addSearchPathOriginal(fileSystem, currentModPath.c_str(), "GAME", PATH_ADD_TO_HEAD);
addSearchPathOriginal(fileSystem, COMPILED_ASSETS_PATH.string().c_str(), "GAME", PATH_ADD_TO_HEAD);
}
+}
+
+FileHandle_t ReadFileFromFilesystemHook(IFileSystem* filesystem, const char* pPath, const char* pOptions, int64_t a4, uint32_t a5)
+{
+ // this isn't super efficient, but it's necessary, since calling addsearchpath in readfilefromvpk doesn't work, possibly refactor later
+ TryReplaceFile((char*)pPath);
+ return readFileFromFilesystem(filesystem, pPath, pOptions, a4, a5);
}
\ No newline at end of file
diff --git a/NorthstarDedicatedTest/modmanager.cpp b/NorthstarDedicatedTest/modmanager.cpp
index 964d37ae..ae1ad98a 100644
--- a/NorthstarDedicatedTest/modmanager.cpp
+++ b/NorthstarDedicatedTest/modmanager.cpp
@@ -1,6 +1,7 @@
#include "pch.h"
#include "modmanager.h"
#include "convar.h"
+#include "concommand.h"
#include "rapidjson/error/en.h"
#include "rapidjson/document.h"
@@ -272,7 +273,14 @@ void ModManager::CompileAssetsForFile(const char* filename)
}
+void ReloadModsCommand(const CCommand& args)
+{
+ g_ModManager->LoadMods();
+}
+
void InitialiseModManager(HMODULE baseAddress)
{
g_ModManager = new ModManager();
+
+ RegisterConCommand("reload_mods", ReloadModsCommand, "idk", FCVAR_NONE);
}
\ No newline at end of file
diff --git a/NorthstarDedicatedTest/scriptmodmenu.cpp b/NorthstarDedicatedTest/scriptmodmenu.cpp
new file mode 100644
index 00000000..f65b3a8c
--- /dev/null
+++ b/NorthstarDedicatedTest/scriptmodmenu.cpp
@@ -0,0 +1,124 @@
+#include "pch.h"
+#include "scriptmodmenu.h"
+#include "modmanager.h"
+#include "squirrel.h"
+
+// array NSGetModNames()
+SQInteger SQ_GetModNames(void* sqvm)
+{
+ ClientSq_newarray(sqvm, 0);
+
+ for (Mod* mod : g_ModManager->m_loadedMods)
+ {
+ ClientSq_pushstring(sqvm, mod->Name.c_str(), -1);
+ ClientSq_arrayappend(sqvm, -2);
+ }
+
+ return 1;
+}
+
+// string NSGetModDescriptionByModName(string modName)
+SQInteger SQ_GetModDescription(void* sqvm)
+{
+ const SQChar* modName = ClientSq_getstring(sqvm, 1);
+
+ // manual lookup, not super performant but eh not a big deal
+ for (Mod* mod : g_ModManager->m_loadedMods)
+ {
+ if (!mod->Name.compare(modName))
+ {
+ ClientSq_pushstring(sqvm, mod->Description.c_str(), -1);
+ return 1;
+ }
+ }
+
+ return 0; // return null
+}
+
+// string NSGetModVersionByModName(string modName)
+SQInteger SQ_GetModVersion(void* sqvm)
+{
+ const SQChar* modName = ClientSq_getstring(sqvm, 1);
+
+ // manual lookup, not super performant but eh not a big deal
+ for (Mod* mod : g_ModManager->m_loadedMods)
+ {
+ if (!mod->Name.compare(modName))
+ {
+ ClientSq_pushstring(sqvm, mod->Version.c_str(), -1);
+ return 1;
+ }
+ }
+
+ return 0; // return null
+}
+
+// string NSGetModDownloadLinkByModName(string modName)
+SQInteger SQ_GetModDownloadLink(void* sqvm)
+{
+ const SQChar* modName = ClientSq_getstring(sqvm, 1);
+
+ // manual lookup, not super performant but eh not a big deal
+ for (Mod* mod : g_ModManager->m_loadedMods)
+ {
+ if (!mod->Name.compare(modName))
+ {
+ ClientSq_pushstring(sqvm, mod->DownloadLink.c_str(), -1);
+ return 1;
+ }
+ }
+
+ return 0; // return null
+}
+
+// int NSGetModLoadPriority(string modName)
+SQInteger SQ_GetModLoadPriority(void* sqvm)
+{
+ const SQChar* modName = ClientSq_getstring(sqvm, 1);
+
+ // manual lookup, not super performant but eh not a big deal
+ for (Mod* mod : g_ModManager->m_loadedMods)
+ {
+ if (!mod->Name.compare(modName))
+ {
+ ClientSq_pushinteger(sqvm, mod->LoadPriority);
+ return 1;
+ }
+ }
+
+ return 0; // return null
+}
+
+// array NSGetModConvarsByModName(string modName)
+SQInteger SQ_GetModConvars(void* sqvm)
+{
+ const SQChar* modName = ClientSq_getstring(sqvm, 1);
+ ClientSq_newarray(sqvm, 0);
+
+ // manual lookup, not super performant but eh not a big deal
+ for (Mod* mod : g_ModManager->m_loadedMods)
+ {
+ if (!mod->Name.compare(modName))
+ {
+ for (ModConVar* cvar : mod->ConVars)
+ {
+ ClientSq_pushstring(sqvm, cvar->Name.c_str(), -1);
+ ClientSq_arrayappend(sqvm, -2);
+ }
+
+ return 1;
+ }
+ }
+
+ return 1; // return empty array
+}
+
+void InitialiseScriptModMenu(HMODULE baseAddress)
+{
+ g_UISquirrelManager->AddFuncRegistration("array", "NSGetModNames", "", "Returns the names of all loaded mods", SQ_GetModNames);
+ g_UISquirrelManager->AddFuncRegistration("string", "NSGetModDescriptionByModName", "asset modName", "Returns a given mod's description", SQ_GetModDescription);
+ g_UISquirrelManager->AddFuncRegistration("string", "NSGetModVersionByModName", "string modName", "Returns a given mod's version", SQ_GetModVersion);
+ g_UISquirrelManager->AddFuncRegistration("string", "NSGetModDownloadLinkByModName", "string modName", "Returns a given mod's download link", SQ_GetModVersion);
+ g_UISquirrelManager->AddFuncRegistration("int", "NSGetModLoadPriority", "string modName", "Returns a given mod's load priority", SQ_GetModLoadPriority);
+ g_UISquirrelManager->AddFuncRegistration("array", "NSGetModConvarsByModName", "string modName", "Returns the names of all a given mod's cvars", SQ_GetModConvars);
+}
\ No newline at end of file
diff --git a/NorthstarDedicatedTest/scriptmodmenu.h b/NorthstarDedicatedTest/scriptmodmenu.h
new file mode 100644
index 00000000..019346d3
--- /dev/null
+++ b/NorthstarDedicatedTest/scriptmodmenu.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void InitialiseScriptModMenu(HMODULE baseAddress);
\ No newline at end of file
diff --git a/NorthstarDedicatedTest/scriptsrson.cpp b/NorthstarDedicatedTest/scriptsrson.cpp
index b5aef421..9c590280 100644
--- a/NorthstarDedicatedTest/scriptsrson.cpp
+++ b/NorthstarDedicatedTest/scriptsrson.cpp
@@ -15,7 +15,7 @@ void ModManager::BuildScriptsRson()
// not really important since it doesn't affect actual functionality at all, but the rson we output is really weird
// has a shitload of newlines added, even in places where we don't modify it at all
- std::string scriptsRson = ReadVPKOriginalFile("scripts/vscripts/scripts.rson");
+ std::string scriptsRson = ReadVPKOriginalFile(VPK_SCRIPTS_RSON_PATH);
scriptsRson += "\n\n// START MODDED SCRIPT CONTENT\n\n"; // newline before we start custom stuff
for (Mod* mod : m_loadedMods)
diff --git a/NorthstarDedicatedTest/serverauthentication.cpp b/NorthstarDedicatedTest/serverauthentication.cpp
index a856c00f..d6f3b2b2 100644
--- a/NorthstarDedicatedTest/serverauthentication.cpp
+++ b/NorthstarDedicatedTest/serverauthentication.cpp
@@ -19,11 +19,15 @@ CBaseClient__ActivatePlayerType CBaseClient__ActivatePlayer;
typedef void(*CBaseClient__DisconnectType)(void* self, uint32_t unknownButAlways1, const char* reason, ...);
CBaseClient__DisconnectType CBaseClient__Disconnect;
+typedef char(*CGameClient__ExecuteStringCommandType)(void* self, uint32_t unknown, const char* pCommandString);
+CGameClient__ExecuteStringCommandType CGameClient__ExecuteStringCommand;
+
// global vars
ServerAuthenticationManager* g_ServerAuthenticationManager;
ConVar* CVar_ns_auth_allow_insecure;
ConVar* CVar_ns_auth_allow_insecure_write;
+ConVar* CVar_sv_quota_stringcmdspersecond;
void ServerAuthenticationManager::AddPlayerAuth(char* authToken, char* uid, char* pdata, size_t pdataSize)
{
@@ -167,18 +171,28 @@ void CBaseClient__DisconnectHook(void* self, uint32_t unknownButAlways1, const c
CBaseClient__Disconnect(self, unknownButAlways1, buf);
}
+// maybe this should be done outside of auth code, but effort to refactor rn and it sorta fits
+char CGameClient__ExecuteStringCommandHook(void* self, uint32_t unknown, const char* pCommandString)
+{
+ // todo later, basically just limit to CVar_sv_quota_stringcmdspersecond->m_nValue stringcmds per client per second
+ return CGameClient__ExecuteStringCommand(self, unknown, pCommandString);
+}
+
void InitialiseServerAuthentication(HMODULE baseAddress)
{
g_ServerAuthenticationManager = new ServerAuthenticationManager;
CVar_ns_auth_allow_insecure = RegisterConVar("ns_auth_allow_insecure", "0", FCVAR_GAMEDLL, "Whether this server will allow unauthenicated players to connect");
CVar_ns_auth_allow_insecure_write = RegisterConVar("ns_auth_allow_insecure_write", "0", FCVAR_GAMEDLL, "Whether the pdata of unauthenticated clients will be written to disk when changed");
+ // literally just stolen from a fix valve used in csgo
+ CVar_sv_quota_stringcmdspersecond = RegisterConVar("sv_quota_stringcmdspersecond", "40", FCVAR_NONE, "How many string commands per second clients are allowed to submit, 0 to disallow all string commands");
HookEnabler hook;
ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x114430, &CBaseServer__ConnectClientHook, reinterpret_cast(&CBaseServer__ConnectClient));
ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x101740, &CBaseClient__ConnectHook, reinterpret_cast(&CBaseClient__Connect));
ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x100F80, &CBaseClient__ActivatePlayerHook, reinterpret_cast(&CBaseClient__ActivatePlayer));
ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x1012C0, &CBaseClient__DisconnectHook, reinterpret_cast(&CBaseClient__Disconnect));
+ ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x1022E0, &CGameClient__ExecuteStringCommandHook, reinterpret_cast(&CGameClient__ExecuteStringCommand));
// patch to disable kicking based on incorrect serverfilter in connectclient, since we repurpose it for use as an auth token
{
diff --git a/NorthstarDedicatedTest/squirrel.cpp b/NorthstarDedicatedTest/squirrel.cpp
index b57e22ae..17758282 100644
--- a/NorthstarDedicatedTest/squirrel.cpp
+++ b/NorthstarDedicatedTest/squirrel.cpp
@@ -34,6 +34,7 @@ CallScriptInitCallbackType ClientCallScriptInitCallback;
CallScriptInitCallbackType ServerCallScriptInitCallback;
template char CallScriptInitCallbackHook(void* sqvm, const char* callback);
+// core sqvm funcs
sq_compilebufferType ClientSq_compilebuffer;
sq_compilebufferType ServerSq_compilebuffer;
@@ -46,6 +47,37 @@ sq_callType ServerSq_call;
RegisterSquirrelFuncType ClientRegisterSquirrelFunc;
RegisterSquirrelFuncType ServerRegisterSquirrelFunc;
+
+// sq stack array funcs
+sq_newarrayType ClientSq_newarray;
+sq_newarrayType ServerSq_newarray;
+
+sq_arrayappendType ClientSq_arrayappend;
+sq_arrayappendType ServerSq_arrayappend;
+
+
+// sq stack push funcs
+sq_pushstringType ClientSq_pushstring;
+sq_pushstringType ServerSq_pushstring;
+
+sq_pushintegerType ClientSq_pushinteger;
+sq_pushintegerType ServerSq_pushinteger;
+
+sq_pushfloatType ClientSq_pushfloat;
+sq_pushfloatType ServerSq_pushfloat;
+
+
+// sq stack get funcs
+sq_getstringType ClientSq_getstring;
+sq_getstringType ServerSq_getstring;
+
+sq_getintegerType ClientSq_getinteger;
+sq_getintegerType ServerSq_getinteger;
+
+sq_getfloatType ClientSq_getfloat;
+sq_getfloatType ServerSq_getfloat;
+
+
template void ExecuteCodeCommand(const CCommand& args);
// inits
@@ -80,6 +112,17 @@ void InitialiseClientSquirrel(HMODULE baseAddress)
ClientSq_call = (sq_callType)((char*)baseAddress + 0x8650);
ClientRegisterSquirrelFunc = (RegisterSquirrelFuncType)((char*)baseAddress + 0x108E0);
+ ClientSq_newarray = (sq_newarrayType)((char*)baseAddress + 0x39F0);
+ ClientSq_arrayappend = (sq_arrayappendType)((char*)baseAddress + 0x3C70);
+
+ ClientSq_pushstring = (sq_pushstringType)((char*)baseAddress + 0x3440);
+ ClientSq_pushinteger = (sq_pushintegerType)((char*)baseAddress + 0x36A0);
+ ClientSq_pushfloat = (sq_pushfloatType)((char*)baseAddress + 0x3800);
+
+ ClientSq_getstring = (sq_getstringType)((char*)baseAddress + 0x60C0);
+ ClientSq_getinteger = (sq_getintegerType)((char*)baseAddress + 0x60E0);
+ ClientSq_getfloat = (sq_getfloatType)((char*)baseAddress + 0x6100);
+
ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x26130, &CreateNewVMHook, reinterpret_cast(&ClientCreateNewVM)); // client createnewvm function
ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x26E70, &DestroyVMHook, reinterpret_cast(&ClientDestroyVM)); // client destroyvm function
ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x79A50, &ScriptCompileErrorHook, reinterpret_cast(&ClientSQCompileError)); // client compileerror function
@@ -98,6 +141,17 @@ void InitialiseServerSquirrel(HMODULE baseAddress)
ServerSq_call = (sq_callType)((char*)baseAddress + 0x8620);
ServerRegisterSquirrelFunc = (RegisterSquirrelFuncType)((char*)baseAddress + 0x1DD10);
+ ServerSq_newarray = (sq_newarrayType)((char*)baseAddress + 0x39F0);
+ ServerSq_arrayappend = (sq_arrayappendType)((char*)baseAddress + 0x3C70);
+
+ ServerSq_pushstring = (sq_pushstringType)((char*)baseAddress + 0x3440);
+ ServerSq_pushinteger = (sq_pushintegerType)((char*)baseAddress + 0x36A0);
+ ServerSq_pushfloat = (sq_pushfloatType)((char*)baseAddress + 0x3800);
+
+ ServerSq_getstring = (sq_getstringType)((char*)baseAddress + 0x60A0);
+ ServerSq_getinteger = (sq_getintegerType)((char*)baseAddress + 0x60C0);
+ ServerSq_getfloat = (sq_getfloatType)((char*)baseAddress + 0x60E0);
+
ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x1FE90, &SQPrintHook, reinterpret_cast(&ServerSQPrint)); // server print function
ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x260E0, &CreateNewVMHook, reinterpret_cast(&ServerCreateNewVM)); // server createnewvm function
ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x26E20, &DestroyVMHook, reinterpret_cast(&ServerDestroyVM)); // server destroyvm function
diff --git a/NorthstarDedicatedTest/squirrel.h b/NorthstarDedicatedTest/squirrel.h
index 2704dbc7..b094dbaf 100644
--- a/NorthstarDedicatedTest/squirrel.h
+++ b/NorthstarDedicatedTest/squirrel.h
@@ -12,6 +12,8 @@ typedef char SQChar;
typedef SQUnsignedInteger SQBool;
typedef SQInteger SQRESULT;
+typedef SQInteger(*SQFunction)(void* sqvm);
+
struct CompileBufferState
{
const SQChar* buffer;
@@ -53,6 +55,7 @@ struct SQFuncRegistration
}
};
+// core sqvm funcs
typedef SQRESULT(*sq_compilebufferType)(void* sqvm, CompileBufferState* compileBuffer, const char* file, int a1, int a2);
extern sq_compilebufferType ClientSq_compilebuffer;
extern sq_compilebufferType ServerSq_compilebuffer;
@@ -69,9 +72,44 @@ typedef int64_t(*RegisterSquirrelFuncType)(void* sqvm, SQFuncRegistration* funcR
extern RegisterSquirrelFuncType ClientRegisterSquirrelFunc;
extern RegisterSquirrelFuncType ServerRegisterSquirrelFunc;
-//template void ExecuteSQCode(SquirrelManager sqManager, const char* code); // need this because we can't do template class functions in the .cpp file
+// sq stack array funcs
+typedef void(*sq_newarrayType)(void* sqvm, SQInteger stackpos);
+extern sq_newarrayType ClientSq_newarray;
+extern sq_newarrayType ServerSq_newarray;
+
+typedef SQRESULT(*sq_arrayappendType)(void* sqvm, SQInteger stackpos);
+extern sq_arrayappendType ClientSq_arrayappend;
+extern sq_arrayappendType ServerSq_arrayappend;
+
+
+// sq stack push funcs
+typedef void(*sq_pushstringType)(void* sqvm, const SQChar* str, SQInteger stackpos);
+extern sq_pushstringType ClientSq_pushstring;
+extern sq_pushstringType ServerSq_pushstring;
+
+// weird how these don't take a stackpos arg?
+typedef void(*sq_pushintegerType)(void* sqvm, SQInteger i);
+extern sq_pushintegerType ClientSq_pushinteger;
+extern sq_pushintegerType ServerSq_pushinteger;
+
+typedef void(*sq_pushfloatType)(void* sqvm, SQFloat f);
+extern sq_pushfloatType ClientSq_pushfloat;
+extern sq_pushfloatType ServerSq_pushfloat;
+
+
+// sq stack get funcs
+typedef const SQChar*(*sq_getstringType)(void* sqvm, SQInteger stackpos);
+extern sq_getstringType ClientSq_getstring;
+extern sq_getstringType ServerSq_getstring;
+
+typedef SQInteger(*sq_getintegerType)(void* sqvm, SQInteger stackpos);
+extern sq_getintegerType ClientSq_getinteger;
+extern sq_getintegerType ServerSq_getinteger;
+
+typedef SQFloat(*sq_getfloatType)(void*, SQInteger stackpos);
+extern sq_getfloatType ClientSq_getfloat;
+extern sq_getfloatType ServerSq_getfloat;
-typedef SQInteger(*SQFunction)(void* sqvm);
template class SquirrelManager
{
--
cgit v1.2.3