From 829e122cead5521d5ffa57daa7e9fbd10755d68f Mon Sep 17 00:00:00 2001 From: IcePixelx <41352111+PixieCore@users.noreply.github.com> Date: Sat, 15 Jan 2022 15:25:19 +0100 Subject: [PATCH] SQ Serverbrowser V1 push. Clean-up following after @r-ex fixed SQ things. --- r5dev/gameui/IBrowser.cpp | 52 ++++++- r5dev/gameui/IBrowser.h | 6 +- r5dev/r5dev.vcxproj | 2 + r5dev/r5dev.vcxproj.filters | 6 + r5dev/squirrel/sqapi.h | 6 + r5dev/squirrel/sqnativefunctions.cpp | 207 +++++++++++++++++++++++++++ r5dev/squirrel/sqnativefunctions.h | 20 +++ r5dev/squirrel/sqvm.cpp | 29 ++++ r5dev/squirrel/sqvm.h | 15 +- r5dev/tier0/cvar.cpp | 2 +- 10 files changed, 338 insertions(+), 7 deletions(-) create mode 100644 r5dev/squirrel/sqnativefunctions.cpp create mode 100644 r5dev/squirrel/sqnativefunctions.h diff --git a/r5dev/gameui/IBrowser.cpp b/r5dev/gameui/IBrowser.cpp index ffd91627..1d7a68b0 100644 --- a/r5dev/gameui/IBrowser.cpp +++ b/r5dev/gameui/IBrowser.cpp @@ -29,6 +29,7 @@ History: #include "vpc/keyvalues.h" #include "squirrel/sqinit.h" #include "gameui/IBrowser.h" +#include "squirrel/sqapi.h" //----------------------------------------------------------------------------- // Purpose: @@ -88,6 +89,32 @@ IBrowser::~IBrowser() //delete r5net; } +//----------------------------------------------------------------------------- +// Purpose: Sets needed create game vars +//----------------------------------------------------------------------------- +void IBrowser::SetMenuVars(std::string name, std::string vis) +{ + if (vis == "Public") + { + m_Server.bHidden = false; + eServerVisibility = EServerVisibility::PUBLIC; + } + else if (vis == "Private") + { + eServerVisibility = EServerVisibility::HIDDEN; + m_Server.bHidden = true; + } + else + { + m_Server.bHidden = true; + eServerVisibility = EServerVisibility::OFFLINE; + } + + m_Server.svServerName = name; + + UpdateHostingStatus(); +} + //----------------------------------------------------------------------------- // Purpose: draws the main browser front-end //----------------------------------------------------------------------------- @@ -272,6 +299,16 @@ void IBrowser::RefreshServerList() } } +//----------------------------------------------------------------------------- +// Purpose: get server list from pylon. +//----------------------------------------------------------------------------- +void IBrowser::GetServerList() +{ + m_vServerList.clear(); + m_szServerListMessage.clear(); + m_vServerList = g_pR5net->GetServersList(m_szServerListMessage); +} + //----------------------------------------------------------------------------- // Purpose: connects to specified server //----------------------------------------------------------------------------- @@ -302,6 +339,14 @@ void IBrowser::ConnectToServer(const std::string connString, const std::string e ProcessCommand(cmd.str().c_str()); } +//----------------------------------------------------------------------------- +// Purpose: Load playlist into KeyValues. +//----------------------------------------------------------------------------- +void IBrowser::LoadPlaylist(const char* playlistName) +{ + KeyValues_LoadPlaylist(playlistName); +} + //----------------------------------------------------------------------------- // Purpose: draws the hidden private server modal //----------------------------------------------------------------------------- @@ -445,7 +490,7 @@ void IBrowser::HostServerSection() * Playlist gets parsed in two instances, first in LoadPlaylist all the neccessary values. * Then when you would normally call launchplaylist which calls StartPlaylist it would cmd call mp_gamemode which parses the gamemode specific part of the playlist.. */ - KeyValues_LoadPlaylist(m_Server.svPlaylist.c_str()); + LoadPlaylist(m_Server.svPlaylist.c_str()); std::stringstream cgmd; cgmd << "mp_gamemode " << m_Server.svPlaylist; ProcessCommand(cgmd.str().c_str()); @@ -488,7 +533,7 @@ void IBrowser::HostServerSection() * Playlist gets parsed in two instances, first in LoadPlaylist all the neccessary values. * Then when you would normally call launchplaylist which calls StartPlaylist it would cmd call mp_gamemode which parses the gamemode specific part of the playlist.. */ - KeyValues_LoadPlaylist(m_Server.svPlaylist.c_str()); + LoadPlaylist(m_Server.svPlaylist.c_str()); std::stringstream cgmd; cgmd << "mp_gamemode " << m_Server.svPlaylist; ProcessCommand(cgmd.str().c_str()); @@ -761,5 +806,4 @@ void IBrowser::SetStyleVar() style.WindowPadding = ImVec2(5, 5); } - -IBrowser* g_pIBrowser = new IBrowser(); +IBrowser* g_pIBrowser = new IBrowser(); \ No newline at end of file diff --git a/r5dev/gameui/IBrowser.h b/r5dev/gameui/IBrowser.h index f5dcd5ed..c0833069 100644 --- a/r5dev/gameui/IBrowser.h +++ b/r5dev/gameui/IBrowser.h @@ -16,8 +16,11 @@ public: void ServerBrowserSection(); void RefreshServerList(); + void GetServerList(); + void ConnectToServer(const std::string ip, const std::string port, const std::string encKey); void ConnectToServer(const std::string connString, const std::string encKey); + void SetMenuVars(std::string name, std::string vis); void HiddenServersModal(); void HostServerSection(); @@ -26,6 +29,7 @@ public: void SendHostingPostRequest(); void ProcessCommand(const char* command_line); + void LoadPlaylist(const char* playlistName); void SettingsSection(); void RegenerateEncryptionKey(); @@ -113,4 +117,4 @@ public: }; extern IBrowser* g_pIBrowser; -#endif +#endif \ No newline at end of file diff --git a/r5dev/r5dev.vcxproj b/r5dev/r5dev.vcxproj index 7b28127d..2a8d82b6 100644 --- a/r5dev/r5dev.vcxproj +++ b/r5dev/r5dev.vcxproj @@ -59,6 +59,7 @@ + NotUsing @@ -265,6 +266,7 @@ + diff --git a/r5dev/r5dev.vcxproj.filters b/r5dev/r5dev.vcxproj.filters index c26cd15c..4f646e83 100644 --- a/r5dev/r5dev.vcxproj.filters +++ b/r5dev/r5dev.vcxproj.filters @@ -405,6 +405,9 @@ core + + sdk\squirrel + @@ -1046,6 +1049,9 @@ core + + sdk\squirrel + diff --git a/r5dev/squirrel/sqapi.h b/r5dev/squirrel/sqapi.h index 8dce4f0d..cc1f8533 100644 --- a/r5dev/squirrel/sqapi.h +++ b/r5dev/squirrel/sqapi.h @@ -48,6 +48,12 @@ void hsq_newslot(void* sqvm, int idx); void SQAPI_Attach(); void SQAPI_Detach(); +typedef int SQRESULT; +#define SQ_OK (1) +#define SQ_ERROR (-1) +#define SQ_FAILED(res) (res<0) +#define SQ_SUCCEEDED(res) (res>=0) + /////////////////////////////////////////////////////////////////////////////// class HSqapi : public IDetour { diff --git a/r5dev/squirrel/sqnativefunctions.cpp b/r5dev/squirrel/sqnativefunctions.cpp new file mode 100644 index 00000000..a22eaa7c --- /dev/null +++ b/r5dev/squirrel/sqnativefunctions.cpp @@ -0,0 +1,207 @@ +#include "core/stdafx.h" +#include "squirrel/sqnativefunctions.h" + +#include "engine/sys_utils.h" +#include "gameui/IBrowser.h" + +namespace SQNativeFunctions +{ + namespace IBrowser + { + SQRESULT GetServerName(void* sqvm) + { + int svIndex = hsq_getinteger(sqvm, 1); + std::string svName = g_pIBrowser->m_vServerList[svIndex].svServerName; + + hsq_pushstring(sqvm, svName.c_str(), -1); + + return SQ_OK; + } + + SQRESULT GetServerPlaylist(void* sqvm) + { + int svIndex = hsq_getinteger(sqvm, 1); + std::string svPlaylist = g_pIBrowser->m_vServerList[svIndex].svPlaylist; + + hsq_pushstring(sqvm, svPlaylist.c_str(), -1); + + return SQ_OK; + } + + SQRESULT GetServerMap(void* sqvm) + { + int svIndex = hsq_getinteger(sqvm, 1); + std::string svMapName = g_pIBrowser->m_vServerList[svIndex].svMapName; + + hsq_pushstring(sqvm, svMapName.c_str(), -1); + + return SQ_OK; + } + + SQRESULT GetServerAmount(void* sqvm) + { + g_pIBrowser->GetServerList(); // Refresh server list. + + hsq_pushinteger(sqvm, g_pIBrowser->m_vServerList.size() - 1); // please fix the -1 rexx okay thank you. + + return SQ_OK; + } + + SQRESULT GetSDKVersion(void* sqvm) + { + hsq_pushstring(sqvm, g_pR5net->GetSDKVersion().c_str(), -1); + + return SQ_OK; + } + + SQRESULT GetPromoData(void* sqvm) + { + enum class R5RPromoData : int + { + PromoLargeTitle, + PromoLargeDesc, + PromoLeftTitle, + PromoLeftDesc, + PromoRightTitle, + PromoRightDesc + }; + + R5RPromoData prIndex = (R5RPromoData)hsq_getinteger(sqvm, 1); + + std::string prStr = std::string(); + + switch (prIndex) + { + case R5RPromoData::PromoLargeTitle: + { + prStr = "Welcome To R5Reloaded!"; + break; + } + case R5RPromoData::PromoLargeDesc: + { + prStr = "Make sure to join the discord! discord.gg/r5reloaded"; + break; + } + case R5RPromoData::PromoLeftTitle: + { + prStr = "Yes"; + break; + } + case R5RPromoData::PromoLeftDesc: + { + prStr = "Your ad could be here"; + break; + } + case R5RPromoData::PromoRightTitle: + { + prStr = "Yes2"; + break; + } + case R5RPromoData::PromoRightDesc: + { + prStr = "Yes3"; + break; + } + default: + { + prStr = "You should not see this."; + break; + } + } + + hsq_pushstring(sqvm, prStr.c_str(), -1); + + return SQ_OK; + } + + SQRESULT SetEncKeyAndConnect(void* sqvm) + { + int svIndex = hsq_getinteger(sqvm, 1); + + g_pIBrowser->ConnectToServer(g_pIBrowser->m_vServerList[svIndex].svIpAddress, g_pIBrowser->m_vServerList[svIndex].svPort, g_pIBrowser->m_vServerList[svIndex].svEncryptionKey); + + return SQ_OK; + } + + SQRESULT CreateServerFromMenu(void* sqvm) + { + std::string svName = hsq_getstring(sqvm, 1); + std::string svMapName = hsq_getstring(sqvm, 2); + std::string svPlaylist = hsq_getstring(sqvm, 3); + std::string svVisibility = hsq_getstring(sqvm, 4); // Rexx please change this to an integer, so we don't have that ghetto switch case in SetMenuVars. + + if (svMapName.empty() || svPlaylist.empty() || svVisibility.empty()) + return SQ_OK; + + g_pIBrowser->SetMenuVars(svName, svVisibility); // Pass integer instead + + + /* Changing this up to call a IBrowser method eventually. */ + DevMsg(eDLL_T::ENGINE, "Starting Server with map '%s' and playlist '%s'\n", svMapName.c_str(), svPlaylist.c_str()); + + g_pIBrowser->LoadPlaylist(svPlaylist.c_str()); + std::stringstream cgmd; + cgmd << "mp_gamemode " << svPlaylist; + g_pIBrowser->ProcessCommand(cgmd.str().c_str()); + + // This is to avoid svIndex race condition. + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + std::stringstream cmd; + cmd << "map " << svMapName; + g_pIBrowser->ProcessCommand(cmd.str().c_str()); + + return SQ_OK; + } + + SQRESULT JoinPrivateServerFromMenu(void* sqvm) + { + std::string m_szHiddenServerRequestMessage; + + std::string token = hsq_getstring(sqvm, 1); + + ServerListing server; + bool result = g_pR5net->GetServerByToken(server, m_szHiddenServerRequestMessage, token); // Send token connect request. + if (result) + { + g_pIBrowser->ConnectToServer(server.svIpAddress, server.svPort, server.svEncryptionKey); + } + + return SQ_OK; + } + + SQRESULT GetPrivateServerMessage(void* sqvm) + { + std::string m_szHiddenServerRequestMessage; + + std::string token = hsq_getstring(sqvm, 1); + + ServerListing server; + bool result = g_pR5net->GetServerByToken(server, m_szHiddenServerRequestMessage, token); // Send token connect request. + if (!server.svServerName.empty()) + { + m_szHiddenServerRequestMessage = "Found Server: " + server.svServerName; + + hsq_pushstring(sqvm, m_szHiddenServerRequestMessage.c_str(), -1); + } + else + { + m_szHiddenServerRequestMessage = "Error: Server Not Found"; + + hsq_pushstring(sqvm, m_szHiddenServerRequestMessage.c_str(), -1); + } + + return SQ_OK; + } + + SQRESULT ConnectToIPFromMenu(void* sqvm) + { + std::string ip = hsq_getstring(sqvm, 1); + std::string key = hsq_getstring(sqvm, 2); + + g_pIBrowser->ConnectToServer(ip, key); + + return SQ_OK; + } + } +} \ No newline at end of file diff --git a/r5dev/squirrel/sqnativefunctions.h b/r5dev/squirrel/sqnativefunctions.h new file mode 100644 index 00000000..29579027 --- /dev/null +++ b/r5dev/squirrel/sqnativefunctions.h @@ -0,0 +1,20 @@ +#pragma once +#include "squirrel/sqapi.h" + +namespace SQNativeFunctions +{ + namespace IBrowser + { + SQRESULT GetServerName(void* sqvm); + SQRESULT GetServerPlaylist(void* sqvm); + SQRESULT GetServerMap(void* sqvm); + SQRESULT GetServerAmount(void* sqvm); + SQRESULT GetSDKVersion(void* sqvm); + SQRESULT GetPromoData(void* sqvm); + SQRESULT SetEncKeyAndConnect(void* sqvm); + SQRESULT CreateServerFromMenu(void* sqvm); + SQRESULT JoinPrivateServerFromMenu(void* sqvm); + SQRESULT GetPrivateServerMessage(void* sqvm); + SQRESULT ConnectToIPFromMenu(void* sqvm); + } +} \ No newline at end of file diff --git a/r5dev/squirrel/sqvm.cpp b/r5dev/squirrel/sqvm.cpp index fe7567c6..bc071458 100644 --- a/r5dev/squirrel/sqvm.cpp +++ b/r5dev/squirrel/sqvm.cpp @@ -14,6 +14,7 @@ #include "vgui/CEngineVGui.h" #include "gameui/IConsole.h" #include "squirrel/sqvm.h" +#include "squirrel/sqnativefunctions.h" //--------------------------------------------------------------------------------- // Purpose: prints the output of each VM to the console @@ -248,6 +249,22 @@ int HSQVM_NativeTest(void* sqvm) void RegisterUIScriptFunctions(void* sqvm) { HSQVM_RegisterFunction(sqvm, "UINativeTest", "native ui function", "void", "", &HSQVM_NativeTest); + //Server Browser Data + HSQVM_RegisterFunction(sqvm, "GetServerName", "native ui function", "string", "int", &SQNativeFunctions::IBrowser::GetServerName); + HSQVM_RegisterFunction(sqvm, "GetServerPlaylist", "native ui function", "string", "int", &SQNativeFunctions::IBrowser::GetServerPlaylist); + HSQVM_RegisterFunction(sqvm, "GetServerMap", "native ui function", "string", "int", &SQNativeFunctions::IBrowser::GetServerMap); + HSQVM_RegisterFunction(sqvm, "GetServerAmmount", "native ui function", "int", "", &SQNativeFunctions::IBrowser::GetServerAmount); + + //Main Menu Data + HSQVM_RegisterFunction(sqvm, "GetSDKVersion", "native ui function", "string", "", &SQNativeFunctions::IBrowser::GetSDKVersion); + HSQVM_RegisterFunction(sqvm, "GetPromoData", "native ui function", "string", "int", &SQNativeFunctions::IBrowser::GetPromoData); + + //Connecting To Servers + HSQVM_RegisterFunction(sqvm, "CreateServer", "native ui function", "void", "string,string,string,string", &SQNativeFunctions::IBrowser::CreateServerFromMenu); + HSQVM_RegisterFunction(sqvm, "SetEncKeyAndConnect", "native ui function", "void", "int", &SQNativeFunctions::IBrowser::SetEncKeyAndConnect); + HSQVM_RegisterFunction(sqvm, "JoinPrivateServerFromMenu", "native ui function", "void", "string", &SQNativeFunctions::IBrowser::JoinPrivateServerFromMenu); + HSQVM_RegisterFunction(sqvm, "GetPrivateServerMessage", "native ui function", "string", "string", &SQNativeFunctions::IBrowser::GetPrivateServerMessage); + HSQVM_RegisterFunction(sqvm, "ConnectToIPFromMenu", "native ui function", "void", "string,string", &SQNativeFunctions::IBrowser::ConnectToIPFromMenu); } void RegisterClientScriptFunctions(void* sqvm) @@ -260,12 +277,23 @@ void RegisterServerScriptFunctions(void* sqvm) HSQVM_RegisterFunction(sqvm, "ServerNativeTest", "native server function", "void", "", &HSQVM_NativeTest); } +void HSQVM_RegisterOriginFuncs(void* sqvm) +{ + if (sqvm == *p_SQVM_UIVM.RCast()) + RegisterUIScriptFunctions(sqvm); + else + RegisterClientScriptFunctions(sqvm); + + return SQVM_RegisterOriginFuncs(sqvm); +} + void SQVM_Attach() { DetourAttach((LPVOID*)&SQVM_PrintFunc, &HSQVM_PrintFunc); DetourAttach((LPVOID*)&SQVM_WarningFunc, &HSQVM_WarningFunc); DetourAttach((LPVOID*)&SQVM_LoadRson, &HSQVM_LoadRson); DetourAttach((LPVOID*)&SQVM_LoadScript, &HSQVM_LoadScript); + DetourAttach((LPVOID*)&SQVM_RegisterOriginFuncs, &HSQVM_RegisterOriginFuncs); } void SQVM_Detach() @@ -274,6 +302,7 @@ void SQVM_Detach() DetourDetach((LPVOID*)&SQVM_WarningFunc, &HSQVM_WarningFunc); DetourDetach((LPVOID*)&SQVM_LoadRson, &HSQVM_LoadRson); DetourDetach((LPVOID*)&SQVM_LoadScript, &HSQVM_LoadScript); + DetourDetach((LPVOID*)&SQVM_RegisterOriginFuncs, &HSQVM_RegisterOriginFuncs); } /////////////////////////////////////////////////////////////////////////////// diff --git a/r5dev/squirrel/sqvm.h b/r5dev/squirrel/sqvm.h index d3d5e57a..a74c39a9 100644 --- a/r5dev/squirrel/sqvm.h +++ b/r5dev/squirrel/sqvm.h @@ -43,6 +43,12 @@ const static std::string SQVM_ANSI_LOG_T[4] = "\u001b[90mScript(X):" }; +typedef int SQRESULT; +#define SQ_OK (1) +#define SQ_ERROR (-1) +#define SQ_FAILED(res) (res<0) +#define SQ_SUCCEEDED(res) (res>=0) + namespace { /* ==== SQUIRREL ======================================================================================================================================================== */ @@ -66,6 +72,13 @@ namespace ADDRESS p_SQVM_RegisterFunc = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x83\xEC\x38\x45\x0F\xB6\xC8", "xxxxxxxx"); /*48 83 EC 38 45 0F B6 C8*/ void* (*SQVM_RegisterFunc)(void* sqvm, SQFuncRegistration* sqFunc, int a1) = (void* (*)(void*, SQFuncRegistration*, int))p_SQVM_RegisterFunc.GetPtr(); + + ADDRESS p_SQVM_CreateUIVM = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x40\x53\x48\x83\xEC\x20\x48\x8B\x1D\x00\x00\x00\x00\xC6\x05\x00\x00\x00\x00\x00", "xxxxxxxxx????xx?????"); /*40 53 48 83 EC 20 48 8B 1D ? ? ? ? C6 05 ? ? ? ? ?*/ + bool (*SQVM_CreateUIVM)() = (bool(*)())p_SQVM_CreateUIVM.GetPtr(); + ADDRESS p_SQVM_UIVM = (void*)p_SQVM_CreateUIVM.FindPatternSelf("48 8B 1D", ADDRESS::Direction::DOWN, 50).ResolveRelativeAddressSelf(0x3, 0x7).GetPtr(); + + ADDRESS p_SQVM_RegisterOriginFuncs = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\xE8\x00\x00\x00\x00\x48\x8B\x0D\x00\x00\x00\x00\x48\x8D\x15\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x48\x8B\x05\x00\x00\x00\x00\xC7\x05\x00\x00\x00\x00\x00\x00\x00\x00", "x????xxx????xxx????x????xxx????xx????????"); /*E8 ? ? ? ? 48 8B 0D ? ? ? ? 48 8D 15 ? ? ? ? E8 ? ? ? ? 48 8B 05 ? ? ? ? C7 05 ? ? ? ? ? ? ? ?*/ + void (*SQVM_RegisterOriginFuncs)(void* sqvm) = (void(*)(void*))p_SQVM_RegisterOriginFuncs.FollowNearCall().GetPtr(); } void* HSQVM_PrintFunc(void* sqvm, char* fmt, ...); @@ -74,7 +87,7 @@ bool HSQVM_LoadScript(void* sqvm, const char* szScriptPath, const char* szScript void HSQVM_RegisterFunction(void* sqvm, const char* szName, const char* szHelpString, const char* szRetValType, const char* szArgTypes, void* pFunction); int HSQVM_NativeTest(void* sqvm); - +void HSQVM_RegisterOriginFuncs(void* sqvm); void SQVM_Attach(); void SQVM_Detach(); diff --git a/r5dev/tier0/cvar.cpp b/r5dev/tier0/cvar.cpp index df4ce362..9c7e35b9 100644 --- a/r5dev/tier0/cvar.cpp +++ b/r5dev/tier0/cvar.cpp @@ -96,7 +96,7 @@ CCVarIteratorInternal* CCVar::FactoryInternalIterator() std::unordered_map CCVar::DumpToMap() { std::stringstream ss; - CCVarIteratorInternal* itint = FactoryInternalIterator(); // Allocatd new InternalIterator. + CCVarIteratorInternal* itint = FactoryInternalIterator(); // Allocate new InternalIterator. std::unordered_map allConVars;