diff options
Diffstat (limited to 'NorthstarDedicatedTest')
23 files changed, 230 insertions, 232 deletions
diff --git a/NorthstarDedicatedTest/ExploitFixes.cpp b/NorthstarDedicatedTest/ExploitFixes.cpp index 257ec428..cc42ab73 100644 --- a/NorthstarDedicatedTest/ExploitFixes.cpp +++ b/NorthstarDedicatedTest/ExploitFixes.cpp @@ -5,6 +5,7 @@ #include "hooks.h" #include "NSMem.h" #include "cvar.h" +#include "tier0.h" ConVar* ns_exploitfixes_log; #define SHOULD_LOG (ns_exploitfixes_log->m_Value.m_nValue > 0) @@ -324,7 +325,7 @@ INVALID_CMD: #include "gameutils.h" KHOOK(IsValveMod, ("engine.dll", "48 83 EC 28 48 8B 0D ? ? ? ? 48 8D 15 ? ? ? ? E8 ? ? ? ? 85 C0 74 63"), bool, __fastcall, ()) { - return !CommandLine()->CheckParm("-norestrictservercommands"); + return !Tier0::CommandLine()->CheckParm("-norestrictservercommands"); } // Fix respawn's crappy UTF8 parser so it doesn't crash -_- diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj index 1125b87e..c523534a 100644 --- a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj +++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj @@ -570,6 +570,7 @@ <ClInclude Include="ExploitFixes.h" /> <ClInclude Include="ExploitFixes_UTF8Parser.h" /> <ClInclude Include="NSMem.h" /> + <ClInclude Include="tier0.h" /> <ClInclude Include="version.h" /> </ItemGroup> <ItemGroup> @@ -629,6 +630,7 @@ <ClCompile Include="sourceinterface.cpp" /> <ClCompile Include="squirrel.cpp" /> <ClCompile Include="ExploitFixes.cpp" /> + <ClCompile Include="tier0.cpp" /> <ClCompile Include="version.cpp" /> </ItemGroup> <ItemGroup> diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters index eb4f2a5c..1cb6cadd 100644 --- a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters +++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters @@ -582,9 +582,6 @@ <ClInclude Include="modlocalisation.h"> <Filter>Header Files\Client</Filter> </ClInclude> - <ClInclude Include="playlist.h"> - <Filter>Header Files\Server</Filter> - </ClInclude> <ClInclude Include="dedicatedmaterialsystem.h"> <Filter>Header Files\Dedicated</Filter> </ClInclude> @@ -1509,6 +1506,12 @@ <ClInclude Include="ns_version.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="playlist.h"> + <Filter>Header Files\Shared</Filter> + </ClInclude> + <ClInclude Include="tier0.h"> + <Filter>Header Files\Shared\Game Functions</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="dllmain.cpp"> @@ -1580,9 +1583,6 @@ <ClCompile Include="modlocalisation.cpp"> <Filter>Source Files\Client</Filter> </ClCompile> - <ClCompile Include="playlist.cpp"> - <Filter>Source Files\Server</Filter> - </ClCompile> <ClCompile Include="dedicatedmaterialsystem.cpp"> <Filter>Source Files\Server\Dedicated</Filter> </ClCompile> @@ -1673,6 +1673,12 @@ <ClCompile Include="clientruihooks.cpp"> <Filter>Source Files\Client</Filter> </ClCompile> + <ClCompile Include="playlist.cpp"> + <Filter>Source Files\Shared</Filter> + </ClCompile> + <ClCompile Include="tier0.cpp"> + <Filter>Source Files\Shared\Game Functions</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <MASM Include="audio_asm.asm"> diff --git a/NorthstarDedicatedTest/dedicated.cpp b/NorthstarDedicatedTest/dedicated.cpp index 9430b7a6..89896195 100644 --- a/NorthstarDedicatedTest/dedicated.cpp +++ b/NorthstarDedicatedTest/dedicated.cpp @@ -3,9 +3,13 @@ #include "dedicated.h" #include "hookutils.h" #include "gameutils.h" +#include "tier0.h" +#include "playlist.h" #include "serverauthentication.h" #include "masterserver.h" +using namespace Tier0; + bool IsDedicated() { static bool result = strstr(GetCommandLineA(), "-dedicated"); @@ -55,7 +59,7 @@ void RunServer(CDedicatedExports* dedicated) Cbuf_Execute(); // ensure playlist initialises right, if we've not explicitly called setplaylist - SetCurrentPlaylist(GetCurrentPlaylistName()); + R2::SetCurrentPlaylist(R2::GetCurrentPlaylistName()); // note: we no longer manually set map and hoststate to start server in g_pHostState, we just use +map which seems to initialise stuff // better @@ -76,7 +80,7 @@ void RunServer(CDedicatedExports* dedicated) frameTitle = frameStart; // this way of getting playercount/maxplayers honestly really sucks, but not got any other methods of doing it rn - const char* maxPlayers = GetCurrentPlaylistVar("max_players", false); + const char* maxPlayers = R2::GetCurrentPlaylistVar("max_players", false); if (!maxPlayers) maxPlayers = "6"; @@ -86,7 +90,7 @@ void RunServer(CDedicatedExports* dedicated) g_pHostState->m_levelName, g_ServerAuthenticationManager->m_additionalPlayerData.size(), maxPlayers, - GetCurrentPlaylistName()) + R2::GetCurrentPlaylistName()) .c_str()); } diff --git a/NorthstarDedicatedTest/dedicatedmaterialsystem.cpp b/NorthstarDedicatedTest/dedicatedmaterialsystem.cpp index da6ce7d3..50f1a1b4 100644 --- a/NorthstarDedicatedTest/dedicatedmaterialsystem.cpp +++ b/NorthstarDedicatedTest/dedicatedmaterialsystem.cpp @@ -5,6 +5,7 @@ #include "dedicatedmaterialsystem.h" #include "hookutils.h" #include "gameutils.h" +#include "tier0.h" #include "NSMem.h" typedef HRESULT (*__stdcall D3D11CreateDeviceType)( @@ -39,7 +40,7 @@ HRESULT __stdcall D3D11CreateDeviceHook( // atm, i think the play might be to run d3d in software, and then just stub out any calls that allocate memory/use alot of resources // (e.g. createtexture and that sorta thing) // note: this has been succeeded by the d3d11 and gfsdk stubs, and is only being kept around for posterity and as a fallback option - if (CommandLine()->CheckParm("-softwared3d11")) + if (Tier0::CommandLine()->CheckParm("-softwared3d11")) DriverType = 5; // D3D_DRIVER_TYPE_WARP return D3D11CreateDevice( diff --git a/NorthstarDedicatedTest/dllmain.cpp b/NorthstarDedicatedTest/dllmain.cpp index 01692ed4..bb6f19f3 100644 --- a/NorthstarDedicatedTest/dllmain.cpp +++ b/NorthstarDedicatedTest/dllmain.cpp @@ -5,6 +5,7 @@ #include "keyvalues.h" #include "masterserver.h" #include "gameutils.h" +#include "tier0.h" #include "memalloc.h" #include "maxplayers.h" #include "configurables.h" @@ -38,18 +39,6 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv return TRUE; } -void WaitForDebugger(HMODULE baseAddress) -{ - // earlier waitfordebugger call than is in vanilla, just so we can debug stuff a little easier - if (CommandLine()->CheckParm("-waitfordebugger")) - { - spdlog::info("waiting for debugger..."); - - while (!IsDebuggerPresent()) - Sleep(100); - } -} - void freeLibrary(HMODULE hLib) { if (!FreeLibrary(hLib)) @@ -157,12 +146,8 @@ bool LoadPlugins() bool InitialiseNorthstar() { static bool bInitialised = false; - if (bInitialised) - { - // spdlog::warn("Called InitialiseNorthstar more than once!"); // it's actually 100% fine for that to happen return false; - } bInitialised = true; @@ -181,8 +166,6 @@ bool InitialiseNorthstar() // Write launcher version to log spdlog::info("NorthstarLauncher version: {}", version); - AddDllLoadCallback("engine.dll", WaitForDebugger); - AddDllLoadCallback("tier0.dll", InitialiseTier0GameUtilFunctions); AddDllLoadCallback("engine.dll", InitialiseEngineGameUtilFunctions); AddDllLoadCallback("server.dll", InitialiseServerGameUtilFunctions); diff --git a/NorthstarDedicatedTest/gameutils.cpp b/NorthstarDedicatedTest/gameutils.cpp index 792d8bf2..d6e5840a 100644 --- a/NorthstarDedicatedTest/gameutils.cpp +++ b/NorthstarDedicatedTest/gameutils.cpp @@ -2,11 +2,6 @@ #include "convar.h" #include "gameutils.h" -// memory -IMemAlloc* g_pMemAllocSingleton; -typedef IMemAlloc* (*CreateGlobalMemAllocType)(); -CreateGlobalMemAllocType CreateGlobalMemAlloc; - // cmd.h Cbuf_GetCurrentPlayerType Cbuf_GetCurrentPlayer; Cbuf_AddTextType Cbuf_AddText; @@ -19,15 +14,6 @@ CHostState* g_pHostState; CEngine* g_pEngine; server_state_t* sv_m_State; -// network stuff -ConVar* Cvar_hostport; - -// playlist stuff -GetCurrentPlaylistType GetCurrentPlaylistName; -SetCurrentPlaylistType SetCurrentPlaylist; -SetPlaylistVarOverrideType SetPlaylistVarOverride; -GetCurrentPlaylistVarType GetCurrentPlaylistVar; - // server entity stuff Server_GetEntityByIndexType Server_GetEntityByIndex; @@ -36,10 +22,6 @@ char* g_LocalPlayerUserID; char* g_LocalPlayerOriginToken; // misc stuff -ErrorType Error; -CommandLineType CommandLine; -Plat_FloatTimeType Plat_FloatTime; -ThreadInServerFrameThreadType ThreadInServerFrameThread; GetBaseLocalClientType GetBaseLocalClient; void InitialiseEngineGameUtilFunctions(HMODULE baseAddress) @@ -52,11 +34,6 @@ void InitialiseEngineGameUtilFunctions(HMODULE baseAddress) g_pEngine = *(CEngine**)((char*)baseAddress + 0x7D70C8); sv_m_State = (server_state_t*)((char*)baseAddress + 0x12A53D48); - GetCurrentPlaylistName = (GetCurrentPlaylistType)((char*)baseAddress + 0x18C640); - SetCurrentPlaylist = (SetCurrentPlaylistType)((char*)baseAddress + 0x18EB20); - SetPlaylistVarOverride = (SetPlaylistVarOverrideType)((char*)baseAddress + 0x18ED00); - GetCurrentPlaylistVar = (GetCurrentPlaylistVarType)((char*)baseAddress + 0x18C680); - g_LocalPlayerUserID = (char*)baseAddress + 0x13F8E688; g_LocalPlayerOriginToken = (char*)baseAddress + 0x13979C80; @@ -76,44 +53,9 @@ void InitialiseEngineGameUtilFunctions(HMODULE baseAddress) g_pAllConVars.push_back(pConVar); } }*/ - - Cvar_hostport = (ConVar*)((char*)baseAddress + 0x13FA6070); } void InitialiseServerGameUtilFunctions(HMODULE baseAddress) { Server_GetEntityByIndex = (Server_GetEntityByIndexType)((char*)baseAddress + 0xFB820); -} - -void InitialiseTier0GameUtilFunctions(HMODULE baseAddress) -{ - if (!baseAddress) - { - spdlog::critical("tier0 base address is null, but it should be already loaded"); - throw "tier0 base address is null, but it should be already loaded"; - } - if (g_pMemAllocSingleton) - return; // seems this function was already called - CreateGlobalMemAlloc = reinterpret_cast<CreateGlobalMemAllocType>(GetProcAddress(baseAddress, "CreateGlobalMemAlloc")); - IMemAlloc** ppMemAllocSingleton = reinterpret_cast<IMemAlloc**>(GetProcAddress(baseAddress, "g_pMemAllocSingleton")); - if (!ppMemAllocSingleton) - { - spdlog::critical("Address of g_pMemAllocSingleton is a null pointer, this should never happen"); - throw "Address of g_pMemAllocSingleton is a null pointer, this should never happen"; - } - if (!*ppMemAllocSingleton) - { - g_pMemAllocSingleton = CreateGlobalMemAlloc(); - *ppMemAllocSingleton = g_pMemAllocSingleton; - spdlog::info("Created new g_pMemAllocSingleton"); - } - else - { - g_pMemAllocSingleton = *ppMemAllocSingleton; - } - - Error = reinterpret_cast<ErrorType>(GetProcAddress(baseAddress, "Error")); - CommandLine = reinterpret_cast<CommandLineType>(GetProcAddress(baseAddress, "CommandLine")); - Plat_FloatTime = reinterpret_cast<Plat_FloatTimeType>(GetProcAddress(baseAddress, "Plat_FloatTime")); - ThreadInServerFrameThread = reinterpret_cast<ThreadInServerFrameThreadType>(GetProcAddress(baseAddress, "ThreadInServerFrameThread")); }
\ No newline at end of file diff --git a/NorthstarDedicatedTest/gameutils.h b/NorthstarDedicatedTest/gameutils.h index 6d625c16..4d1b8fb7 100644 --- a/NorthstarDedicatedTest/gameutils.h +++ b/NorthstarDedicatedTest/gameutils.h @@ -1,34 +1,6 @@ #pragma once #include "convar.h" -// memory -class IMemAlloc -{ - public: - struct VTable - { - void* unknown[1]; // alloc debug - void* (*Alloc)(IMemAlloc* memAlloc, size_t nSize); - void* unknown2[1]; // realloc debug - void* (*Realloc)(IMemAlloc* memAlloc, void* pMem, size_t nSize); - void* unknown3[1]; // free #1 - void (*Free)(IMemAlloc* memAlloc, void* pMem); - void* unknown4[2]; // nullsubs, maybe CrtSetDbgFlag - size_t (*GetSize)(IMemAlloc* memAlloc, void* pMem); - void* unknown5[9]; // they all do literally nothing - void (*DumpStats)(IMemAlloc* memAlloc); - void (*DumpStatsFileBase)(IMemAlloc* memAlloc, const char* pchFileBase); - void* unknown6[4]; - int (*heapchk)(IMemAlloc* memAlloc); - }; - - VTable* m_vtable; -}; - -extern IMemAlloc* g_pMemAllocSingleton; -typedef IMemAlloc* (*CreateGlobalMemAllocType)(); -extern CreateGlobalMemAllocType CreateGlobalMemAlloc; - // cmd.h enum class ECommandTarget_t { @@ -85,33 +57,6 @@ extern Cbuf_AddTextType Cbuf_AddText; typedef void (*Cbuf_ExecuteType)(); extern Cbuf_ExecuteType Cbuf_Execute; -// commandline stuff -class CCommandLine -{ - public: - // based on the defs in the 2013 source sdk, but for some reason has an extra function (may be another CreateCmdLine overload?) - // these seem to line up with what they should be though - virtual void CreateCmdLine(const char* commandline) {} - virtual void CreateCmdLine(int argc, char** argv) {} - virtual void unknown() {} - virtual const char* GetCmdLine(void) const {} - - virtual const char* CheckParm(const char* psz, const char** ppszValue = 0) const {} - virtual void RemoveParm() const {} - virtual void AppendParm(const char* pszParm, const char* pszValues) {} - - virtual const char* ParmValue(const char* psz, const char* pDefaultVal = 0) const {} - virtual int ParmValue(const char* psz, int nDefaultVal) const {} - virtual float ParmValue(const char* psz, float flDefaultVal) const {} - - virtual int ParmCount() const {} - virtual int FindParm(const char* psz) const {} - virtual const char* GetParm(int nIndex) const {} - virtual void SetParm(int nIndex, char const* pParm) {} - - // virtual const char** GetParms() const {} -}; - // hoststate stuff enum HostState_t { @@ -204,22 +149,6 @@ enum server_state_t extern server_state_t* sv_m_State; -// network stuff -extern ConVar* Cvar_hostport; - -// playlist stuff -typedef const char* (*GetCurrentPlaylistType)(); -extern GetCurrentPlaylistType GetCurrentPlaylistName; - -typedef void (*SetCurrentPlaylistType)(const char* playlistName); -extern SetCurrentPlaylistType SetCurrentPlaylist; - -typedef void (*SetPlaylistVarOverrideType)(const char* varName, const char* value); -extern SetPlaylistVarOverrideType SetPlaylistVarOverride; - -typedef char* (*GetCurrentPlaylistVarType)(const char* varName, bool useOverrides); -extern GetCurrentPlaylistVarType GetCurrentPlaylistVar; - // server entity stuff typedef void* (*Server_GetEntityByIndexType)(int index); extern Server_GetEntityByIndexType Server_GetEntityByIndex; @@ -229,21 +158,9 @@ extern char* g_LocalPlayerUserID; extern char* g_LocalPlayerOriginToken; // misc stuff -typedef void (*ErrorType)(const char* fmt, ...); -extern ErrorType Error; - -typedef CCommandLine* (*CommandLineType)(); -extern CommandLineType CommandLine; - -typedef double (*Plat_FloatTimeType)(); -extern Plat_FloatTimeType Plat_FloatTime; - -typedef bool (*ThreadInServerFrameThreadType)(); -extern ThreadInServerFrameThreadType ThreadInServerFrameThread; typedef void* (*GetBaseLocalClientType)(); extern GetBaseLocalClientType GetBaseLocalClient; void InitialiseEngineGameUtilFunctions(HMODULE baseAddress); -void InitialiseServerGameUtilFunctions(HMODULE baseAddress); -void InitialiseTier0GameUtilFunctions(HMODULE baseAddress);
\ No newline at end of file +void InitialiseServerGameUtilFunctions(HMODULE baseAddress);
\ No newline at end of file diff --git a/NorthstarDedicatedTest/languagehooks.cpp b/NorthstarDedicatedTest/languagehooks.cpp index 1ca22d89..5e58924e 100644 --- a/NorthstarDedicatedTest/languagehooks.cpp +++ b/NorthstarDedicatedTest/languagehooks.cpp @@ -2,6 +2,7 @@ #include "hooks.h" #include "languagehooks.h" #include "gameutils.h" +#include "tier0.h" #include <filesystem> #include <regex> @@ -61,7 +62,7 @@ char* GetGameLanguageHook() bool& canOriginDictateLang = *(bool*)((char*)tier0Handle + 0xA9A90); const char* forcedLanguage; - if (CommandLine()->CheckParm("-language", &forcedLanguage)) + if (Tier0::CommandLine()->CheckParm("-language", &forcedLanguage)) { if (!CheckLangAudioExists((char*)forcedLanguage)) { diff --git a/NorthstarDedicatedTest/masterserver.cpp b/NorthstarDedicatedTest/masterserver.cpp index 9c78c71a..63915732 100644 --- a/NorthstarDedicatedTest/masterserver.cpp +++ b/NorthstarDedicatedTest/masterserver.cpp @@ -3,9 +3,11 @@ #include "hooks.h" #include "concommand.h" #include "gameutils.h" +#include "playlist.h" #include "hookutils.h" #include "serverauthentication.h" #include "gameutils.h" +#include "tier0.h" #include "rapidjson/document.h" #include "rapidjson/stringbuffer.h" #include "rapidjson/writer.h" @@ -30,6 +32,7 @@ ConVar* Cvar_ns_curl_log_enable; // Source ConVar ConVar* Cvar_hostname; +ConVar* Cvar_hostport; MasterServerManager* g_MasterServerManager; @@ -148,7 +151,7 @@ void MasterServerManager::SetCommonHttpClientOptions(CURL* curl) curl_easy_setopt(curl, CURLOPT_VERBOSE, Cvar_ns_curl_log_enable->GetBool()); curl_easy_setopt(curl, CURLOPT_USERAGENT, &NSUserAgent); // curl_easy_setopt(curl, CURLOPT_STDERR, stdout); - if (CommandLine()->FindParm("-msinsecure")) // TODO: this check doesn't seem to work + if (Tier0::CommandLine()->FindParm("-msinsecure")) // TODO: this check doesn't seem to work { curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); @@ -921,11 +924,11 @@ void MasterServerManager::AddSelfToServerList( char* escapedNameNew = curl_easy_escape(curl, g_MasterServerManager->m_sUnicodeServerName.c_str(), NULL); char* escapedDescNew = curl_easy_escape(curl, g_MasterServerManager->m_sUnicodeServerDesc.c_str(), NULL); char* escapedMapNew = curl_easy_escape(curl, g_pHostState->m_levelName, NULL); - char* escapedPlaylistNew = curl_easy_escape(curl, GetCurrentPlaylistName(), NULL); + char* escapedPlaylistNew = curl_easy_escape(curl, R2::GetCurrentPlaylistName(), NULL); char* escapedPasswordNew = curl_easy_escape(curl, Cvar_ns_server_password->GetString(), NULL); int maxPlayers = 6; - char* maxPlayersVar = GetCurrentPlaylistVar("max_players", false); + const char* maxPlayersVar = R2::GetCurrentPlaylistVar("max_players", false); if (maxPlayersVar) // GetCurrentPlaylistVar can return null so protect against this maxPlayers = std::stoi(maxPlayersVar); @@ -1216,7 +1219,7 @@ void CHostState__State_NewGameHook(CHostState* hostState) // need to do this to ensure we don't go to private match if (g_ServerAuthenticationManager->m_bNeedLocalAuthForNewgame) - SetCurrentPlaylist("tdm"); + R2::SetCurrentPlaylist("tdm"); // net_data_block_enabled is required for sp, force it if we're on an sp map // sucks for security but just how it be @@ -1226,12 +1229,12 @@ void CHostState__State_NewGameHook(CHostState* hostState) Cbuf_Execute(); } - double dStartTime = Plat_FloatTime(); + double dStartTime = Tier0::Plat_FloatTime(); CHostState__State_NewGame(hostState); - spdlog::info("loading took {}s", Plat_FloatTime() - dStartTime); + spdlog::info("loading took {}s", Tier0::Plat_FloatTime() - dStartTime); int maxPlayers = 6; - char* maxPlayersVar = GetCurrentPlaylistVar("max_players", false); + const char* maxPlayersVar = R2::GetCurrentPlaylistVar("max_players", false); if (maxPlayersVar) // GetCurrentPlaylistVar can return null so protect against this maxPlayers = std::stoi(maxPlayersVar); @@ -1246,7 +1249,7 @@ void CHostState__State_NewGameHook(CHostState* hostState) (char*)Cvar_ns_server_name->GetString(), (char*)Cvar_ns_server_desc->GetString(), hostState->m_levelName, - (char*)GetCurrentPlaylistName(), + (char*)R2::GetCurrentPlaylistName(), maxPlayers, (char*)Cvar_ns_server_password->GetString()); g_ServerAuthenticationManager->StartPlayerAuthServer(); @@ -1256,7 +1259,7 @@ void CHostState__State_NewGameHook(CHostState* hostState) void CHostState__State_ChangeLevelMPHook(CHostState* hostState) { int maxPlayers = 6; - char* maxPlayersVar = GetCurrentPlaylistVar("max_players", false); + const char* maxPlayersVar = R2::GetCurrentPlaylistVar("max_players", false); if (maxPlayersVar) // GetCurrentPlaylistVar can return null so protect against this maxPlayers = std::stoi(maxPlayersVar); @@ -1268,11 +1271,11 @@ void CHostState__State_ChangeLevelMPHook(CHostState* hostState) Cbuf_Execute(); } - g_MasterServerManager->UpdateServerMapAndPlaylist(hostState->m_levelName, (char*)GetCurrentPlaylistName(), maxPlayers); + g_MasterServerManager->UpdateServerMapAndPlaylist(hostState->m_levelName, (char*)R2::GetCurrentPlaylistName(), maxPlayers); - double dStartTime = Plat_FloatTime(); + double dStartTime = Tier0::Plat_FloatTime(); CHostState__State_ChangeLevelMP(hostState); - spdlog::info("loading took {}s", Plat_FloatTime() - dStartTime); + spdlog::info("loading took {}s", Tier0::Plat_FloatTime() - dStartTime); } void CHostState__State_ChangeLevelSPHook(CHostState* hostState) @@ -1282,11 +1285,11 @@ void CHostState__State_ChangeLevelSPHook(CHostState* hostState) // so idk it's fucked int maxPlayers = 6; - char* maxPlayersVar = GetCurrentPlaylistVar("max_players", false); + const char* maxPlayersVar = R2::GetCurrentPlaylistVar("max_players", false); if (maxPlayersVar) // GetCurrentPlaylistVar can return null so protect against this maxPlayers = std::stoi(maxPlayersVar); - g_MasterServerManager->UpdateServerMapAndPlaylist(hostState->m_levelName, (char*)GetCurrentPlaylistName(), maxPlayers); + g_MasterServerManager->UpdateServerMapAndPlaylist(hostState->m_levelName, (char*)R2::GetCurrentPlaylistName(), maxPlayers); CHostState__State_ChangeLevelSP(hostState); } @@ -1315,6 +1318,7 @@ ON_DLL_LOAD_RELIESON("engine.dll", MasterServer, ConCommand, (HMODULE baseAddres Cvar_ns_curl_log_enable = new ConVar("ns_curl_log_enable", "0", FCVAR_NONE, ""); Cvar_hostname = *(ConVar**)((char*)baseAddress + 0x1315bae8); + Cvar_hostport = (ConVar*)((char*)baseAddress + 0x13FA6070); g_MasterServerManager = new MasterServerManager; diff --git a/NorthstarDedicatedTest/maxplayers.cpp b/NorthstarDedicatedTest/maxplayers.cpp index b2219faf..15846ea8 100644 --- a/NorthstarDedicatedTest/maxplayers.cpp +++ b/NorthstarDedicatedTest/maxplayers.cpp @@ -2,6 +2,7 @@ #include "hooks.h" #include "maxplayers.h" #include "gameutils.h" +#include "tier0.h" // never set this to anything below 32 #define NEW_MAX_PLAYERS 64 @@ -106,7 +107,7 @@ void* StringTables_CreateStringTable_Hook( bool MaxPlayersIncreaseEnabled() { - return CommandLine() && CommandLine()->CheckParm("-experimentalmaxplayersincrease"); + return Tier0::CommandLine() && Tier0::CommandLine()->CheckParm("-experimentalmaxplayersincrease"); } ON_DLL_LOAD("engine.dll", MaxPlayersOverride_Engine, (HMODULE baseAddress) diff --git a/NorthstarDedicatedTest/memalloc.cpp b/NorthstarDedicatedTest/memalloc.cpp index 4ba54c73..e00d3fc7 100644 --- a/NorthstarDedicatedTest/memalloc.cpp +++ b/NorthstarDedicatedTest/memalloc.cpp @@ -1,6 +1,8 @@ #include "pch.h" #include "memalloc.h" -#include "gameutils.h" +#include "tier0.h" + +using namespace Tier0; // TODO: rename to malloc and free after removing statically compiled .libs @@ -8,9 +10,8 @@ extern "C" void* _malloc_base(size_t n) { // allocate into static buffer if g_pMemAllocSingleton isn't initialised if (!g_pMemAllocSingleton) - { - InitialiseTier0GameUtilFunctions(GetModuleHandleA("tier0.dll")); - } + TryCreateGlobalMemAlloc(); + return g_pMemAllocSingleton->m_vtable->Alloc(g_pMemAllocSingleton, n); } @@ -22,19 +23,16 @@ extern "C" void* _malloc_base(size_t n) extern "C" void _free_base(void* p) { if (!g_pMemAllocSingleton) - { - spdlog::warn("Trying to free something before g_pMemAllocSingleton was ready, this should never happen"); - InitialiseTier0GameUtilFunctions(GetModuleHandleA("tier0.dll")); - } + TryCreateGlobalMemAlloc(); + g_pMemAllocSingleton->m_vtable->Free(g_pMemAllocSingleton, p); } extern "C" void* _realloc_base(void* oldPtr, size_t size) { if (!g_pMemAllocSingleton) - { - InitialiseTier0GameUtilFunctions(GetModuleHandleA("tier0.dll")); - } + TryCreateGlobalMemAlloc(); + return g_pMemAllocSingleton->m_vtable->Realloc(g_pMemAllocSingleton, oldPtr, size); } diff --git a/NorthstarDedicatedTest/misccommands.cpp b/NorthstarDedicatedTest/misccommands.cpp index 00a32c48..51891a07 100644 --- a/NorthstarDedicatedTest/misccommands.cpp +++ b/NorthstarDedicatedTest/misccommands.cpp @@ -2,6 +2,7 @@ #include "misccommands.h" #include "concommand.h" #include "gameutils.h" +#include "playlist.h" #include "masterserver.h" #include "serverauthentication.h" #include "squirrel.h" @@ -52,7 +53,7 @@ void AddMiscConCommands() // this won't set playlist correctly on remote clients, don't think they can set playlist until they've left which sorta // fucks things should maybe set this in HostState_NewGame? - SetCurrentPlaylist("tdm"); + R2::SetCurrentPlaylist("tdm"); strcpy(g_pHostState->m_levelName, "mp_lobby"); g_pHostState->m_iNextState = HS_NEW_GAME; } diff --git a/NorthstarDedicatedTest/modmanager.cpp b/NorthstarDedicatedTest/modmanager.cpp index 01f9670a..79244194 100644 --- a/NorthstarDedicatedTest/modmanager.cpp +++ b/NorthstarDedicatedTest/modmanager.cpp @@ -388,7 +388,7 @@ void ModManager::LoadMods() // not using atm because we need to resolve path to rpak // if (m_hasLoadedMods && modPak.m_bAutoLoad) - // g_PakLoadManager->LoadPakAsync(pakName.c_str()); + // g_pPakLoadManager->LoadPakAsync(pakName.c_str()); } } } diff --git a/NorthstarDedicatedTest/pch.h b/NorthstarDedicatedTest/pch.h index 1955071c..a67315ba 100644 --- a/NorthstarDedicatedTest/pch.h +++ b/NorthstarDedicatedTest/pch.h @@ -24,6 +24,7 @@ #include "include/MinHook.h" #include "spdlog/spdlog.h" #include "libcurl/include/curl/curl.h" +#include "hooks.h" #include "hookutils.h" template <typename ReturnType, typename... Args> ReturnType CallVFunc(int index, void* thisPtr, Args... args) diff --git a/NorthstarDedicatedTest/playlist.cpp b/NorthstarDedicatedTest/playlist.cpp index 59798510..477b3b0a 100644 --- a/NorthstarDedicatedTest/playlist.cpp +++ b/NorthstarDedicatedTest/playlist.cpp @@ -8,24 +8,21 @@ #include "hookutils.h" #include "squirrel.h" -typedef char (*Onclc_SetPlaylistVarOverrideType)(void* a1, void* a2); -Onclc_SetPlaylistVarOverrideType Onclc_SetPlaylistVarOverride; - -typedef int (*GetCurrentGamemodeMaxPlayersType)(); -GetCurrentGamemodeMaxPlayersType GetCurrentGamemodeMaxPlayers; - -// function type defined in gameutils.h -SetPlaylistVarOverrideType SetPlaylistVarOverrideOriginal; -GetCurrentPlaylistVarType GetCurrentPlaylistVarOriginal; - -ConVar* Cvar_ns_use_clc_SetPlaylistVarOverride; +// use the R2 namespace for game funcs +namespace R2 +{ + GetCurrentPlaylistNameType GetCurrentPlaylistName; + SetCurrentPlaylistType SetCurrentPlaylist; + SetPlaylistVarOverrideType SetPlaylistVarOverride; + GetCurrentPlaylistVarType GetCurrentPlaylistVar; +} // namespace R2 void SetPlaylistCommand(const CCommand& args) { if (args.ArgC() < 2) return; - SetCurrentPlaylist(args.Arg(1)); + R2::SetCurrentPlaylist(args.Arg(1)); } void SetPlaylistVarOverrideCommand(const CCommand& args) @@ -34,14 +31,18 @@ void SetPlaylistVarOverrideCommand(const CCommand& args) return; for (int i = 1; i < args.ArgC(); i += 2) - SetPlaylistVarOverride(args.Arg(i), args.Arg(i + 1)); + R2::SetPlaylistVarOverride(args.Arg(i), args.Arg(i + 1)); } +ConVar* Cvar_ns_use_clc_SetPlaylistVarOverride; + +typedef char (*Onclc_SetPlaylistVarOverrideType)(void* a1, void* a2); +Onclc_SetPlaylistVarOverrideType Onclc_SetPlaylistVarOverride; char Onclc_SetPlaylistVarOverrideHook(void* a1, void* a2) { // the private_match playlist is the only situation where there should be any legitimate sending of this netmessage // todo: check mp_lobby here too - if (!Cvar_ns_use_clc_SetPlaylistVarOverride->GetBool() || strcmp(GetCurrentPlaylistName(), "private_match")) + if (!Cvar_ns_use_clc_SetPlaylistVarOverride->GetBool() || strcmp(R2::GetCurrentPlaylistName(), "private_match")) return 1; return Onclc_SetPlaylistVarOverride(a1, a2); @@ -52,20 +53,22 @@ void SetPlaylistVarOverrideHook(const char* varName, const char* value) if (strlen(value) >= 64) return; - SetPlaylistVarOverrideOriginal(varName, value); + R2::SetPlaylistVarOverride(varName, value); } -char* GetCurrentPlaylistVarHook(const char* varName, bool useOverrides) +const char* GetCurrentPlaylistVarHook(const char* varName, bool useOverrides) { if (!useOverrides && !strcmp(varName, "max_players")) useOverrides = true; - return GetCurrentPlaylistVarOriginal(varName, useOverrides); + return R2::GetCurrentPlaylistVar(varName, useOverrides); } +typedef int (*GetCurrentGamemodeMaxPlayersType)(); +GetCurrentGamemodeMaxPlayersType GetCurrentGamemodeMaxPlayers; int GetCurrentGamemodeMaxPlayersHook() { - char* maxPlayersStr = GetCurrentPlaylistVar("max_players", 0); + char* maxPlayersStr = R2::GetCurrentPlaylistVar("max_players", 0); if (!maxPlayersStr) return GetCurrentGamemodeMaxPlayers(); @@ -75,32 +78,41 @@ int GetCurrentGamemodeMaxPlayersHook() ON_DLL_LOAD_RELIESON("engine.dll", PlaylistHooks, ConCommand, (HMODULE baseAddress) { + // playlist is the name of the command on respawn servers, but we already use setplaylist so can't get rid of it + RegisterConCommand("playlist", SetPlaylistCommand, "Sets the current playlist", FCVAR_NONE); RegisterConCommand("setplaylist", SetPlaylistCommand, "Sets the current playlist", FCVAR_NONE); RegisterConCommand("setplaylistvaroverrides", SetPlaylistVarOverrideCommand, "sets a playlist var override", FCVAR_NONE); + // note: clc_SetPlaylistVarOverride is pretty insecure, since it allows for entirely arbitrary playlist var overrides to be sent to the - // server this is somewhat restricted on custom servers to prevent it being done outside of private matches, but ideally it should be + // server, this is somewhat restricted on custom servers to prevent it being done outside of private matches, but ideally it should be // disabled altogether, since the custom menus won't use it anyway this should only really be accepted if you want vanilla client // compatibility Cvar_ns_use_clc_SetPlaylistVarOverride = new ConVar( "ns_use_clc_SetPlaylistVarOverride", "0", FCVAR_GAMEDLL, "Whether the server should accept clc_SetPlaylistVarOverride messages"); + R2::GetCurrentPlaylistName = (R2::GetCurrentPlaylistNameType)((char*)baseAddress + 0x18C640); + R2::SetCurrentPlaylist = (R2::SetCurrentPlaylistType)((char*)baseAddress + 0x18EB20); + R2::SetPlaylistVarOverride = (R2::SetPlaylistVarOverrideType)((char*)baseAddress + 0x18ED00); + R2::GetCurrentPlaylistVar = (R2::GetCurrentPlaylistVarType)((char*)baseAddress + 0x18C680); + HookEnabler hook; ENABLER_CREATEHOOK( hook, (char*)baseAddress + 0x222180, &Onclc_SetPlaylistVarOverrideHook, reinterpret_cast<LPVOID*>(&Onclc_SetPlaylistVarOverride)); ENABLER_CREATEHOOK( - hook, (char*)baseAddress + 0x18ED00, &SetPlaylistVarOverrideHook, reinterpret_cast<LPVOID*>(&SetPlaylistVarOverrideOriginal)); + hook, (char*)baseAddress + 0x18ED00, &SetPlaylistVarOverrideHook, reinterpret_cast<LPVOID*>(&R2::SetPlaylistVarOverride)); ENABLER_CREATEHOOK( - hook, (char*)baseAddress + 0x18C680, &GetCurrentPlaylistVarHook, reinterpret_cast<LPVOID*>(&GetCurrentPlaylistVarOriginal)); + hook, (char*)baseAddress + 0x18C680, &GetCurrentPlaylistVarHook, reinterpret_cast<LPVOID*>(&R2::GetCurrentPlaylistVar)); ENABLER_CREATEHOOK( - hook, (char*)baseAddress + 0x18C430, &GetCurrentGamemodeMaxPlayersHook, reinterpret_cast<LPVOID*>(&GetCurrentGamemodeMaxPlayers)); + hook, + (char*)baseAddress + 0x18C430, + &GetCurrentGamemodeMaxPlayersHook, + reinterpret_cast<LPVOID*>(&GetCurrentGamemodeMaxPlayers)); uintptr_t ba = (uintptr_t)baseAddress; // patch to prevent clc_SetPlaylistVarOverride from being able to crash servers if we reach max overrides due to a call to Error (why is // this possible respawn, wtf) todo: add a warning for this - { - NSMem::BytePatch(ba + 0x18ED8D, "C3"); - } + NSMem::BytePatch(ba + 0x18ED8D, "C3"); // patch to allow setplaylistvaroverride to be called before map init on dedicated and private match launched through the game NSMem::NOP(ba + 0x18ED17, 6); diff --git a/NorthstarDedicatedTest/playlist.h b/NorthstarDedicatedTest/playlist.h index 7b9637ef..2ca1985f 100644 --- a/NorthstarDedicatedTest/playlist.h +++ b/NorthstarDedicatedTest/playlist.h @@ -1 +1,15 @@ -#pragma once
\ No newline at end of file +#pragma once +namespace R2 +{ + typedef const char* (*GetCurrentPlaylistNameType)(); + extern GetCurrentPlaylistNameType GetCurrentPlaylistName; + + typedef void (*SetCurrentPlaylistType)(const char* playlistName); + extern SetCurrentPlaylistType SetCurrentPlaylist; + + typedef void (*SetPlaylistVarOverrideType)(const char* varName, const char* value); + extern SetPlaylistVarOverrideType SetPlaylistVarOverride; + + typedef char* (*GetCurrentPlaylistVarType)(const char* varName, bool useOverrides); + extern GetCurrentPlaylistVarType GetCurrentPlaylistVar; +} // namespace R2
\ No newline at end of file diff --git a/NorthstarDedicatedTest/rpakfilesystem.cpp b/NorthstarDedicatedTest/rpakfilesystem.cpp index c7bab5ee..fce7ddf1 100644 --- a/NorthstarDedicatedTest/rpakfilesystem.cpp +++ b/NorthstarDedicatedTest/rpakfilesystem.cpp @@ -28,7 +28,7 @@ struct PakLoadFuncs PakLoadFuncs* g_pakLoadApi; void** pUnknownPakLoadSingleton; -PakLoadManager* g_PakLoadManager; +PakLoadManager* g_pPakLoadManager; void PakLoadManager::LoadPakSync(const char* path) { g_pakLoadApi->LoadPakSync(path, *pUnknownPakLoadSingleton, 0); @@ -79,7 +79,7 @@ void LoadPreloadPaks() for (ModRpakEntry& pak : mod.Rpaks) if (pak.m_bAutoLoad) - g_PakLoadManager->LoadPakAsync((modPakPath / pak.m_sPakName).string().c_str(), false); + g_pPakLoadManager->LoadPakAsync((modPakPath / pak.m_sPakName).string().c_str(), false); } } @@ -114,7 +114,7 @@ void LoadCustomMapPaks(char** pakName, bool* bNeedToFreePakName) true; // we can't free this memory until we're done with the pak, so let whatever's calling this deal with it } else - g_PakLoadManager->LoadPakAsync((modPakPath / pak.m_sPakName).string().c_str(), true); + g_pPakLoadManager->LoadPakAsync((modPakPath / pak.m_sPakName).string().c_str(), true); } } } @@ -166,7 +166,7 @@ void* UnloadPakHook(int pakHandle, void* callback) if (bShouldUnloadPaks) { bShouldUnloadPaks = false; - g_PakLoadManager->UnloadPaks(); + g_pPakLoadManager->UnloadPaks(); bShouldUnloadPaks = true; } @@ -209,7 +209,7 @@ void* ReadFullFileFromDiskHook(const char* requestedPath, void* a2) ON_DLL_LOAD("engine.dll", RpakFilesystem, (HMODULE baseAddress) { - g_PakLoadManager = new PakLoadManager; + g_pPakLoadManager = new PakLoadManager; g_pakLoadApi = *(PakLoadFuncs**)((char*)baseAddress + 0x5BED78); pUnknownPakLoadSingleton = (void**)((char*)baseAddress + 0x7C5E20); diff --git a/NorthstarDedicatedTest/rpakfilesystem.h b/NorthstarDedicatedTest/rpakfilesystem.h index b711800e..e72ab5ff 100644 --- a/NorthstarDedicatedTest/rpakfilesystem.h +++ b/NorthstarDedicatedTest/rpakfilesystem.h @@ -11,4 +11,4 @@ class PakLoadManager std::vector<int> m_pakHandlesToUnload; }; -extern PakLoadManager* g_PakLoadManager;
\ No newline at end of file +extern PakLoadManager* g_pPakLoadManager;
\ No newline at end of file diff --git a/NorthstarDedicatedTest/serverauthentication.cpp b/NorthstarDedicatedTest/serverauthentication.cpp index 27db8bc9..5f9f10e8 100644 --- a/NorthstarDedicatedTest/serverauthentication.cpp +++ b/NorthstarDedicatedTest/serverauthentication.cpp @@ -16,6 +16,9 @@ #include <thread> #include "configurables.h" #include "NSMem.h" +#include "tier0.h" + +using namespace Tier0; const char* AUTHSERVER_VERIFY_STRING = "I am a northstar server!"; diff --git a/NorthstarDedicatedTest/serverchathooks.cpp b/NorthstarDedicatedTest/serverchathooks.cpp index c16b7a4b..5ac582fd 100644 --- a/NorthstarDedicatedTest/serverchathooks.cpp +++ b/NorthstarDedicatedTest/serverchathooks.cpp @@ -140,6 +140,7 @@ void ChatBroadcastMessage(int fromPlayerIndex, int toPlayerIndex, const char* te CRecipientFilter__Destruct(&filter); } +// void function NSSendMessage( int playerIndex, string text, bool isTeam ) SQRESULT SQ_SendMessage(void* sqvm) { int playerIndex = g_pServerSquirrel->sq_getinteger(sqvm, 1); @@ -151,6 +152,7 @@ SQRESULT SQ_SendMessage(void* sqvm) return SQRESULT_NULL; } +// void function NSBroadcastMessage( int fromPlayerIndex, int toPlayerIndex, string text, bool isTeam, bool isDead, int messageType ) SQRESULT SQ_BroadcastMessage(void* sqvm) { int fromPlayerIndex = g_pServerSquirrel->sq_getinteger(sqvm, 1); diff --git a/NorthstarDedicatedTest/tier0.cpp b/NorthstarDedicatedTest/tier0.cpp new file mode 100644 index 00000000..1a0957ad --- /dev/null +++ b/NorthstarDedicatedTest/tier0.cpp @@ -0,0 +1,37 @@ +#include "pch.h" +#include "tier0.h" + +// use the Tier0 namespace for tier0 funcs +namespace Tier0 +{ + IMemAlloc* g_pMemAllocSingleton; + + ErrorType Error; + CommandLineType CommandLine; + Plat_FloatTimeType Plat_FloatTime; + ThreadInServerFrameThreadType ThreadInServerFrameThread; +} // namespace Tier0 + +typedef Tier0::IMemAlloc* (*CreateGlobalMemAllocType)(); +CreateGlobalMemAllocType CreateGlobalMemAlloc; + +// needs to be a seperate function, since memalloc.cpp calls it +void TryCreateGlobalMemAlloc() +{ + // init memalloc stuff + CreateGlobalMemAlloc = reinterpret_cast<CreateGlobalMemAllocType>(GetProcAddress(GetModuleHandleA("tier0.dll"), "CreateGlobalMemAlloc")); + Tier0::g_pMemAllocSingleton = CreateGlobalMemAlloc(); // if it already exists, this returns the preexisting IMemAlloc instance +} + +ON_DLL_LOAD("tier0.dll", Tier0GameFuncs, (HMODULE baseAddress) +{ + // shouldn't be necessary, but do this just in case + TryCreateGlobalMemAlloc(); + + // setup tier0 funcs + Tier0::Error = reinterpret_cast<Tier0::ErrorType>(GetProcAddress(baseAddress, "Error")); + Tier0::CommandLine = reinterpret_cast<Tier0::CommandLineType>(GetProcAddress(baseAddress, "CommandLine")); + Tier0::Plat_FloatTime = reinterpret_cast<Tier0::Plat_FloatTimeType>(GetProcAddress(baseAddress, "Plat_FloatTime")); + Tier0::ThreadInServerFrameThread = + reinterpret_cast<Tier0::ThreadInServerFrameThreadType>(GetProcAddress(baseAddress, "ThreadInServerFrameThread")); +})
\ No newline at end of file diff --git a/NorthstarDedicatedTest/tier0.h b/NorthstarDedicatedTest/tier0.h new file mode 100644 index 00000000..5fefc699 --- /dev/null +++ b/NorthstarDedicatedTest/tier0.h @@ -0,0 +1,68 @@ +#pragma once +namespace Tier0 +{ + class IMemAlloc + { + public: + struct VTable + { + void* unknown[1]; // alloc debug + void* (*Alloc)(IMemAlloc* memAlloc, size_t nSize); + void* unknown2[1]; // realloc debug + void* (*Realloc)(IMemAlloc* memAlloc, void* pMem, size_t nSize); + void* unknown3[1]; // free #1 + void (*Free)(IMemAlloc* memAlloc, void* pMem); + void* unknown4[2]; // nullsubs, maybe CrtSetDbgFlag + size_t (*GetSize)(IMemAlloc* memAlloc, void* pMem); + void* unknown5[9]; // they all do literally nothing + void (*DumpStats)(IMemAlloc* memAlloc); + void (*DumpStatsFileBase)(IMemAlloc* memAlloc, const char* pchFileBase); + void* unknown6[4]; + int (*heapchk)(IMemAlloc* memAlloc); + }; + + VTable* m_vtable; + }; + + class CCommandLine + { + public: + // based on the defs in the 2013 source sdk, but for some reason has an extra function (may be another CreateCmdLine overload?) + // these seem to line up with what they should be though + virtual void CreateCmdLine(const char* commandline) {} + virtual void CreateCmdLine(int argc, char** argv) {} + virtual void unknown() {} + virtual const char* GetCmdLine(void) const {} + + virtual const char* CheckParm(const char* psz, const char** ppszValue = 0) const {} + virtual void RemoveParm() const {} + virtual void AppendParm(const char* pszParm, const char* pszValues) {} + + virtual const char* ParmValue(const char* psz, const char* pDefaultVal = 0) const {} + virtual int ParmValue(const char* psz, int nDefaultVal) const {} + virtual float ParmValue(const char* psz, float flDefaultVal) const {} + + virtual int ParmCount() const {} + virtual int FindParm(const char* psz) const {} + virtual const char* GetParm(int nIndex) const {} + virtual void SetParm(int nIndex, char const* pParm) {} + + // virtual const char** GetParms() const {} + }; + + extern IMemAlloc* g_pMemAllocSingleton; + + typedef void (*ErrorType)(const char* fmt, ...); + extern ErrorType Error; + + typedef CCommandLine* (*CommandLineType)(); + extern CommandLineType CommandLine; + + typedef double (*Plat_FloatTimeType)(); + extern Plat_FloatTimeType Plat_FloatTime; + + typedef bool (*ThreadInServerFrameThreadType)(); + extern ThreadInServerFrameThreadType ThreadInServerFrameThread; +} // namespace Tier0 + +void TryCreateGlobalMemAlloc();
\ No newline at end of file |