diff options
Diffstat (limited to 'NorthstarDLL/scripts')
17 files changed, 0 insertions, 2793 deletions
diff --git a/NorthstarDLL/scripts/client/clientchathooks.cpp b/NorthstarDLL/scripts/client/clientchathooks.cpp deleted file mode 100644 index e084f47e..00000000 --- a/NorthstarDLL/scripts/client/clientchathooks.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "squirrel/squirrel.h" -#include "util/utils.h" - -#include "server/serverchathooks.h" -#include "client/localchatwriter.h" - -#include <rapidjson/document.h> - -AUTOHOOK_INIT() - -// clang-format off -AUTOHOOK(CHudChat__AddGameLine, client.dll + 0x22E580, -void, __fastcall, (void* self, const char* message, int inboxId, bool isTeam, bool isDead)) -// clang-format on -{ - // This hook is called for each HUD, but we only want our logic to run once. - if (self != *CHudChat::allHuds) - return; - - int senderId = inboxId & CUSTOM_MESSAGE_INDEX_MASK; - bool isAnonymous = senderId == 0; - bool isCustom = isAnonymous || (inboxId & CUSTOM_MESSAGE_INDEX_BIT); - - // Type is set to 0 for non-custom messages, custom messages have a type encoded as the first byte - int type = 0; - const char* payload = message; - if (isCustom) - { - type = message[0]; - payload = message + 1; - } - - RemoveAsciiControlSequences(const_cast<char*>(message), true); - - SQRESULT result = g_pSquirrel<ScriptContext::CLIENT>->Call( - "CHudChat_ProcessMessageStartThread", static_cast<int>(senderId) - 1, payload, isTeam, isDead, type); - if (result == SQRESULT_ERROR) - for (CHudChat* hud = *CHudChat::allHuds; hud != NULL; hud = hud->next) - CHudChat__AddGameLine(hud, message, inboxId, isTeam, isDead); -} - -ADD_SQFUNC("void", NSChatWrite, "int context, string text", "", ScriptContext::CLIENT) -{ - int chatContext = g_pSquirrel<ScriptContext::CLIENT>->getinteger(sqvm, 1); - const char* str = g_pSquirrel<ScriptContext::CLIENT>->getstring(sqvm, 2); - - LocalChatWriter((LocalChatWriter::Context)chatContext).Write(str); - return SQRESULT_NULL; -} - -ADD_SQFUNC("void", NSChatWriteRaw, "int context, string text", "", ScriptContext::CLIENT) -{ - int chatContext = g_pSquirrel<ScriptContext::CLIENT>->getinteger(sqvm, 1); - const char* str = g_pSquirrel<ScriptContext::CLIENT>->getstring(sqvm, 2); - - LocalChatWriter((LocalChatWriter::Context)chatContext).InsertText(str); - return SQRESULT_NULL; -} - -ADD_SQFUNC("void", NSChatWriteLine, "int context, string text", "", ScriptContext::CLIENT) -{ - int chatContext = g_pSquirrel<ScriptContext::CLIENT>->getinteger(sqvm, 1); - const char* str = g_pSquirrel<ScriptContext::CLIENT>->getstring(sqvm, 2); - - LocalChatWriter((LocalChatWriter::Context)chatContext).WriteLine(str); - return SQRESULT_NULL; -} - -ON_DLL_LOAD_CLIENT("client.dll", ClientChatHooks, (CModule module)) -{ - AUTOHOOK_DISPATCH() -} diff --git a/NorthstarDLL/scripts/client/cursorposition.cpp b/NorthstarDLL/scripts/client/cursorposition.cpp deleted file mode 100644 index c0e8623c..00000000 --- a/NorthstarDLL/scripts/client/cursorposition.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "squirrel/squirrel.h" -#include "util/wininfo.h" - -ADD_SQFUNC("vector ornull", NSGetCursorPosition, "", "", ScriptContext::UI) -{ - RECT rcClient; - POINT p; - if (GetCursorPos(&p) && ScreenToClient(*g_gameHWND, &p) && GetClientRect(*g_gameHWND, &rcClient)) - { - if (GetAncestor(GetForegroundWindow(), GA_ROOTOWNER) != *g_gameHWND) - return SQRESULT_NULL; - - g_pSquirrel<context>->pushvector( - sqvm, - {p.x > 0 ? p.x > rcClient.right ? rcClient.right : (float)p.x : 0, - p.y > 0 ? p.y > rcClient.bottom ? rcClient.bottom : (float)p.y : 0, - 0}); - return SQRESULT_NOTNULL; - } - g_pSquirrel<context>->raiseerror(sqvm, "Failed retrieving cursor position of game window"); - return SQRESULT_ERROR; -} diff --git a/NorthstarDLL/scripts/client/scriptbrowserhooks.cpp b/NorthstarDLL/scripts/client/scriptbrowserhooks.cpp deleted file mode 100644 index 86b4a356..00000000 --- a/NorthstarDLL/scripts/client/scriptbrowserhooks.cpp +++ /dev/null @@ -1,24 +0,0 @@ - -AUTOHOOK_INIT() - -bool* bIsOriginOverlayEnabled; - -// clang-format off -AUTOHOOK(OpenExternalWebBrowser, engine.dll + 0x184E40, -void, __fastcall, (char* pUrl, char flags)) -// clang-format on -{ - bool bIsOriginOverlayEnabledOriginal = *bIsOriginOverlayEnabled; - if (flags & 2 && !strncmp(pUrl, "http", 4)) // custom force external browser flag - *bIsOriginOverlayEnabled = false; // if this bool is false, game will use an external browser rather than the origin overlay one - - OpenExternalWebBrowser(pUrl, flags); - *bIsOriginOverlayEnabled = bIsOriginOverlayEnabledOriginal; -} - -ON_DLL_LOAD_CLIENT("engine.dll", ScriptExternalBrowserHooks, (CModule module)) -{ - AUTOHOOK_DISPATCH() - - bIsOriginOverlayEnabled = module.Offset(0x13978255).RCast<bool*>(); -} diff --git a/NorthstarDLL/scripts/client/scriptmainmenupromos.cpp b/NorthstarDLL/scripts/client/scriptmainmenupromos.cpp deleted file mode 100644 index ecb47af7..00000000 --- a/NorthstarDLL/scripts/client/scriptmainmenupromos.cpp +++ /dev/null @@ -1,123 +0,0 @@ -#include "squirrel/squirrel.h" -#include "masterserver/masterserver.h" - -// mirror this in script -enum eMainMenuPromoDataProperty -{ - newInfoTitle1, - newInfoTitle2, - newInfoTitle3, - - largeButtonTitle, - largeButtonText, - largeButtonUrl, - largeButtonImageIndex, - - smallButton1Title, - smallButton1Url, - smallButton1ImageIndex, - - smallButton2Title, - smallButton2Url, - smallButton2ImageIndex -}; -ADD_SQFUNC("void", NSRequestCustomMainMenuPromos, "", "", ScriptContext::UI) -{ - g_pMasterServerManager->RequestMainMenuPromos(); - return SQRESULT_NULL; -} - -ADD_SQFUNC("bool", NSHasCustomMainMenuPromoData, "", "", ScriptContext::UI) -{ - g_pSquirrel<ScriptContext::UI>->pushbool(sqvm, g_pMasterServerManager->m_bHasMainMenuPromoData); - return SQRESULT_NOTNULL; -} - -ADD_SQFUNC("var", NSGetCustomMainMenuPromoData, "int promoDataKey", "", ScriptContext::UI) -{ - if (!g_pMasterServerManager->m_bHasMainMenuPromoData) - return SQRESULT_NULL; - - switch (g_pSquirrel<ScriptContext::UI>->getinteger(sqvm, 1)) - { - case eMainMenuPromoDataProperty::newInfoTitle1: - { - g_pSquirrel<ScriptContext::UI>->pushstring(sqvm, g_pMasterServerManager->m_sMainMenuPromoData.newInfoTitle1.c_str()); - break; - } - - case eMainMenuPromoDataProperty::newInfoTitle2: - { - g_pSquirrel<ScriptContext::UI>->pushstring(sqvm, g_pMasterServerManager->m_sMainMenuPromoData.newInfoTitle2.c_str()); - break; - } - - case eMainMenuPromoDataProperty::newInfoTitle3: - { - g_pSquirrel<ScriptContext::UI>->pushstring(sqvm, g_pMasterServerManager->m_sMainMenuPromoData.newInfoTitle3.c_str()); - break; - } - - case eMainMenuPromoDataProperty::largeButtonTitle: - { - g_pSquirrel<ScriptContext::UI>->pushstring(sqvm, g_pMasterServerManager->m_sMainMenuPromoData.largeButtonTitle.c_str()); - break; - } - - case eMainMenuPromoDataProperty::largeButtonText: - { - g_pSquirrel<ScriptContext::UI>->pushstring(sqvm, g_pMasterServerManager->m_sMainMenuPromoData.largeButtonText.c_str()); - break; - } - - case eMainMenuPromoDataProperty::largeButtonUrl: - { - g_pSquirrel<ScriptContext::UI>->pushstring(sqvm, g_pMasterServerManager->m_sMainMenuPromoData.largeButtonUrl.c_str()); - break; - } - - case eMainMenuPromoDataProperty::largeButtonImageIndex: - { - g_pSquirrel<ScriptContext::UI>->pushinteger(sqvm, g_pMasterServerManager->m_sMainMenuPromoData.largeButtonImageIndex); - break; - } - - case eMainMenuPromoDataProperty::smallButton1Title: - { - g_pSquirrel<ScriptContext::UI>->pushstring(sqvm, g_pMasterServerManager->m_sMainMenuPromoData.smallButton1Title.c_str()); - break; - } - - case eMainMenuPromoDataProperty::smallButton1Url: - { - g_pSquirrel<ScriptContext::UI>->pushstring(sqvm, g_pMasterServerManager->m_sMainMenuPromoData.smallButton1Url.c_str()); - break; - } - - case eMainMenuPromoDataProperty::smallButton1ImageIndex: - { - g_pSquirrel<ScriptContext::UI>->pushinteger(sqvm, g_pMasterServerManager->m_sMainMenuPromoData.smallButton1ImageIndex); - break; - } - - case eMainMenuPromoDataProperty::smallButton2Title: - { - g_pSquirrel<ScriptContext::UI>->pushstring(sqvm, g_pMasterServerManager->m_sMainMenuPromoData.smallButton2Title.c_str()); - break; - } - - case eMainMenuPromoDataProperty::smallButton2Url: - { - g_pSquirrel<ScriptContext::UI>->pushstring(sqvm, g_pMasterServerManager->m_sMainMenuPromoData.smallButton2Url.c_str()); - break; - } - - case eMainMenuPromoDataProperty::smallButton2ImageIndex: - { - g_pSquirrel<ScriptContext::UI>->pushinteger(sqvm, g_pMasterServerManager->m_sMainMenuPromoData.smallButton2ImageIndex); - break; - } - } - - return SQRESULT_NOTNULL; -} diff --git a/NorthstarDLL/scripts/client/scriptmodmenu.cpp b/NorthstarDLL/scripts/client/scriptmodmenu.cpp deleted file mode 100644 index a88478fb..00000000 --- a/NorthstarDLL/scripts/client/scriptmodmenu.cpp +++ /dev/null @@ -1,165 +0,0 @@ -#include "mods/modmanager.h" -#include "squirrel/squirrel.h" - -ADD_SQFUNC("array<string>", NSGetModNames, "", "", ScriptContext::SERVER | ScriptContext::CLIENT | ScriptContext::UI) -{ - g_pSquirrel<context>->newarray(sqvm, 0); - - for (Mod& mod : g_pModManager->m_LoadedMods) - { - g_pSquirrel<context>->pushstring(sqvm, mod.Name.c_str()); - g_pSquirrel<context>->arrayappend(sqvm, -2); - } - - return SQRESULT_NOTNULL; -} - -ADD_SQFUNC("bool", NSIsModEnabled, "string modName", "", ScriptContext::SERVER | ScriptContext::CLIENT | ScriptContext::UI) -{ - const SQChar* modName = g_pSquirrel<context>->getstring(sqvm, 1); - - // manual lookup, not super performant but eh not a big deal - for (Mod& mod : g_pModManager->m_LoadedMods) - { - if (!mod.Name.compare(modName)) - { - g_pSquirrel<context>->pushbool(sqvm, mod.m_bEnabled); - return SQRESULT_NOTNULL; - } - } - - return SQRESULT_NULL; -} - -ADD_SQFUNC("void", NSSetModEnabled, "string modName, bool enabled", "", ScriptContext::SERVER | ScriptContext::CLIENT | ScriptContext::UI) -{ - const SQChar* modName = g_pSquirrel<context>->getstring(sqvm, 1); - const SQBool enabled = g_pSquirrel<context>->getbool(sqvm, 2); - - // manual lookup, not super performant but eh not a big deal - for (Mod& mod : g_pModManager->m_LoadedMods) - { - if (!mod.Name.compare(modName)) - { - mod.m_bEnabled = enabled; - return SQRESULT_NULL; - } - } - - return SQRESULT_NULL; -} - -ADD_SQFUNC("string", NSGetModDescriptionByModName, "string modName", "", ScriptContext::SERVER | ScriptContext::CLIENT | ScriptContext::UI) -{ - const SQChar* modName = g_pSquirrel<context>->getstring(sqvm, 1); - - // manual lookup, not super performant but eh not a big deal - for (Mod& mod : g_pModManager->m_LoadedMods) - { - if (!mod.Name.compare(modName)) - { - g_pSquirrel<context>->pushstring(sqvm, mod.Description.c_str()); - return SQRESULT_NOTNULL; - } - } - - return SQRESULT_NULL; -} - -ADD_SQFUNC("string", NSGetModVersionByModName, "string modName", "", ScriptContext::SERVER | ScriptContext::CLIENT | ScriptContext::UI) -{ - const SQChar* modName = g_pSquirrel<context>->getstring(sqvm, 1); - - // manual lookup, not super performant but eh not a big deal - for (Mod& mod : g_pModManager->m_LoadedMods) - { - if (!mod.Name.compare(modName)) - { - g_pSquirrel<context>->pushstring(sqvm, mod.Version.c_str()); - return SQRESULT_NOTNULL; - } - } - - return SQRESULT_NULL; -} - -ADD_SQFUNC("string", NSGetModDownloadLinkByModName, "string modName", "", ScriptContext::SERVER | ScriptContext::CLIENT | ScriptContext::UI) -{ - const SQChar* modName = g_pSquirrel<context>->getstring(sqvm, 1); - - // manual lookup, not super performant but eh not a big deal - for (Mod& mod : g_pModManager->m_LoadedMods) - { - if (!mod.Name.compare(modName)) - { - g_pSquirrel<context>->pushstring(sqvm, mod.DownloadLink.c_str()); - return SQRESULT_NOTNULL; - } - } - - return SQRESULT_NULL; -} - -ADD_SQFUNC("int", NSGetModLoadPriority, "string modName", "", ScriptContext::SERVER | ScriptContext::CLIENT | ScriptContext::UI) -{ - const SQChar* modName = g_pSquirrel<context>->getstring(sqvm, 1); - - // manual lookup, not super performant but eh not a big deal - for (Mod& mod : g_pModManager->m_LoadedMods) - { - if (!mod.Name.compare(modName)) - { - g_pSquirrel<context>->pushinteger(sqvm, mod.LoadPriority); - return SQRESULT_NOTNULL; - } - } - - return SQRESULT_NULL; -} - -ADD_SQFUNC("bool", NSIsModRequiredOnClient, "string modName", "", ScriptContext::SERVER | ScriptContext::CLIENT | ScriptContext::UI) -{ - const SQChar* modName = g_pSquirrel<context>->getstring(sqvm, 1); - - // manual lookup, not super performant but eh not a big deal - for (Mod& mod : g_pModManager->m_LoadedMods) - { - if (!mod.Name.compare(modName)) - { - g_pSquirrel<context>->pushbool(sqvm, mod.RequiredOnClient); - return SQRESULT_NOTNULL; - } - } - - return SQRESULT_NULL; -} - -ADD_SQFUNC( - "array<string>", NSGetModConvarsByModName, "string modName", "", ScriptContext::SERVER | ScriptContext::CLIENT | ScriptContext::UI) -{ - const SQChar* modName = g_pSquirrel<context>->getstring(sqvm, 1); - g_pSquirrel<context>->newarray(sqvm, 0); - - // manual lookup, not super performant but eh not a big deal - for (Mod& mod : g_pModManager->m_LoadedMods) - { - if (!mod.Name.compare(modName)) - { - for (ModConVar* cvar : mod.ConVars) - { - g_pSquirrel<context>->pushstring(sqvm, cvar->Name.c_str()); - g_pSquirrel<context>->arrayappend(sqvm, -2); - } - - return SQRESULT_NOTNULL; - } - } - - return SQRESULT_NOTNULL; // return empty array -} - -ADD_SQFUNC("void", NSReloadMods, "", "", ScriptContext::UI) -{ - g_pModManager->LoadMods(); - return SQRESULT_NULL; -} diff --git a/NorthstarDLL/scripts/client/scriptoriginauth.cpp b/NorthstarDLL/scripts/client/scriptoriginauth.cpp deleted file mode 100644 index 420c4872..00000000 --- a/NorthstarDLL/scripts/client/scriptoriginauth.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "squirrel/squirrel.h" -#include "masterserver/masterserver.h" -#include "engine/r2engine.h" -#include "client/r2client.h" - -ADD_SQFUNC("bool", NSIsMasterServerAuthenticated, "", "", ScriptContext::UI) -{ - g_pSquirrel<context>->pushbool(sqvm, g_pMasterServerManager->m_bOriginAuthWithMasterServerDone); - return SQRESULT_NOTNULL; -} - -/* -global struct MasterServerAuthResult -{ - bool success - string errorCode - string errorMessage -} -*/ - -ADD_SQFUNC("MasterServerAuthResult", NSGetMasterServerAuthResult, "", "", ScriptContext::UI) -{ - g_pSquirrel<context>->pushnewstructinstance(sqvm, 3); - - g_pSquirrel<context>->pushbool(sqvm, g_pMasterServerManager->m_bOriginAuthWithMasterServerSuccessful); - g_pSquirrel<context>->sealstructslot(sqvm, 0); - - g_pSquirrel<context>->pushstring(sqvm, g_pMasterServerManager->m_sOriginAuthWithMasterServerErrorCode.c_str(), -1); - g_pSquirrel<context>->sealstructslot(sqvm, 1); - - g_pSquirrel<context>->pushstring(sqvm, g_pMasterServerManager->m_sOriginAuthWithMasterServerErrorMessage.c_str(), -1); - g_pSquirrel<context>->sealstructslot(sqvm, 2); - - return SQRESULT_NOTNULL; -} diff --git a/NorthstarDLL/scripts/client/scriptserverbrowser.cpp b/NorthstarDLL/scripts/client/scriptserverbrowser.cpp deleted file mode 100644 index a142c3f4..00000000 --- a/NorthstarDLL/scripts/client/scriptserverbrowser.cpp +++ /dev/null @@ -1,209 +0,0 @@ -#include "squirrel/squirrel.h" -#include "masterserver/masterserver.h" -#include "server/auth/serverauthentication.h" -#include "engine/r2engine.h" -#include "client/r2client.h" - -// functions for viewing server browser - -ADD_SQFUNC("void", NSRequestServerList, "", "", ScriptContext::UI) -{ - g_pMasterServerManager->RequestServerList(); - return SQRESULT_NULL; -} - -ADD_SQFUNC("bool", NSIsRequestingServerList, "", "", ScriptContext::UI) -{ - g_pSquirrel<context>->pushbool(sqvm, g_pMasterServerManager->m_bScriptRequestingServerList); - return SQRESULT_NOTNULL; -} - -ADD_SQFUNC("bool", NSMasterServerConnectionSuccessful, "", "", ScriptContext::UI) -{ - g_pSquirrel<context>->pushbool(sqvm, g_pMasterServerManager->m_bSuccessfullyConnected); - return SQRESULT_NOTNULL; -} - -ADD_SQFUNC("int", NSGetServerCount, "", "", ScriptContext::UI) -{ - g_pSquirrel<context>->pushinteger(sqvm, g_pMasterServerManager->m_vRemoteServers.size()); - return SQRESULT_NOTNULL; -} - -ADD_SQFUNC("void", NSClearRecievedServerList, "", "", ScriptContext::UI) -{ - g_pMasterServerManager->ClearServerList(); - return SQRESULT_NULL; -} - -// functions for authenticating with servers - -ADD_SQFUNC("void", NSTryAuthWithServer, "int serverIndex, string password = ''", "", ScriptContext::UI) -{ - SQInteger serverIndex = g_pSquirrel<context>->getinteger(sqvm, 1); - const SQChar* password = g_pSquirrel<context>->getstring(sqvm, 2); - - if (serverIndex >= g_pMasterServerManager->m_vRemoteServers.size()) - { - g_pSquirrel<context>->raiseerror( - sqvm, - fmt::format( - "Tried to auth with server index {} when only {} servers are available", - serverIndex, - g_pMasterServerManager->m_vRemoteServers.size()) - .c_str()); - return SQRESULT_ERROR; - } - - // send off persistent data first, don't worry about server/client stuff, since m_additionalPlayerData should only have entries when - // we're a local server note: this seems like it could create a race condition, test later - for (auto& pair : g_pServerAuthentication->m_PlayerAuthenticationData) - g_pServerAuthentication->WritePersistentData(pair.first); - - // do auth - g_pMasterServerManager->AuthenticateWithServer( - g_pLocalPlayerUserID, - g_pMasterServerManager->m_sOwnClientAuthToken, - g_pMasterServerManager->m_vRemoteServers[serverIndex], - (char*)password); - - return SQRESULT_NULL; -} - -ADD_SQFUNC("bool", NSIsAuthenticatingWithServer, "", "", ScriptContext::UI) -{ - g_pSquirrel<context>->pushbool(sqvm, g_pMasterServerManager->m_bScriptAuthenticatingWithGameServer); - return SQRESULT_NOTNULL; -} - -ADD_SQFUNC("bool", NSWasAuthSuccessful, "", "", ScriptContext::UI) -{ - g_pSquirrel<context>->pushbool(sqvm, g_pMasterServerManager->m_bSuccessfullyAuthenticatedWithGameServer); - return SQRESULT_NOTNULL; -} - -ADD_SQFUNC("void", NSConnectToAuthedServer, "", "", ScriptContext::UI) -{ - if (!g_pMasterServerManager->m_bHasPendingConnectionInfo) - { - g_pSquirrel<context>->raiseerror( - sqvm, fmt::format("Tried to connect to authed server before any pending connection info was available").c_str()); - return SQRESULT_ERROR; - } - - RemoteServerConnectionInfo& info = g_pMasterServerManager->m_pendingConnectionInfo; - - // set auth token, then try to connect - // i'm honestly not entirely sure how silentconnect works regarding ports and encryption so using connect for now - g_pCVar->FindVar("serverfilter")->SetValue(info.authToken); - Cbuf_AddText( - Cbuf_GetCurrentPlayer(), - fmt::format( - "connect {}.{}.{}.{}:{}", - info.ip.S_un.S_un_b.s_b1, - info.ip.S_un.S_un_b.s_b2, - info.ip.S_un.S_un_b.s_b3, - info.ip.S_un.S_un_b.s_b4, - info.port) - .c_str(), - cmd_source_t::kCommandSrcCode); - - g_pMasterServerManager->m_bHasPendingConnectionInfo = false; - return SQRESULT_NULL; -} - -ADD_SQFUNC("void", NSTryAuthWithLocalServer, "", "", ScriptContext::UI) -{ - // do auth request - g_pMasterServerManager->AuthenticateWithOwnServer(g_pLocalPlayerUserID, g_pMasterServerManager->m_sOwnClientAuthToken); - - return SQRESULT_NULL; -} - -ADD_SQFUNC("void", NSCompleteAuthWithLocalServer, "", "", ScriptContext::UI) -{ - // literally just set serverfilter - // note: this assumes we have no authdata other than our own - if (g_pServerAuthentication->m_RemoteAuthenticationData.size()) - g_pCVar->FindVar("serverfilter")->SetValue(g_pServerAuthentication->m_RemoteAuthenticationData.begin()->first.c_str()); - - return SQRESULT_NULL; -} - -ADD_SQFUNC("string", NSGetAuthFailReason, "", "", ScriptContext::UI) -{ - g_pSquirrel<context>->pushstring(sqvm, g_pMasterServerManager->m_sAuthFailureReason.c_str(), -1); - return SQRESULT_NOTNULL; -} - -ADD_SQFUNC("array<ServerInfo>", NSGetGameServers, "", "", ScriptContext::UI) -{ - g_pSquirrel<context>->newarray(sqvm, 0); - for (size_t i = 0; i < g_pMasterServerManager->m_vRemoteServers.size(); i++) - { - const RemoteServerInfo& remoteServer = g_pMasterServerManager->m_vRemoteServers[i]; - - g_pSquirrel<context>->pushnewstructinstance(sqvm, 11); - - // index - g_pSquirrel<context>->pushinteger(sqvm, i); - g_pSquirrel<context>->sealstructslot(sqvm, 0); - - // id - g_pSquirrel<context>->pushstring(sqvm, remoteServer.id, -1); - g_pSquirrel<context>->sealstructslot(sqvm, 1); - - // name - g_pSquirrel<context>->pushstring(sqvm, remoteServer.name, -1); - g_pSquirrel<context>->sealstructslot(sqvm, 2); - - // description - g_pSquirrel<context>->pushstring(sqvm, remoteServer.description.c_str(), -1); - g_pSquirrel<context>->sealstructslot(sqvm, 3); - - // map - g_pSquirrel<context>->pushstring(sqvm, remoteServer.map, -1); - g_pSquirrel<context>->sealstructslot(sqvm, 4); - - // playlist - g_pSquirrel<context>->pushstring(sqvm, remoteServer.playlist, -1); - g_pSquirrel<context>->sealstructslot(sqvm, 5); - - // playerCount - g_pSquirrel<context>->pushinteger(sqvm, remoteServer.playerCount); - g_pSquirrel<context>->sealstructslot(sqvm, 6); - - // maxPlayerCount - g_pSquirrel<context>->pushinteger(sqvm, remoteServer.maxPlayers); - g_pSquirrel<context>->sealstructslot(sqvm, 7); - - // requiresPassword - g_pSquirrel<context>->pushbool(sqvm, remoteServer.requiresPassword); - g_pSquirrel<context>->sealstructslot(sqvm, 8); - - // region - g_pSquirrel<context>->pushstring(sqvm, remoteServer.region, -1); - g_pSquirrel<context>->sealstructslot(sqvm, 9); - - // requiredMods - g_pSquirrel<context>->newarray(sqvm); - for (const RemoteModInfo& mod : remoteServer.requiredMods) - { - g_pSquirrel<context>->pushnewstructinstance(sqvm, 2); - - // name - g_pSquirrel<context>->pushstring(sqvm, mod.Name.c_str(), -1); - g_pSquirrel<context>->sealstructslot(sqvm, 0); - - // version - g_pSquirrel<context>->pushstring(sqvm, mod.Version.c_str(), -1); - g_pSquirrel<context>->sealstructslot(sqvm, 1); - - g_pSquirrel<context>->arrayappend(sqvm, -2); - } - g_pSquirrel<context>->sealstructslot(sqvm, 10); - - g_pSquirrel<context>->arrayappend(sqvm, -2); - } - return SQRESULT_NOTNULL; -} diff --git a/NorthstarDLL/scripts/client/scriptservertoclientstringcommand.cpp b/NorthstarDLL/scripts/client/scriptservertoclientstringcommand.cpp deleted file mode 100644 index a3a81c8a..00000000 --- a/NorthstarDLL/scripts/client/scriptservertoclientstringcommand.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "squirrel/squirrel.h" -#include "core/convar/convar.h" -#include "core/convar/concommand.h" - -void ConCommand_ns_script_servertoclientstringcommand(const CCommand& arg) -{ - if (g_pSquirrel<ScriptContext::CLIENT>->m_pSQVM) - g_pSquirrel<ScriptContext::CLIENT>->Call("NSClientCodeCallback_RecievedServerToClientStringCommand", arg.ArgS()); -} - -ON_DLL_LOAD_CLIENT_RELIESON("client.dll", ScriptServerToClientStringCommand, ClientSquirrel, (CModule module)) -{ - RegisterConCommand( - "ns_script_servertoclientstringcommand", - ConCommand_ns_script_servertoclientstringcommand, - "", - FCVAR_CLIENTDLL | FCVAR_SERVER_CAN_EXECUTE); -} diff --git a/NorthstarDLL/scripts/scriptdatatables.cpp b/NorthstarDLL/scripts/scriptdatatables.cpp deleted file mode 100644 index 87a26dca..00000000 --- a/NorthstarDLL/scripts/scriptdatatables.cpp +++ /dev/null @@ -1,909 +0,0 @@ -#include "squirrel/squirrel.h" -#include "core/filesystem/rpakfilesystem.h" -#include "core/convar/convar.h" -#include "dedicated/dedicated.h" -#include "core/filesystem/filesystem.h" -#include "core/math/vector.h" -#include "core/tier0.h" -#include "engine/r2engine.h" -#include <iostream> -#include <sstream> -#include <map> -#include <fstream> -#include <filesystem> - -const uint64_t USERDATA_TYPE_DATATABLE = 0xFFF7FFF700000004; -const uint64_t USERDATA_TYPE_DATATABLE_CUSTOM = 0xFFFCFFFC12345678; - -enum class DatatableType : int -{ - BOOL = 0, - INT, - FLOAT, - VECTOR, - STRING, - ASSET, - UNK_STRING // unknown but deffo a string type -}; - -struct ColumnInfo -{ - char* name; - DatatableType type; - int offset; -}; - -struct Datatable -{ - int numColumns; - int numRows; - ColumnInfo* columnInfo; - char* data; // actually data pointer - int rowInfo; -}; - -ConVar* Cvar_ns_prefer_datatable_from_disk; - -template <ScriptContext context> Datatable* (*SQ_GetDatatableInternal)(HSquirrelVM* sqvm); - -struct CSVData -{ - std::string m_sAssetName; - std::string m_sCSVString; - char* m_pDataBuf; - size_t m_nDataBufSize; - - std::vector<char*> columns; - std::vector<std::vector<char*>> dataPointers; -}; - -std::unordered_map<std::string, CSVData> CSVCache; - -Vector3 StringToVector(char* pString) -{ - Vector3 vRet; - - int length = 0; - while (pString[length]) - { - if ((pString[length] == '<') || (pString[length] == '>')) - pString[length] = '\0'; - length++; - } - - int startOfFloat = 1; - int currentIndex = 1; - - while (pString[currentIndex] && (pString[currentIndex] != ',')) - currentIndex++; - pString[currentIndex] = '\0'; - vRet.x = std::stof(&pString[startOfFloat]); - startOfFloat = ++currentIndex; - - while (pString[currentIndex] && (pString[currentIndex] != ',')) - currentIndex++; - pString[currentIndex] = '\0'; - vRet.y = std::stof(&pString[startOfFloat]); - startOfFloat = ++currentIndex; - - while (pString[currentIndex] && (pString[currentIndex] != ',')) - currentIndex++; - pString[currentIndex] = '\0'; - vRet.z = std::stof(&pString[startOfFloat]); - startOfFloat = ++currentIndex; - - return vRet; -} - -// var function GetDataTable( asset path ) -REPLACE_SQFUNC(GetDataTable, (ScriptContext::UI | ScriptContext::CLIENT | ScriptContext::SERVER)) -{ - const char* pAssetName; - g_pSquirrel<context>->getasset(sqvm, 2, &pAssetName); - - if (strncmp(pAssetName, "datatable/", 10)) - { - g_pSquirrel<context>->raiseerror(sqvm, fmt::format("Asset \"{}\" doesn't start with \"datatable/\"", pAssetName).c_str()); - return SQRESULT_ERROR; - } - else if (!Cvar_ns_prefer_datatable_from_disk->GetBool() && g_pPakLoadManager->LoadFile(pAssetName)) - return g_pSquirrel<context>->m_funcOriginals["GetDataTable"](sqvm); - // either we prefer disk datatables, or we're loading a datatable that wasn't found in rpak - else - { - std::string sAssetPath(fmt::format("scripts/{}", pAssetName)); - - // first, check the cache - if (CSVCache.find(pAssetName) != CSVCache.end()) - { - CSVData** pUserdata = g_pSquirrel<context>->template createuserdata<CSVData*>(sqvm, sizeof(CSVData*)); - g_pSquirrel<context>->setuserdatatypeid(sqvm, -1, USERDATA_TYPE_DATATABLE_CUSTOM); - *pUserdata = &CSVCache[pAssetName]; - - return SQRESULT_NOTNULL; - } - - // check files on disk - // we don't use .rpak as the extension for on-disk datatables, so we need to replace .rpak with .csv in the filename we're reading - fs::path diskAssetPath("scripts"); - if (fs::path(pAssetName).extension() == ".rpak") - diskAssetPath /= fs::path(pAssetName).remove_filename() / (fs::path(pAssetName).stem().string() + ".csv"); - else - diskAssetPath /= fs::path(pAssetName); - - std::string sDiskAssetPath(diskAssetPath.string()); - if ((*g_pFilesystem)->m_vtable2->FileExists(&(*g_pFilesystem)->m_vtable2, sDiskAssetPath.c_str(), "GAME")) - { - std::string sTableCSV = ReadVPKFile(sDiskAssetPath.c_str()); - if (!sTableCSV.size()) - { - g_pSquirrel<context>->raiseerror(sqvm, fmt::format("Datatable \"{}\" is empty", pAssetName).c_str()); - return SQRESULT_ERROR; - } - - // somewhat shit, but ensure we end with a newline to make parsing easier - if (sTableCSV[sTableCSV.length() - 1] != '\n') - sTableCSV += '\n'; - - CSVData csv; - csv.m_sAssetName = pAssetName; - csv.m_sCSVString = sTableCSV; - csv.m_nDataBufSize = sTableCSV.size(); - csv.m_pDataBuf = new char[csv.m_nDataBufSize]; - memcpy(csv.m_pDataBuf, &sTableCSV[0], csv.m_nDataBufSize); - - // parse the csv - // csvs are essentially comma and newline-deliniated sets of strings for parsing, only thing we need to worry about is quoted - // entries when we parse an element of the csv, rather than allocating an entry for it, we just convert that element to a - // null-terminated string i.e., store the ptr to the first char of it, then make the comma that delinates it a nullchar - - bool bHasColumns = false; - bool bInQuotes = false; - - std::vector<char*> vCurrentRow; - char* pElemStart = csv.m_pDataBuf; - char* pElemEnd = nullptr; - - for (int i = 0; i < csv.m_nDataBufSize; i++) - { - if (csv.m_pDataBuf[i] == '\r' && csv.m_pDataBuf[i + 1] == '\n') - { - if (!pElemEnd) - pElemEnd = csv.m_pDataBuf + i; - - continue; // next iteration can handle the \n - } - - // newline, end of a row - if (csv.m_pDataBuf[i] == '\n') - { - // shouldn't have newline in string - if (bInQuotes) - { - g_pSquirrel<context>->raiseerror(sqvm, "Unexpected \\n in string"); - return SQRESULT_ERROR; - } - - // push last entry to current row - if (pElemEnd) - *pElemEnd = '\0'; - else - csv.m_pDataBuf[i] = '\0'; - - vCurrentRow.push_back(pElemStart); - - // newline, push last line to csv data and go from there - if (!bHasColumns) - { - bHasColumns = true; - csv.columns = vCurrentRow; - } - else - csv.dataPointers.push_back(vCurrentRow); - - vCurrentRow.clear(); - // put start of current element at char after newline - pElemStart = csv.m_pDataBuf + i + 1; - pElemEnd = nullptr; - } - // we're starting or ending a quoted string - else if (csv.m_pDataBuf[i] == '"') - { - // start quoted string - if (!bInQuotes) - { - // shouldn't have quoted strings in column names - if (!bHasColumns) - { - g_pSquirrel<context>->raiseerror(sqvm, "Unexpected \" in column name"); - return SQRESULT_ERROR; - } - - bInQuotes = true; - // put start of current element at char after string begin - pElemStart = csv.m_pDataBuf + i + 1; - } - // end quoted string - else - { - pElemEnd = csv.m_pDataBuf + i; - bInQuotes = false; - } - } - // don't parse commas in quotes - else if (bInQuotes) - { - continue; - } - // comma, push new entry to current row - else if (csv.m_pDataBuf[i] == ',') - { - if (pElemEnd) - *pElemEnd = '\0'; - else - csv.m_pDataBuf[i] = '\0'; - - vCurrentRow.push_back(pElemStart); - // put start of next element at char after comma - pElemStart = csv.m_pDataBuf + i + 1; - pElemEnd = nullptr; - } - } - - // add to cache and return - CSVData** pUserdata = g_pSquirrel<context>->template createuserdata<CSVData*>(sqvm, sizeof(CSVData*)); - g_pSquirrel<context>->setuserdatatypeid(sqvm, -1, USERDATA_TYPE_DATATABLE_CUSTOM); - CSVCache[pAssetName] = csv; - *pUserdata = &CSVCache[pAssetName]; - - return SQRESULT_NOTNULL; - } - // the file doesn't exist on disk, check rpak if we haven't already - else if (Cvar_ns_prefer_datatable_from_disk->GetBool() && g_pPakLoadManager->LoadFile(pAssetName)) - return g_pSquirrel<context>->m_funcOriginals["GetDataTable"](sqvm); - // the file doesn't exist at all, error - else - { - g_pSquirrel<context>->raiseerror(sqvm, fmt::format("Datatable {} not found", pAssetName).c_str()); - return SQRESULT_ERROR; - } - } -} - -// int function GetDataTableColumnByName( var datatable, string columnName ) -REPLACE_SQFUNC(GetDataTableColumnByName, (ScriptContext::UI | ScriptContext::CLIENT | ScriptContext::SERVER)) -{ - CSVData** pData; - uint64_t typeId; - g_pSquirrel<context>->getuserdata(sqvm, 2, &pData, &typeId); - - if (typeId != USERDATA_TYPE_DATATABLE_CUSTOM) - return g_pSquirrel<context>->m_funcOriginals["GetDataTableColumnByName"](sqvm); - - CSVData* csv = *pData; - const char* pColumnName = g_pSquirrel<context>->getstring(sqvm, 2); - - for (int i = 0; i < csv->columns.size(); i++) - { - if (!strcmp(csv->columns[i], pColumnName)) - { - g_pSquirrel<context>->pushinteger(sqvm, i); - return SQRESULT_NOTNULL; - } - } - - // column not found - g_pSquirrel<context>->pushinteger(sqvm, -1); - return SQRESULT_NOTNULL; -} - -// int function GetDataTableRowCount( var datatable ) -REPLACE_SQFUNC(GetDataTableRowCount, (ScriptContext::UI | ScriptContext::CLIENT | ScriptContext::SERVER)) -{ - CSVData** pData; - uint64_t typeId; - g_pSquirrel<context>->getuserdata(sqvm, 2, &pData, &typeId); - - if (typeId != USERDATA_TYPE_DATATABLE_CUSTOM) - return g_pSquirrel<context>->m_funcOriginals["GetDatatableRowCount"](sqvm); - - CSVData* csv = *pData; - g_pSquirrel<context>->pushinteger(sqvm, csv->dataPointers.size()); - return SQRESULT_NOTNULL; -} - -// string function GetDataTableString( var datatable, int row, int col ) -REPLACE_SQFUNC(GetDataTableString, (ScriptContext::UI | ScriptContext::CLIENT | ScriptContext::SERVER)) -{ - CSVData** pData; - uint64_t typeId; - g_pSquirrel<context>->getuserdata(sqvm, 2, &pData, &typeId); - - if (typeId != USERDATA_TYPE_DATATABLE_CUSTOM) - return g_pSquirrel<context>->m_funcOriginals["GetDataTableString"](sqvm); - - CSVData* csv = *pData; - const int nRow = g_pSquirrel<context>->getinteger(sqvm, 2); - const int nCol = g_pSquirrel<context>->getinteger(sqvm, 3); - if (nRow >= csv->dataPointers.size() || nCol >= csv->dataPointers[nRow].size()) - { - g_pSquirrel<context>->raiseerror( - sqvm, - fmt::format( - "row {} and col {} are outside of range row {} and col {}", nRow, nCol, csv->dataPointers.size(), csv->columns.size()) - .c_str()); - return SQRESULT_ERROR; - } - - g_pSquirrel<context>->pushstring(sqvm, csv->dataPointers[nRow][nCol], -1); - return SQRESULT_NOTNULL; -} - -// asset function GetDataTableAsset( var datatable, int row, int col ) -REPLACE_SQFUNC(GetDataTableAsset, (ScriptContext::UI | ScriptContext::CLIENT | ScriptContext::SERVER)) -{ - CSVData** pData; - uint64_t typeId; - g_pSquirrel<context>->getuserdata(sqvm, 2, &pData, &typeId); - - if (typeId != USERDATA_TYPE_DATATABLE_CUSTOM) - return g_pSquirrel<context>->m_funcOriginals["GetDataTableAsset"](sqvm); - - CSVData* csv = *pData; - const int nRow = g_pSquirrel<context>->getinteger(sqvm, 2); - const int nCol = g_pSquirrel<context>->getinteger(sqvm, 3); - if (nRow >= csv->dataPointers.size() || nCol >= csv->dataPointers[nRow].size()) - { - g_pSquirrel<context>->raiseerror( - sqvm, - fmt::format( - "row {} and col {} are outside of range row {} and col {}", nRow, nCol, csv->dataPointers.size(), csv->columns.size()) - .c_str()); - return SQRESULT_ERROR; - } - - g_pSquirrel<context>->pushasset(sqvm, csv->dataPointers[nRow][nCol], -1); - return SQRESULT_NOTNULL; -} - -// int function GetDataTableInt( var datatable, int row, int col ) -REPLACE_SQFUNC(GetDataTableInt, (ScriptContext::UI | ScriptContext::CLIENT | ScriptContext::SERVER)) -{ - CSVData** pData; - uint64_t typeId; - g_pSquirrel<context>->getuserdata(sqvm, 2, &pData, &typeId); - - if (typeId != USERDATA_TYPE_DATATABLE_CUSTOM) - return g_pSquirrel<context>->m_funcOriginals["GetDataTableInt"](sqvm); - - CSVData* csv = *pData; - const int nRow = g_pSquirrel<context>->getinteger(sqvm, 2); - const int nCol = g_pSquirrel<context>->getinteger(sqvm, 3); - if (nRow >= csv->dataPointers.size() || nCol >= csv->dataPointers[nRow].size()) - { - g_pSquirrel<context>->raiseerror( - sqvm, - fmt::format( - "row {} and col {} are outside of range row {} and col {}", nRow, nCol, csv->dataPointers.size(), csv->columns.size()) - .c_str()); - return SQRESULT_ERROR; - } - - g_pSquirrel<context>->pushinteger(sqvm, std::stoi(csv->dataPointers[nRow][nCol])); - return SQRESULT_NOTNULL; -} - -// float function GetDataTableFloat( var datatable, int row, int col ) -REPLACE_SQFUNC(GetDataTableFloat, (ScriptContext::UI | ScriptContext::CLIENT | ScriptContext::SERVER)) -{ - CSVData** pData; - uint64_t typeId; - g_pSquirrel<context>->getuserdata(sqvm, 2, &pData, &typeId); - - if (typeId != USERDATA_TYPE_DATATABLE_CUSTOM) - return g_pSquirrel<context>->m_funcOriginals["GetDataTableFloat"](sqvm); - - CSVData* csv = *pData; - const int nRow = g_pSquirrel<context>->getinteger(sqvm, 2); - const int nCol = g_pSquirrel<context>->getinteger(sqvm, 3); - if (nRow >= csv->dataPointers.size() || nCol >= csv->dataPointers[nRow].size()) - { - g_pSquirrel<context>->raiseerror( - sqvm, - fmt::format( - "row {} and col {} are outside of range row {} and col {}", nRow, nCol, csv->dataPointers.size(), csv->columns.size()) - .c_str()); - return SQRESULT_ERROR; - } - - g_pSquirrel<context>->pushfloat(sqvm, std::stof(csv->dataPointers[nRow][nCol])); - return SQRESULT_NOTNULL; -} - -// bool function GetDataTableBool( var datatable, int row, int col ) -REPLACE_SQFUNC(GetDataTableBool, (ScriptContext::UI | ScriptContext::CLIENT | ScriptContext::SERVER)) -{ - CSVData** pData; - uint64_t typeId; - g_pSquirrel<context>->getuserdata(sqvm, 2, &pData, &typeId); - - if (typeId != USERDATA_TYPE_DATATABLE_CUSTOM) - return g_pSquirrel<context>->m_funcOriginals["GetDataTableBool"](sqvm); - - CSVData* csv = *pData; - const int nRow = g_pSquirrel<context>->getinteger(sqvm, 2); - const int nCol = g_pSquirrel<context>->getinteger(sqvm, 3); - if (nRow >= csv->dataPointers.size() || nCol >= csv->dataPointers[nRow].size()) - { - g_pSquirrel<context>->raiseerror( - sqvm, - fmt::format( - "row {} and col {} are outside of range row {} and col {}", nRow, nCol, csv->dataPointers.size(), csv->columns.size()) - .c_str()); - return SQRESULT_ERROR; - } - - g_pSquirrel<context>->pushbool(sqvm, std::stoi(csv->dataPointers[nRow][nCol])); - return SQRESULT_NOTNULL; -} - -// vector function GetDataTableVector( var datatable, int row, int col ) -REPLACE_SQFUNC(GetDataTableVector, (ScriptContext::UI | ScriptContext::CLIENT | ScriptContext::SERVER)) -{ - CSVData** pData; - uint64_t typeId; - g_pSquirrel<context>->getuserdata(sqvm, 2, &pData, &typeId); - - if (typeId != USERDATA_TYPE_DATATABLE_CUSTOM) - return g_pSquirrel<context>->m_funcOriginals["GetDataTableVector"](sqvm); - - CSVData* csv = *pData; - const int nRow = g_pSquirrel<context>->getinteger(sqvm, 2); - const int nCol = g_pSquirrel<context>->getinteger(sqvm, 3); - if (nRow >= csv->dataPointers.size() || nCol >= csv->dataPointers[nRow].size()) - { - g_pSquirrel<context>->raiseerror( - sqvm, - fmt::format( - "row {} and col {} are outside of range row {} and col {}", nRow, nCol, csv->dataPointers.size(), csv->columns.size()) - .c_str()); - return SQRESULT_ERROR; - } - - g_pSquirrel<context>->pushvector(sqvm, StringToVector(csv->dataPointers[nRow][nCol])); - return SQRESULT_NOTNULL; -} - -// int function GetDataTableRowMatchingStringValue( var datatable, int col, string value ) -REPLACE_SQFUNC(GetDataTableRowMatchingStringValue, (ScriptContext::UI | ScriptContext::CLIENT | ScriptContext::SERVER)) -{ - CSVData** pData; - uint64_t typeId; - g_pSquirrel<context>->getuserdata(sqvm, 2, &pData, &typeId); - - if (typeId != USERDATA_TYPE_DATATABLE_CUSTOM) - return g_pSquirrel<context>->m_funcOriginals["GetDataTableRowMatchingStringValue"](sqvm); - - CSVData* csv = *pData; - int nCol = g_pSquirrel<context>->getinteger(sqvm, 2); - const char* pStringVal = g_pSquirrel<context>->getstring(sqvm, 3); - for (int i = 0; i < csv->dataPointers.size(); i++) - { - if (!strcmp(csv->dataPointers[i][nCol], pStringVal)) - { - g_pSquirrel<context>->pushinteger(sqvm, i); - return SQRESULT_NOTNULL; - } - } - - g_pSquirrel<context>->pushinteger(sqvm, -1); - return SQRESULT_NOTNULL; -} - -// int function GetDataTableRowMatchingAssetValue( var datatable, int col, asset value ) -REPLACE_SQFUNC(GetDataTableMatchingAssetValue, (ScriptContext::UI | ScriptContext::CLIENT | ScriptContext::SERVER)) -{ - CSVData** pData; - uint64_t typeId; - g_pSquirrel<context>->getuserdata(sqvm, 2, &pData, &typeId); - - if (typeId != USERDATA_TYPE_DATATABLE_CUSTOM) - return g_pSquirrel<context>->m_funcOriginals["GetDataTableRowMatchingAssetValue"](sqvm); - - CSVData* csv = *pData; - int nCol = g_pSquirrel<context>->getinteger(sqvm, 2); - const char* pStringVal; - g_pSquirrel<context>->getasset(sqvm, 3, &pStringVal); - for (int i = 0; i < csv->dataPointers.size(); i++) - { - if (!strcmp(csv->dataPointers[i][nCol], pStringVal)) - { - g_pSquirrel<context>->pushinteger(sqvm, i); - return SQRESULT_NOTNULL; - } - } - - g_pSquirrel<context>->pushinteger(sqvm, -1); - return SQRESULT_NOTNULL; -} - -// int function GetDataTableRowMatchingFloatValue( var datatable, int col, float value ) -REPLACE_SQFUNC(GetDataTableRowMatchingFloatValue, (ScriptContext::UI | ScriptContext::CLIENT | ScriptContext::SERVER)) -{ - CSVData** pData; - uint64_t typeId; - g_pSquirrel<context>->getuserdata(sqvm, 2, &pData, &typeId); - - if (typeId != USERDATA_TYPE_DATATABLE_CUSTOM) - return g_pSquirrel<context>->m_funcOriginals["GetDataTableRowMatchingFloatValue"](sqvm); - - CSVData* csv = *pData; - int nCol = g_pSquirrel<context>->getinteger(sqvm, 2); - const float flFloatVal = g_pSquirrel<context>->getfloat(sqvm, 3); - for (int i = 0; i < csv->dataPointers.size(); i++) - { - if (flFloatVal == std::stof(csv->dataPointers[i][nCol])) - { - g_pSquirrel<context>->pushinteger(sqvm, i); - return SQRESULT_NOTNULL; - } - } - - g_pSquirrel<context>->pushinteger(sqvm, -1); - return SQRESULT_NOTNULL; -} - -// int function GetDataTableRowMatchingIntValue( var datatable, int col, int value ) -REPLACE_SQFUNC(GetDataTableRowMatchingIntValue, (ScriptContext::UI | ScriptContext::CLIENT | ScriptContext::SERVER)) -{ - CSVData** pData; - uint64_t typeId; - g_pSquirrel<context>->getuserdata(sqvm, 2, &pData, &typeId); - - if (typeId != USERDATA_TYPE_DATATABLE_CUSTOM) - return g_pSquirrel<context>->m_funcOriginals["GetDataTableRowMatchingIntValue"](sqvm); - - CSVData* csv = *pData; - int nCol = g_pSquirrel<context>->getinteger(sqvm, 2); - const int nIntVal = g_pSquirrel<context>->getinteger(sqvm, 3); - for (int i = 0; i < csv->dataPointers.size(); i++) - { - if (nIntVal == std::stoi(csv->dataPointers[i][nCol])) - { - g_pSquirrel<context>->pushinteger(sqvm, i); - return SQRESULT_NOTNULL; - } - } - - g_pSquirrel<context>->pushinteger(sqvm, -1); - return SQRESULT_NOTNULL; -} - -// int function GetDataTableRowMatchingVectorValue( var datatable, int col, vector value ) -REPLACE_SQFUNC(GetDataTableRowMatchingVectorValue, (ScriptContext::UI | ScriptContext::CLIENT | ScriptContext::SERVER)) -{ - CSVData** pData; - uint64_t typeId; - g_pSquirrel<context>->getuserdata(sqvm, 2, &pData, &typeId); - - if (typeId != USERDATA_TYPE_DATATABLE_CUSTOM) - return g_pSquirrel<context>->m_funcOriginals["GetDataTableRowMatchingVectorValue"](sqvm); - - CSVData* csv = *pData; - int nCol = g_pSquirrel<context>->getinteger(sqvm, 2); - const Vector3 vVectorVal = g_pSquirrel<context>->getvector(sqvm, 3); - - for (int i = 0; i < csv->dataPointers.size(); i++) - { - if (vVectorVal == StringToVector(csv->dataPointers[i][nCol])) - { - g_pSquirrel<context>->pushinteger(sqvm, i); - return SQRESULT_NOTNULL; - } - } - - g_pSquirrel<context>->pushinteger(sqvm, -1); - return SQRESULT_NOTNULL; -} - -// int function GetDataTableRowGreaterThanOrEqualToIntValue( var datatable, int col, int value ) -REPLACE_SQFUNC(GetDataTableRowGreaterThanOrEqualToIntValue, (ScriptContext::UI | ScriptContext::CLIENT | ScriptContext::SERVER)) -{ - CSVData** pData; - uint64_t typeId; - g_pSquirrel<context>->getuserdata(sqvm, 2, &pData, &typeId); - - if (typeId != USERDATA_TYPE_DATATABLE_CUSTOM) - return g_pSquirrel<context>->m_funcOriginals["GetDataTableRowGreaterThanOrEqualToIntValue"](sqvm); - - CSVData* csv = *pData; - int nCol = g_pSquirrel<context>->getinteger(sqvm, 2); - const int nIntVal = g_pSquirrel<context>->getinteger(sqvm, 3); - for (int i = 0; i < csv->dataPointers.size(); i++) - { - if (nIntVal >= std::stoi(csv->dataPointers[i][nCol])) - { - spdlog::info("datatable not loaded"); - g_pSquirrel<context>->pushinteger(sqvm, 1); - return SQRESULT_NOTNULL; - } - } - - g_pSquirrel<context>->pushinteger(sqvm, -1); - return SQRESULT_NOTNULL; -} - -// int function GetDataTableRowLessThanOrEqualToIntValue( var datatable, int col, int value ) -REPLACE_SQFUNC(GetDataTableRowLessThanOrEqualToIntValue, (ScriptContext::UI | ScriptContext::CLIENT | ScriptContext::SERVER)) -{ - CSVData** pData; - uint64_t typeId; - g_pSquirrel<context>->getuserdata(sqvm, 2, &pData, &typeId); - - if (typeId != USERDATA_TYPE_DATATABLE_CUSTOM) - return g_pSquirrel<context>->m_funcOriginals["GetDataTableRowLessThanOrEqualToIntValue"](sqvm); - - CSVData* csv = *pData; - int nCol = g_pSquirrel<context>->getinteger(sqvm, 2); - const int nIntVal = g_pSquirrel<context>->getinteger(sqvm, 3); - for (int i = 0; i < csv->dataPointers.size(); i++) - { - if (nIntVal <= std::stoi(csv->dataPointers[i][nCol])) - { - g_pSquirrel<context>->pushinteger(sqvm, i); - return SQRESULT_NOTNULL; - } - } - - g_pSquirrel<context>->pushinteger(sqvm, -1); - return SQRESULT_NOTNULL; -} - -// int function GetDataTableRowGreaterThanOrEqualToFloatValue( var datatable, int col, float value ) -REPLACE_SQFUNC(GetDataTableRowGreaterThanOrEqualToFloatValue, (ScriptContext::UI | ScriptContext::CLIENT | ScriptContext::SERVER)) -{ - CSVData** pData; - uint64_t typeId; - g_pSquirrel<context>->getuserdata(sqvm, 2, &pData, &typeId); - - if (typeId != USERDATA_TYPE_DATATABLE_CUSTOM) - return g_pSquirrel<context>->m_funcOriginals["GetDataTableRowGreaterThanOrEqualToFloatValue"](sqvm); - - CSVData* csv = *pData; - int nCol = g_pSquirrel<context>->getinteger(sqvm, 2); - const float flFloatVal = g_pSquirrel<context>->getfloat(sqvm, 3); - for (int i = 0; i < csv->dataPointers.size(); i++) - { - if (flFloatVal >= std::stof(csv->dataPointers[i][nCol])) - { - g_pSquirrel<context>->pushinteger(sqvm, i); - return SQRESULT_NOTNULL; - } - } - - g_pSquirrel<context>->pushinteger(sqvm, -1); - return SQRESULT_NOTNULL; -} - -// int function GetDataTableRowLessThanOrEqualToFloatValue( var datatable, int col, float value ) -REPLACE_SQFUNC(GetDataTableRowLessThanOrEqualToFloatValue, (ScriptContext::UI | ScriptContext::CLIENT | ScriptContext::SERVER)) -{ - CSVData** pData; - uint64_t typeId; - g_pSquirrel<context>->getuserdata(sqvm, 2, &pData, &typeId); - - if (typeId != USERDATA_TYPE_DATATABLE_CUSTOM) - return g_pSquirrel<context>->m_funcOriginals["GetDataTableRowLessThanOrEqualToFloatValue"](sqvm); - - CSVData* csv = *pData; - int nCol = g_pSquirrel<context>->getinteger(sqvm, 2); - const float flFloatVal = g_pSquirrel<context>->getfloat(sqvm, 3); - for (int i = 0; i < csv->dataPointers.size(); i++) - { - if (flFloatVal <= std::stof(csv->dataPointers[i][nCol])) - { - g_pSquirrel<context>->pushinteger(sqvm, i); - return SQRESULT_NOTNULL; - } - } - - g_pSquirrel<context>->pushinteger(sqvm, -1); - return SQRESULT_NOTNULL; -} - -std::string DataTableToString(Datatable* datatable) -{ - std::string sCSVString; - - // write columns - bool bShouldComma = false; - for (int i = 0; i < datatable->numColumns; i++) - { - if (bShouldComma) - sCSVString += ','; - else - bShouldComma = true; - - sCSVString += datatable->columnInfo[i].name; - } - - // write rows - for (int row = 0; row < datatable->numRows; row++) - { - sCSVString += '\n'; - - bool bShouldComma = false; - for (int col = 0; col < datatable->numColumns; col++) - { - if (bShouldComma) - sCSVString += ','; - else - bShouldComma = true; - - // output typed data - ColumnInfo column = datatable->columnInfo[col]; - const void* pUntypedVal = datatable->data + column.offset + row * datatable->rowInfo; - switch (column.type) - { - case DatatableType::BOOL: - { - sCSVString += *(bool*)pUntypedVal ? '1' : '0'; - break; - } - - case DatatableType::INT: - { - sCSVString += std::to_string(*(int*)pUntypedVal); - break; - } - - case DatatableType::FLOAT: - { - sCSVString += std::to_string(*(float*)pUntypedVal); - break; - } - - case DatatableType::VECTOR: - { - Vector3* pVector = (Vector3*)(pUntypedVal); - sCSVString += fmt::format("<{},{},{}>", pVector->x, pVector->y, pVector->z); - break; - } - - case DatatableType::STRING: - case DatatableType::ASSET: - case DatatableType::UNK_STRING: - { - sCSVString += fmt::format("\"{}\"", *(char**)pUntypedVal); - break; - } - } - } - } - - return sCSVString; -} - -void DumpDatatable(const char* pDatatablePath) -{ - Datatable* pDatatable = (Datatable*)g_pPakLoadManager->LoadFile(pDatatablePath); - if (!pDatatable) - { - spdlog::error("couldn't load datatable {} (rpak containing it may not be loaded?)", pDatatablePath); - return; - } - - std::string sOutputPath(fmt::format("{}/scripts/datatable/{}.csv", g_pModName, fs::path(pDatatablePath).stem().string())); - std::string sDatatableContents(DataTableToString(pDatatable)); - - fs::create_directories(fs::path(sOutputPath).remove_filename()); - std::ofstream outputStream(sOutputPath); - outputStream.write(sDatatableContents.c_str(), sDatatableContents.size()); - outputStream.close(); - - spdlog::info("dumped datatable {} {} to {}", pDatatablePath, (void*)pDatatable, sOutputPath); -} - -void ConCommand_dump_datatable(const CCommand& args) -{ - if (args.ArgC() < 2) - { - spdlog::info("usage: dump_datatable datatable/tablename.rpak"); - return; - } - - DumpDatatable(args.Arg(1)); -} - -void ConCommand_dump_datatables(const CCommand& args) -{ - // likely not a comprehensive list, might be missing a couple? - static const std::vector<const char*> VANILLA_DATATABLE_PATHS = { - "datatable/burn_meter_rewards.rpak", - "datatable/burn_meter_store.rpak", - "datatable/calling_cards.rpak", - "datatable/callsign_icons.rpak", - "datatable/camo_skins.rpak", - "datatable/default_pilot_loadouts.rpak", - "datatable/default_titan_loadouts.rpak", - "datatable/faction_leaders.rpak", - "datatable/fd_awards.rpak", - "datatable/features_mp.rpak", - "datatable/non_loadout_weapons.rpak", - "datatable/pilot_abilities.rpak", - "datatable/pilot_executions.rpak", - "datatable/pilot_passives.rpak", - "datatable/pilot_properties.rpak", - "datatable/pilot_weapons.rpak", - "datatable/pilot_weapon_features.rpak", - "datatable/pilot_weapon_mods.rpak", - "datatable/pilot_weapon_mods_common.rpak", - "datatable/playlist_items.rpak", - "datatable/titans_mp.rpak", - "datatable/titan_abilities.rpak", - "datatable/titan_executions.rpak", - "datatable/titan_fd_upgrades.rpak", - "datatable/titan_nose_art.rpak", - "datatable/titan_passives.rpak", - "datatable/titan_primary_mods.rpak", - "datatable/titan_primary_mods_common.rpak", - "datatable/titan_primary_weapons.rpak", - "datatable/titan_properties.rpak", - "datatable/titan_skins.rpak", - "datatable/titan_voices.rpak", - "datatable/unlocks_faction_level.rpak", - "datatable/unlocks_fd_titan_level.rpak", - "datatable/unlocks_player_level.rpak", - "datatable/unlocks_random.rpak", - "datatable/unlocks_titan_level.rpak", - "datatable/unlocks_weapon_level_pilot.rpak", - "datatable/weapon_skins.rpak", - "datatable/xp_per_faction_level.rpak", - "datatable/xp_per_fd_titan_level.rpak", - "datatable/xp_per_player_level.rpak", - "datatable/xp_per_titan_level.rpak", - "datatable/xp_per_weapon_level.rpak", - "datatable/faction_leaders_dropship_anims.rpak", - "datatable/score_events.rpak", - "datatable/startpoints.rpak", - "datatable/sp_levels.rpak", - "datatable/community_entries.rpak", - "datatable/spotlight_images.rpak", - "datatable/death_hints_mp.rpak", - "datatable/flightpath_assets.rpak", - "datatable/earn_meter_mp.rpak", - "datatable/battle_chatter_voices.rpak", - "datatable/battle_chatter.rpak", - "datatable/titan_os_conversations.rpak", - "datatable/faction_dialogue.rpak", - "datatable/grunt_chatter_mp.rpak", - "datatable/spectre_chatter_mp.rpak", - "datatable/pain_death_sounds.rpak", - "datatable/caller_ids_mp.rpak"}; - - for (const char* datatable : VANILLA_DATATABLE_PATHS) - DumpDatatable(datatable); -} - -ON_DLL_LOAD_RELIESON("server.dll", ServerScriptDatatables, ServerSquirrel, (CModule module)) -{ - SQ_GetDatatableInternal<ScriptContext::SERVER> = module.Offset(0x1250f0).RCast<Datatable* (*)(HSquirrelVM*)>(); -} - -ON_DLL_LOAD_RELIESON("client.dll", ClientScriptDatatables, ClientSquirrel, (CModule module)) -{ - SQ_GetDatatableInternal<ScriptContext::CLIENT> = module.Offset(0x1C9070).RCast<Datatable* (*)(HSquirrelVM*)>(); - SQ_GetDatatableInternal<ScriptContext::UI> = SQ_GetDatatableInternal<ScriptContext::CLIENT>; -} - -ON_DLL_LOAD_RELIESON("engine.dll", SharedScriptDataTables, ConVar, (CModule module)) -{ - Cvar_ns_prefer_datatable_from_disk = new ConVar( - "ns_prefer_datatable_from_disk", - IsDedicatedServer() && CommandLine()->CheckParm("-nopakdedi") ? "1" : "0", - FCVAR_NONE, - "whether to prefer loading datatables from disk, rather than rpak"); - - RegisterConCommand("dump_datatables", ConCommand_dump_datatables, "dumps all datatables from a hardcoded list", FCVAR_NONE); - RegisterConCommand("dump_datatable", ConCommand_dump_datatable, "dump a datatable", FCVAR_NONE); -} diff --git a/NorthstarDLL/scripts/scripthttprequesthandler.cpp b/NorthstarDLL/scripts/scripthttprequesthandler.cpp deleted file mode 100644 index aa75127a..00000000 --- a/NorthstarDLL/scripts/scripthttprequesthandler.cpp +++ /dev/null @@ -1,585 +0,0 @@ -#include "scripthttprequesthandler.h" -#include "util/version.h" -#include "squirrel/squirrel.h" -#include "core/tier0.h" - -HttpRequestHandler* g_httpRequestHandler; - -bool IsHttpDisabled() -{ - const static bool bIsHttpDisabled = CommandLine()->FindParm("-disablehttprequests"); - return bIsHttpDisabled; -} - -bool IsLocalHttpAllowed() -{ - const static bool bIsLocalHttpAllowed = CommandLine()->FindParm("-allowlocalhttp"); - return bIsLocalHttpAllowed; -} - -bool DisableHttpSsl() -{ - const static bool bDisableHttpSsl = CommandLine()->FindParm("-disablehttpssl"); - return bDisableHttpSsl; -} - -HttpRequestHandler::HttpRequestHandler() -{ - // Cache the launch parameters as early as possible in order to avoid possible exploits that change them at runtime. - IsHttpDisabled(); - IsLocalHttpAllowed(); - DisableHttpSsl(); -} - -void HttpRequestHandler::StartHttpRequestHandler() -{ - if (IsRunning()) - { - spdlog::warn("%s was called while IsRunning() is true!", __FUNCTION__); - return; - } - - m_bIsHttpRequestHandlerRunning = true; - spdlog::info("HttpRequestHandler started."); -} - -void HttpRequestHandler::StopHttpRequestHandler() -{ - if (!IsRunning()) - { - spdlog::warn("%s was called while IsRunning() is false", __FUNCTION__); - return; - } - - m_bIsHttpRequestHandlerRunning = false; - spdlog::info("HttpRequestHandler stopped."); -} - -bool IsHttpDestinationHostAllowed(const std::string& host, std::string& outHostname, std::string& outAddress, std::string& outPort) -{ - CURLU* url = curl_url(); - if (!url) - { - spdlog::error("Failed to call curl_url() for http request."); - return false; - } - - if (curl_url_set(url, CURLUPART_URL, host.c_str(), CURLU_DEFAULT_SCHEME) != CURLUE_OK) - { - spdlog::error("Failed to parse destination URL for http request."); - - curl_url_cleanup(url); - return false; - } - - char* urlHostname = nullptr; - if (curl_url_get(url, CURLUPART_HOST, &urlHostname, 0) != CURLUE_OK) - { - spdlog::error("Failed to parse hostname from destination URL for http request."); - - curl_url_cleanup(url); - return false; - } - - char* urlScheme = nullptr; - if (curl_url_get(url, CURLUPART_SCHEME, &urlScheme, CURLU_DEFAULT_SCHEME) != CURLUE_OK) - { - spdlog::error("Failed to parse scheme from destination URL for http request."); - - curl_url_cleanup(url); - curl_free(urlHostname); - return false; - } - - char* urlPort = nullptr; - if (curl_url_get(url, CURLUPART_PORT, &urlPort, CURLU_DEFAULT_PORT) != CURLUE_OK) - { - spdlog::error("Failed to parse port from destination URL for http request."); - - curl_url_cleanup(url); - curl_free(urlHostname); - curl_free(urlScheme); - return false; - } - - // Resolve the hostname into an address. - addrinfo* result; - addrinfo hints; - std::memset(&hints, 0, sizeof(addrinfo)); - hints.ai_family = AF_UNSPEC; - - if (getaddrinfo(urlHostname, urlScheme, &hints, &result) != 0) - { - spdlog::error("Failed to resolve http request destination {} using getaddrinfo().", urlHostname); - - curl_url_cleanup(url); - curl_free(urlHostname); - curl_free(urlScheme); - curl_free(urlPort); - return false; - } - - bool bFoundIPv6 = false; - sockaddr_in* sockaddr_ipv4 = nullptr; - for (addrinfo* info = result; info; info = info->ai_next) - { - if (info->ai_family == AF_INET) - { - sockaddr_ipv4 = (sockaddr_in*)info->ai_addr; - break; - } - - bFoundIPv6 = bFoundIPv6 || info->ai_family == AF_INET6; - } - - if (sockaddr_ipv4 == nullptr) - { - if (bFoundIPv6) - { - spdlog::error("Only IPv4 destinations are supported for HTTP requests. To allow IPv6, launch the game using -allowlocalhttp."); - } - else - { - spdlog::error("Failed to resolve http request destination {} into a valid IPv4 address.", urlHostname); - } - - curl_free(urlHostname); - curl_free(urlScheme); - curl_free(urlPort); - curl_url_cleanup(url); - - return false; - } - - // Fast checks for private ranges of IPv4. - // clang-format off - { - auto addrBytes = sockaddr_ipv4->sin_addr.S_un.S_un_b; - - if (addrBytes.s_b1 == 10 // 10.0.0.0 - 10.255.255.255 (Class A Private) - || addrBytes.s_b1 == 172 && addrBytes.s_b2 >= 16 && addrBytes.s_b2 <= 31 // 172.16.0.0 - 172.31.255.255 (Class B Private) - || addrBytes.s_b1 == 192 && addrBytes.s_b2 == 168 // 192.168.0.0 - 192.168.255.255 (Class C Private) - || addrBytes.s_b1 == 192 && addrBytes.s_b2 == 0 && addrBytes.s_b3 == 0 // 192.0.0.0 - 192.0.0.255 (IETF Assignment) - || addrBytes.s_b1 == 192 && addrBytes.s_b2 == 0 && addrBytes.s_b3 == 2 // 192.0.2.0 - 192.0.2.255 (TEST-NET-1) - || addrBytes.s_b1 == 192 && addrBytes.s_b2 == 88 && addrBytes.s_b3 == 99 // 192.88.99.0 - 192.88.99.255 (IPv4-IPv6 Relay) - || addrBytes.s_b1 == 192 && addrBytes.s_b2 >= 18 && addrBytes.s_b2 <= 19 // 192.18.0.0 - 192.19.255.255 (Internet Benchmark) - || addrBytes.s_b1 == 192 && addrBytes.s_b2 == 51 && addrBytes.s_b3 == 100 // 192.51.100.0 - 192.51.100.255 (TEST-NET-2) - || addrBytes.s_b1 == 203 && addrBytes.s_b2 == 0 && addrBytes.s_b3 == 113 // 203.0.113.0 - 203.0.113.255 (TEST-NET-3) - || addrBytes.s_b1 == 169 && addrBytes.s_b2 == 254 // 169.254.00 - 169.254.255.255 (Link-local/APIPA) - || addrBytes.s_b1 == 127 // 127.0.0.0 - 127.255.255.255 (Loopback) - || addrBytes.s_b1 == 0 // 0.0.0.0 - 0.255.255.255 (Current network) - || addrBytes.s_b1 == 100 && addrBytes.s_b2 >= 64 && addrBytes.s_b2 <= 127 // 100.64.0.0 - 100.127.255.255 (Shared address space) - || sockaddr_ipv4->sin_addr.S_un.S_addr == 0xFFFFFFFF // 255.255.255.255 (Broadcast) - || addrBytes.s_b1 >= 224 && addrBytes.s_b2 <= 239 // 224.0.0.0 - 239.255.255.255 (Multicast) - || addrBytes.s_b1 == 233 && addrBytes.s_b2 == 252 && addrBytes.s_b3 == 0 // 233.252.0.0 - 233.252.0.255 (MCAST-TEST-NET) - || addrBytes.s_b1 >= 240 && addrBytes.s_b4 <= 254) // 240.0.0.0 - 255.255.255.254 (Future Use Class E) - { - curl_free(urlHostname); - curl_free(urlScheme); - curl_free(urlPort); - curl_url_cleanup(url); - - return false; - } - } - - // clang-format on - - char resolvedStr[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &sockaddr_ipv4->sin_addr, resolvedStr, INET_ADDRSTRLEN); - - // Use the resolved address as the new request host. - outHostname = urlHostname; - outAddress = resolvedStr; - outPort = urlPort; - - freeaddrinfo(result); - - curl_free(urlHostname); - curl_free(urlScheme); - curl_free(urlPort); - curl_url_cleanup(url); - - return true; -} - -size_t HttpCurlWriteToStringBufferCallback(char* contents, size_t size, size_t nmemb, void* userp) -{ - ((std::string*)userp)->append((char*)contents, size * nmemb); - return size * nmemb; -} - -template <ScriptContext context> int HttpRequestHandler::MakeHttpRequest(const HttpRequest& requestParameters) -{ - if (!IsRunning()) - { - spdlog::warn("%s was called while IsRunning() is false!", __FUNCTION__); - return -1; - } - - if (IsHttpDisabled()) - { - spdlog::warn("NS_InternalMakeHttpRequest called while the game is running with -disablehttprequests." - " Please check if requests are allowed using NSIsHttpEnabled() first."); - return -1; - } - - bool bAllowLocalHttp = IsLocalHttpAllowed(); - - // This handle will be returned to Squirrel so it can wait for the response and assign a callback for it. - int handle = ++m_iLastRequestHandle; - - std::thread requestThread( - [this, handle, requestParameters, bAllowLocalHttp]() - { - std::string hostname, resolvedAddress, resolvedPort; - - if (!bAllowLocalHttp) - { - if (!IsHttpDestinationHostAllowed(requestParameters.baseUrl, hostname, resolvedAddress, resolvedPort)) - { - spdlog::warn( - "HttpRequestHandler::MakeHttpRequest attempted to make a request to a private network. This is only allowed when " - "running the game with -allowlocalhttp."); - g_pSquirrel<context>->AsyncCall( - "NSHandleFailedHttpRequest", - handle, - (int)0, - "Cannot make HTTP requests to private network hosts without -allowlocalhttp. Check your console for more " - "information."); - return; - } - } - - CURL* curl = curl_easy_init(); - if (!curl) - { - spdlog::error("HttpRequestHandler::MakeHttpRequest failed to init libcurl for request."); - g_pSquirrel<context>->AsyncCall( - "NSHandleFailedHttpRequest", handle, static_cast<int>(CURLE_FAILED_INIT), curl_easy_strerror(CURLE_FAILED_INIT)); - return; - } - - // HEAD has no body. - if (requestParameters.method == HttpRequestMethod::HRM_HEAD) - { - curl_easy_setopt(curl, CURLOPT_NOBODY, 1L); - } - - curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, HttpRequestMethod::ToString(requestParameters.method).c_str()); - - // Only resolve to IPv4 if we don't allow private network requests. - curl_slist* host = nullptr; - if (!bAllowLocalHttp) - { - curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); - host = curl_slist_append(host, fmt::format("{}:{}:{}", hostname, resolvedPort, resolvedAddress).c_str()); - curl_easy_setopt(curl, CURLOPT_RESOLVE, host); - } - - // Ensure we only allow HTTP or HTTPS. - curl_easy_setopt(curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS); - - // Allow redirects - curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); - curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 3L); - - // Check if the url already contains a query. - // If so, we'll know to append with & instead of start with ? - std::string queryUrl = requestParameters.baseUrl; - bool bUrlContainsQuery = false; - - // If this fails, just ignore the parsing and trust what the user wants to query. - // Probably will fail but handling it here would be annoying. - CURLU* curlUrl = curl_url(); - if (curlUrl) - { - if (curl_url_set(curlUrl, CURLUPART_URL, queryUrl.c_str(), CURLU_DEFAULT_SCHEME) == CURLUE_OK) - { - char* currentQuery; - if (curl_url_get(curlUrl, CURLUPART_QUERY, ¤tQuery, 0) == CURLUE_OK) - { - if (currentQuery && std::strlen(currentQuery) != 0) - { - bUrlContainsQuery = true; - } - } - - curl_free(currentQuery); - } - - curl_url_cleanup(curlUrl); - } - - // GET requests, or POST-like requests with an empty body, can have query parameters. - // Append them to the base url. - if (HttpRequestMethod::CanHaveQueryParameters(requestParameters.method) && - !HttpRequestMethod::UsesCurlPostOptions(requestParameters.method) || - requestParameters.body.empty()) - { - bool isFirstValue = true; - for (const auto& kv : requestParameters.queryParameters) - { - char* key = curl_easy_escape(curl, kv.first.c_str(), kv.first.length()); - - for (const std::string& queryValue : kv.second) - { - char* value = curl_easy_escape(curl, queryValue.c_str(), queryValue.length()); - - if (isFirstValue && !bUrlContainsQuery) - { - queryUrl.append(fmt::format("?{}={}", key, value)); - isFirstValue = false; - } - else - { - queryUrl.append(fmt::format("&{}={}", key, value)); - } - - curl_free(value); - } - - curl_free(key); - } - } - - // If this method uses POST-like curl options, set those and set the body. - // The body won't be sent if it's empty anyway, meaning the query parameters above, if any, would be. - if (HttpRequestMethod::UsesCurlPostOptions(requestParameters.method)) - { - // Grab the body and set it as a POST field - curl_easy_setopt(curl, CURLOPT_POST, 1L); - - curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, requestParameters.body.length()); - curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, requestParameters.body.c_str()); - } - - // Set the full URL for this http request. - curl_easy_setopt(curl, CURLOPT_URL, queryUrl.c_str()); - - std::string bodyBuffer; - std::string headerBuffer; - - // Set up buffers to write the response headers and body. - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HttpCurlWriteToStringBufferCallback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &bodyBuffer); - curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, HttpCurlWriteToStringBufferCallback); - curl_easy_setopt(curl, CURLOPT_HEADERDATA, &headerBuffer); - - // Add all the headers for the request. - curl_slist* headers = nullptr; - - // Content-Type header for POST-like requests. - if (HttpRequestMethod::UsesCurlPostOptions(requestParameters.method) && !requestParameters.body.empty()) - { - headers = curl_slist_append(headers, fmt::format("Content-Type: {}", requestParameters.contentType).c_str()); - } - - for (const auto& kv : requestParameters.headers) - { - for (const std::string& headerValue : kv.second) - { - headers = curl_slist_append(headers, fmt::format("{}: {}", kv.first, headerValue).c_str()); - } - } - - if (headers != nullptr) - { - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); - } - - // Disable SSL checks if requested by the user. - if (DisableHttpSsl()) - { - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 0L); - } - - // Enforce the Northstar user agent, unless an override was specified. - if (requestParameters.userAgent.empty()) - { - curl_easy_setopt(curl, CURLOPT_USERAGENT, &NSUserAgent); - } - else - { - curl_easy_setopt(curl, CURLOPT_USERAGENT, requestParameters.userAgent.c_str()); - } - - // Set the timeout for this request. Max 60 seconds so mods can't just spin up native threads all the time. - curl_easy_setopt(curl, CURLOPT_TIMEOUT, std::clamp<long>(requestParameters.timeout, 1, 60)); - - CURLcode result = curl_easy_perform(curl); - if (IsRunning()) - { - if (result == CURLE_OK) - { - // While the curl request is OK, it could return a non success code. - // Squirrel side will handle firing the correct callback. - long httpCode = 0; - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode); - g_pSquirrel<context>->AsyncCall( - "NSHandleSuccessfulHttpRequest", handle, static_cast<int>(httpCode), bodyBuffer, headerBuffer); - } - else - { - // Pass CURL result code & error. - spdlog::error( - "curl_easy_perform() failed with code {}, error: {}", static_cast<int>(result), curl_easy_strerror(result)); - - // If it's an SSL issue, tell the user they may disable SSL checks using -disablehttpssl. - if (result == CURLE_PEER_FAILED_VERIFICATION || result == CURLE_SSL_CERTPROBLEM || - result == CURLE_SSL_INVALIDCERTSTATUS) - { - spdlog::error("You can try disabling SSL verifications for this issue using the -disablehttpssl launch argument. " - "Keep in mind this is potentially dangerous!"); - } - - g_pSquirrel<context>->AsyncCall( - "NSHandleFailedHttpRequest", handle, static_cast<int>(result), curl_easy_strerror(result)); - } - } - - curl_easy_cleanup(curl); - curl_slist_free_all(headers); - curl_slist_free_all(host); - }); - - requestThread.detach(); - return handle; -} - -// int NS_InternalMakeHttpRequest(int method, string baseUrl, table<string, string> headers, table<string, string> queryParams, -// string contentType, string body, int timeout, string userAgent) -template <ScriptContext context> SQRESULT SQ_InternalMakeHttpRequest(HSquirrelVM* sqvm) -{ - if (!g_httpRequestHandler || !g_httpRequestHandler->IsRunning()) - { - spdlog::warn("NS_InternalMakeHttpRequest called while the http request handler isn't running."); - g_pSquirrel<context>->pushinteger(sqvm, -1); - return SQRESULT_NOTNULL; - } - - if (IsHttpDisabled()) - { - spdlog::warn("NS_InternalMakeHttpRequest called while the game is running with -disablehttprequests." - " Please check if requests are allowed using NSIsHttpEnabled() first."); - g_pSquirrel<context>->pushinteger(sqvm, -1); - return SQRESULT_NOTNULL; - } - - HttpRequest request; - request.method = static_cast<HttpRequestMethod::Type>(g_pSquirrel<context>->getinteger(sqvm, 1)); - request.baseUrl = g_pSquirrel<context>->getstring(sqvm, 2); - - // Read the tables for headers and query parameters. - SQTable* headerTable = sqvm->_stackOfCurrentFunction[3]._VAL.asTable; - for (int idx = 0; idx < headerTable->_numOfNodes; ++idx) - { - tableNode* node = &headerTable->_nodes[idx]; - - if (node->key._Type == OT_STRING && node->val._Type == OT_ARRAY) - { - SQArray* valueArray = node->val._VAL.asArray; - std::vector<std::string> headerValues; - - for (int vIdx = 0; vIdx < valueArray->_usedSlots; ++vIdx) - { - if (valueArray->_values[vIdx]._Type == OT_STRING) - { - headerValues.push_back(valueArray->_values[vIdx]._VAL.asString->_val); - } - } - - request.headers[node->key._VAL.asString->_val] = headerValues; - } - } - - SQTable* queryTable = sqvm->_stackOfCurrentFunction[4]._VAL.asTable; - for (int idx = 0; idx < queryTable->_numOfNodes; ++idx) - { - tableNode* node = &queryTable->_nodes[idx]; - - if (node->key._Type == OT_STRING && node->val._Type == OT_ARRAY) - { - SQArray* valueArray = node->val._VAL.asArray; - std::vector<std::string> queryValues; - - for (int vIdx = 0; vIdx < valueArray->_usedSlots; ++vIdx) - { - if (valueArray->_values[vIdx]._Type == OT_STRING) - { - queryValues.push_back(valueArray->_values[vIdx]._VAL.asString->_val); - } - } - - request.queryParameters[node->key._VAL.asString->_val] = queryValues; - } - } - - request.contentType = g_pSquirrel<context>->getstring(sqvm, 5); - request.body = g_pSquirrel<context>->getstring(sqvm, 6); - request.timeout = g_pSquirrel<context>->getinteger(sqvm, 7); - request.userAgent = g_pSquirrel<context>->getstring(sqvm, 8); - - int handle = g_httpRequestHandler->MakeHttpRequest<context>(request); - g_pSquirrel<context>->pushinteger(sqvm, handle); - return SQRESULT_NOTNULL; -} - -// bool NSIsHttpEnabled() -template <ScriptContext context> SQRESULT SQ_IsHttpEnabled(HSquirrelVM* sqvm) -{ - g_pSquirrel<context>->pushbool(sqvm, !IsHttpDisabled()); - return SQRESULT_NOTNULL; -} - -// bool NSIsLocalHttpAllowed() -template <ScriptContext context> SQRESULT SQ_IsLocalHttpAllowed(HSquirrelVM* sqvm) -{ - g_pSquirrel<context>->pushbool(sqvm, IsLocalHttpAllowed()); - return SQRESULT_NOTNULL; -} - -template <ScriptContext context> void HttpRequestHandler::RegisterSQFuncs() -{ - g_pSquirrel<context>->AddFuncRegistration( - "int", - "NS_InternalMakeHttpRequest", - "int method, string baseUrl, table<string, array<string> > headers, table<string, array<string> > queryParams, string contentType, " - "string body, " - "int timeout, string userAgent", - "[Internal use only] Passes the HttpRequest struct fields to be reconstructed in native and used for an http request", - SQ_InternalMakeHttpRequest<context>); - - g_pSquirrel<context>->AddFuncRegistration( - "bool", - "NSIsHttpEnabled", - "", - "Whether or not HTTP requests are enabled. You can opt-out by starting the game with -disablehttprequests.", - SQ_IsHttpEnabled<context>); - - g_pSquirrel<context>->AddFuncRegistration( - "bool", - "NSIsLocalHttpAllowed", - "", - "Whether or not HTTP requests can be made to a private network address. You can enable this by starting the game with " - "-allowlocalhttp.", - SQ_IsLocalHttpAllowed<context>); -} - -ON_DLL_LOAD_RELIESON("client.dll", HttpRequestHandler_ClientInit, ClientSquirrel, (CModule module)) -{ - g_httpRequestHandler->RegisterSQFuncs<ScriptContext::CLIENT>(); - g_httpRequestHandler->RegisterSQFuncs<ScriptContext::UI>(); -} - -ON_DLL_LOAD_RELIESON("server.dll", HttpRequestHandler_ServerInit, ServerSquirrel, (CModule module)) -{ - g_httpRequestHandler->RegisterSQFuncs<ScriptContext::SERVER>(); -} - -ON_DLL_LOAD("engine.dll", HttpRequestHandler_Init, (CModule module)) -{ - g_httpRequestHandler = new HttpRequestHandler; - g_httpRequestHandler->StartHttpRequestHandler(); -} diff --git a/NorthstarDLL/scripts/scripthttprequesthandler.h b/NorthstarDLL/scripts/scripthttprequesthandler.h deleted file mode 100644 index f3921f4e..00000000 --- a/NorthstarDLL/scripts/scripthttprequesthandler.h +++ /dev/null @@ -1,130 +0,0 @@ -#pragma once - -enum class ScriptContext; - -// These definitions below should match on the Squirrel side so we can easily pass them along through a function. - -/** - * Allowed methods for an HttpRequest. - */ -namespace HttpRequestMethod -{ - enum Type - { - HRM_GET = 0, - HRM_POST = 1, - HRM_HEAD = 2, - HRM_PUT = 3, - HRM_DELETE = 4, - HRM_PATCH = 5, - HRM_OPTIONS = 6, - }; - - /** Returns the HTTP string representation of the given method. */ - inline std::string ToString(HttpRequestMethod::Type method) - { - switch (method) - { - case HttpRequestMethod::HRM_GET: - return "GET"; - case HttpRequestMethod::HRM_POST: - return "POST"; - case HttpRequestMethod::HRM_HEAD: - return "HEAD"; - case HttpRequestMethod::HRM_PUT: - return "PUT"; - case HttpRequestMethod::HRM_DELETE: - return "DELETE"; - case HttpRequestMethod::HRM_PATCH: - return "PATCH"; - case HttpRequestMethod::HRM_OPTIONS: - return "OPTIONS"; - default: - return "INVALID"; - } - } - - /** Whether or not the given method should be treated like a POST for curlopts. */ - bool UsesCurlPostOptions(HttpRequestMethod::Type method) - { - switch (method) - { - case HttpRequestMethod::HRM_POST: - case HttpRequestMethod::HRM_PUT: - case HttpRequestMethod::HRM_DELETE: - case HttpRequestMethod::HRM_PATCH: - return true; - default: - return false; - } - } - - /** Whether or not the given http request method can have query parameters in the URL. */ - bool CanHaveQueryParameters(HttpRequestMethod::Type method) - { - return method == HttpRequestMethod::HRM_GET || UsesCurlPostOptions(method); - } -}; // namespace HttpRequestMethod - -/** Contains data about an http request that has been queued. */ -struct HttpRequest -{ - /** Method used for this http request. */ - HttpRequestMethod::Type method; - - /** Base URL of this http request. */ - std::string baseUrl; - - /** Headers used for this http request. Some may get overridden or ignored. */ - std::unordered_map<std::string, std::vector<std::string>> headers; - - /** Query parameters for this http request. */ - std::unordered_map<std::string, std::vector<std::string>> queryParameters; - - /** The content type of this http request. Defaults to text/plain & UTF-8 charset. */ - std::string contentType = "text/plain; charset=utf-8"; - - /** The body of this http request. If set, will override queryParameters.*/ - std::string body; - - /** The timeout for the http request, in seconds. Must be between 1 and 60. */ - int timeout; - - /** If set, the override to use for the User-Agent header. */ - std::string userAgent; -}; - -/** - * Handles making HTTP requests and sending the responses back to Squirrel. - */ -class HttpRequestHandler -{ -public: - HttpRequestHandler(); - - // Start/Stop the HTTP request handler. Right now this doesn't do much. - void StartHttpRequestHandler(); - void StopHttpRequestHandler(); - - // Whether or not this http request handler is currently running. - bool IsRunning() const - { - return m_bIsHttpRequestHandlerRunning; - } - - /** - * Creates a new thread to execute an HTTP request. - * @param requestParameters The parameters to use for this http request. - * @returns The handle for the http request being sent, or -1 if the request failed. - */ - template <ScriptContext context> int MakeHttpRequest(const HttpRequest& requestParameters); - - /** Registers the HTTP request Squirrel functions for the given script context. */ - template <ScriptContext context> void RegisterSQFuncs(); - -private: - int m_iLastRequestHandle = 0; - std::atomic_bool m_bIsHttpRequestHandlerRunning = false; -}; - -extern HttpRequestHandler* g_httpRequestHandler; diff --git a/NorthstarDLL/scripts/scriptjson.cpp b/NorthstarDLL/scripts/scriptjson.cpp deleted file mode 100644 index 06bda6f4..00000000 --- a/NorthstarDLL/scripts/scriptjson.cpp +++ /dev/null @@ -1,250 +0,0 @@ -#include "squirrel/squirrel.h" - -#include "rapidjson/error/en.h" -#include "rapidjson/document.h" -#include "rapidjson/writer.h" -#include "rapidjson/stringbuffer.h" - -#ifdef _MSC_VER -#undef GetObject // fuck microsoft developers -#endif - -template <ScriptContext context> void -DecodeJsonArray(HSquirrelVM* sqvm, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* arr) -{ - g_pSquirrel<context>->newarray(sqvm, 0); - - for (auto& itr : arr->GetArray()) - { - switch (itr.GetType()) - { - case rapidjson::kObjectType: - DecodeJsonTable<context>(sqvm, &itr); - g_pSquirrel<context>->arrayappend(sqvm, -2); - break; - case rapidjson::kArrayType: - DecodeJsonArray<context>(sqvm, &itr); - g_pSquirrel<context>->arrayappend(sqvm, -2); - break; - case rapidjson::kStringType: - g_pSquirrel<context>->pushstring(sqvm, itr.GetString(), -1); - g_pSquirrel<context>->arrayappend(sqvm, -2); - break; - case rapidjson::kTrueType: - case rapidjson::kFalseType: - g_pSquirrel<context>->pushbool(sqvm, itr.GetBool()); - g_pSquirrel<context>->arrayappend(sqvm, -2); - break; - case rapidjson::kNumberType: - if (itr.IsDouble() || itr.IsFloat()) - g_pSquirrel<context>->pushfloat(sqvm, itr.GetFloat()); - else - g_pSquirrel<context>->pushinteger(sqvm, itr.GetInt()); - g_pSquirrel<context>->arrayappend(sqvm, -2); - break; - } - } -} - -template <ScriptContext context> void -DecodeJsonTable(HSquirrelVM* sqvm, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* obj) -{ - g_pSquirrel<context>->newtable(sqvm); - - for (auto itr = obj->MemberBegin(); itr != obj->MemberEnd(); itr++) - { - switch (itr->value.GetType()) - { - case rapidjson::kObjectType: - g_pSquirrel<context>->pushstring(sqvm, itr->name.GetString(), -1); - DecodeJsonTable<context>( - sqvm, (rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>*)&itr->value); - g_pSquirrel<context>->newslot(sqvm, -3, false); - break; - case rapidjson::kArrayType: - g_pSquirrel<context>->pushstring(sqvm, itr->name.GetString(), -1); - DecodeJsonArray<context>( - sqvm, (rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>*)&itr->value); - g_pSquirrel<context>->newslot(sqvm, -3, false); - break; - case rapidjson::kStringType: - g_pSquirrel<context>->pushstring(sqvm, itr->name.GetString(), -1); - g_pSquirrel<context>->pushstring(sqvm, itr->value.GetString(), -1); - - g_pSquirrel<context>->newslot(sqvm, -3, false); - break; - case rapidjson::kTrueType: - case rapidjson::kFalseType: - g_pSquirrel<context>->pushstring(sqvm, itr->name.GetString(), -1); - g_pSquirrel<context>->pushbool(sqvm, itr->value.GetBool()); - g_pSquirrel<context>->newslot(sqvm, -3, false); - break; - case rapidjson::kNumberType: - if (itr->value.IsDouble() || itr->value.IsFloat()) - { - g_pSquirrel<context>->pushstring(sqvm, itr->name.GetString(), -1); - g_pSquirrel<context>->pushfloat(sqvm, itr->value.GetFloat()); - } - else - { - g_pSquirrel<context>->pushstring(sqvm, itr->name.GetString(), -1); - g_pSquirrel<context>->pushinteger(sqvm, itr->value.GetInt()); - } - g_pSquirrel<context>->newslot(sqvm, -3, false); - break; - } - } -} - -template <ScriptContext context> void EncodeJSONTable( - SQTable* table, - rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* obj, - rapidjson::MemoryPoolAllocator<SourceAllocator>& allocator) -{ - for (int i = 0; i < table->_numOfNodes; i++) - { - tableNode* node = &table->_nodes[i]; - if (node->key._Type == OT_STRING) - { - rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>> newObj(rapidjson::kObjectType); - rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>> newArray(rapidjson::kArrayType); - - switch (node->val._Type) - { - case OT_STRING: - obj->AddMember( - rapidjson::StringRef(node->key._VAL.asString->_val), rapidjson::StringRef(node->val._VAL.asString->_val), allocator); - break; - case OT_INTEGER: - obj->AddMember(rapidjson::StringRef(node->key._VAL.asString->_val), node->val._VAL.asInteger, allocator); - break; - case OT_FLOAT: - obj->AddMember(rapidjson::StringRef(node->key._VAL.asString->_val), node->val._VAL.asFloat, allocator); - break; - case OT_BOOL: - if (node->val._VAL.asInteger) - { - obj->AddMember(rapidjson::StringRef(node->key._VAL.asString->_val), true, allocator); - } - else - { - obj->AddMember(rapidjson::StringRef(node->key._VAL.asString->_val), false, allocator); - } - break; - case OT_TABLE: - EncodeJSONTable<context>(node->val._VAL.asTable, &newObj, allocator); - obj->AddMember(rapidjson::StringRef(node->key._VAL.asString->_val), newObj, allocator); - break; - case OT_ARRAY: - EncodeJSONArray<context>(node->val._VAL.asArray, &newArray, allocator); - obj->AddMember(rapidjson::StringRef(node->key._VAL.asString->_val), newArray, allocator); - break; - default: - spdlog::warn("SQ_EncodeJSON: squirrel type {} not supported", SQTypeNameFromID(node->val._Type)); - break; - } - } - } -} - -template <ScriptContext context> void EncodeJSONArray( - SQArray* arr, - rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* obj, - rapidjson::MemoryPoolAllocator<SourceAllocator>& allocator) -{ - for (int i = 0; i < arr->_usedSlots; i++) - { - SQObject* node = &arr->_values[i]; - - rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>> newObj(rapidjson::kObjectType); - rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>> newArray(rapidjson::kArrayType); - - switch (node->_Type) - { - case OT_STRING: - obj->PushBack(rapidjson::StringRef(node->_VAL.asString->_val), allocator); - break; - case OT_INTEGER: - obj->PushBack(node->_VAL.asInteger, allocator); - break; - case OT_FLOAT: - obj->PushBack(node->_VAL.asFloat, allocator); - break; - case OT_BOOL: - if (node->_VAL.asInteger) - obj->PushBack(rapidjson::StringRef("true"), allocator); - else - obj->PushBack(rapidjson::StringRef("false"), allocator); - break; - case OT_TABLE: - EncodeJSONTable<context>(node->_VAL.asTable, &newObj, allocator); - obj->PushBack(newObj, allocator); - break; - case OT_ARRAY: - EncodeJSONArray<context>(node->_VAL.asArray, &newArray, allocator); - obj->PushBack(newArray, allocator); - break; - default: - spdlog::info("SQ encode Json type {} not supported", SQTypeNameFromID(node->_Type)); - } - } -} - -ADD_SQFUNC( - "table", - DecodeJSON, - "string json, bool fatalParseErrors = false", - "converts a json string to a squirrel table", - ScriptContext::UI | ScriptContext::CLIENT | ScriptContext::SERVER) -{ - const char* pJson = g_pSquirrel<context>->getstring(sqvm, 1); - const bool bFatalParseErrors = g_pSquirrel<context>->getbool(sqvm, 2); - - rapidjson_document doc; - doc.Parse(pJson); - if (doc.HasParseError()) - { - g_pSquirrel<context>->newtable(sqvm); - - std::string sErrorString = fmt::format( - "Failed parsing json file: encountered parse error \"{}\" at offset {}", - GetParseError_En(doc.GetParseError()), - doc.GetErrorOffset()); - - if (bFatalParseErrors) - { - g_pSquirrel<context>->raiseerror(sqvm, sErrorString.c_str()); - return SQRESULT_ERROR; - } - - spdlog::warn(sErrorString); - return SQRESULT_NOTNULL; - } - - DecodeJsonTable<context>(sqvm, (rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>*)&doc); - return SQRESULT_NOTNULL; -} - -ADD_SQFUNC( - "string", - EncodeJSON, - "table data", - "converts a squirrel table to a json string", - ScriptContext::UI | ScriptContext::CLIENT | ScriptContext::SERVER) -{ - rapidjson_document doc; - doc.SetObject(); - - // temp until this is just the func parameter type - HSquirrelVM* vm = (HSquirrelVM*)sqvm; - SQTable* table = vm->_stackOfCurrentFunction[1]._VAL.asTable; - EncodeJSONTable<context>(table, &doc, doc.GetAllocator()); - - rapidjson::StringBuffer buffer; - rapidjson::Writer<rapidjson::StringBuffer> writer(buffer); - doc.Accept(writer); - const char* pJsonString = buffer.GetString(); - - g_pSquirrel<context>->pushstring(sqvm, pJsonString, -1); - return SQRESULT_NOTNULL; -} diff --git a/NorthstarDLL/scripts/scriptjson.h b/NorthstarDLL/scripts/scriptjson.h deleted file mode 100644 index b747106b..00000000 --- a/NorthstarDLL/scripts/scriptjson.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "rapidjson/document.h" -#include "rapidjson/writer.h" -#include "rapidjson/stringbuffer.h" - -template <ScriptContext context> void EncodeJSONTable( - SQTable* table, - rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* obj, - rapidjson::MemoryPoolAllocator<SourceAllocator>& allocator); - -template <ScriptContext context> void -DecodeJsonTable(HSquirrelVM* sqvm, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* obj); diff --git a/NorthstarDLL/scripts/scriptutility.cpp b/NorthstarDLL/scripts/scriptutility.cpp deleted file mode 100644 index 4b92fa02..00000000 --- a/NorthstarDLL/scripts/scriptutility.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "squirrel/squirrel.h" -#include "client/r2client.h" -#include "engine/r2engine.h" - -// asset function StringToAsset( string assetName ) -ADD_SQFUNC( - "asset", - StringToAsset, - "string assetName", - "converts a given string to an asset", - ScriptContext::UI | ScriptContext::CLIENT | ScriptContext::SERVER) -{ - g_pSquirrel<context>->pushasset(sqvm, g_pSquirrel<context>->getstring(sqvm, 1), -1); - return SQRESULT_NOTNULL; -} - -// string function NSGetLocalPlayerUID() -ADD_SQFUNC( - "string", NSGetLocalPlayerUID, "", "Returns the local player's uid.", ScriptContext::UI | ScriptContext::CLIENT | ScriptContext::SERVER) -{ - if (g_pLocalPlayerUserID) - { - g_pSquirrel<context>->pushstring(sqvm, g_pLocalPlayerUserID); - return SQRESULT_NOTNULL; - } - - return SQRESULT_NULL; -} diff --git a/NorthstarDLL/scripts/server/miscserverfixes.cpp b/NorthstarDLL/scripts/server/miscserverfixes.cpp deleted file mode 100644 index 48c2c111..00000000 --- a/NorthstarDLL/scripts/server/miscserverfixes.cpp +++ /dev/null @@ -1,6 +0,0 @@ - -ON_DLL_LOAD("server.dll", MiscServerFixes, (CModule module)) -{ - // nop out call to VGUI shutdown since it crashes the game when quitting from the console - module.Offset(0x154A96).NOP(5); -} diff --git a/NorthstarDLL/scripts/server/miscserverscript.cpp b/NorthstarDLL/scripts/server/miscserverscript.cpp deleted file mode 100644 index ed6e4800..00000000 --- a/NorthstarDLL/scripts/server/miscserverscript.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include "squirrel/squirrel.h" -#include "masterserver/masterserver.h" -#include "server/auth/serverauthentication.h" -#include "dedicated/dedicated.h" -#include "client/r2client.h" -#include "server/r2server.h" - -#include <filesystem> - -ADD_SQFUNC("void", NSEarlyWritePlayerPersistenceForLeave, "entity player", "", ScriptContext::SERVER) -{ - const CBasePlayer* pPlayer = g_pSquirrel<context>->template getentity<CBasePlayer>(sqvm, 1); - if (!pPlayer) - { - spdlog::warn("NSEarlyWritePlayerPersistenceForLeave got null player"); - - g_pSquirrel<context>->pushbool(sqvm, false); - return SQRESULT_NOTNULL; - } - - CBaseClient* pClient = &g_pClientArray[pPlayer->m_nPlayerIndex - 1]; - if (g_pServerAuthentication->m_PlayerAuthenticationData.find(pClient) == g_pServerAuthentication->m_PlayerAuthenticationData.end()) - { - g_pSquirrel<context>->pushbool(sqvm, false); - return SQRESULT_NOTNULL; - } - - g_pServerAuthentication->m_PlayerAuthenticationData[pClient].needPersistenceWriteOnLeave = false; - g_pServerAuthentication->WritePersistentData(pClient); - return SQRESULT_NULL; -} - -ADD_SQFUNC("bool", NSIsWritingPlayerPersistence, "", "", ScriptContext::SERVER) -{ - g_pSquirrel<context>->pushbool(sqvm, g_pMasterServerManager->m_bSavingPersistentData); - return SQRESULT_NOTNULL; -} - -ADD_SQFUNC("bool", NSIsPlayerLocalPlayer, "entity player", "", ScriptContext::SERVER) -{ - const CBasePlayer* pPlayer = g_pSquirrel<ScriptContext::SERVER>->template getentity<CBasePlayer>(sqvm, 1); - if (!pPlayer) - { - spdlog::warn("NSIsPlayerLocalPlayer got null player"); - - g_pSquirrel<context>->pushbool(sqvm, false); - return SQRESULT_NOTNULL; - } - - CBaseClient* pClient = &g_pClientArray[pPlayer->m_nPlayerIndex - 1]; - g_pSquirrel<context>->pushbool(sqvm, !strcmp(g_pLocalPlayerUserID, pClient->m_UID)); - return SQRESULT_NOTNULL; -} - -ADD_SQFUNC("bool", NSIsDedicated, "", "", ScriptContext::SERVER) -{ - g_pSquirrel<context>->pushbool(sqvm, IsDedicatedServer()); - return SQRESULT_NOTNULL; -} - -ADD_SQFUNC( - "bool", - NSDisconnectPlayer, - "entity player, string reason", - "Disconnects the player from the server with the given reason", - ScriptContext::SERVER) -{ - const CBasePlayer* pPlayer = g_pSquirrel<context>->template getentity<CBasePlayer>(sqvm, 1); - const char* reason = g_pSquirrel<context>->getstring(sqvm, 2); - - if (!pPlayer) - { - spdlog::warn("Attempted to call NSDisconnectPlayer() with null player."); - - g_pSquirrel<context>->pushbool(sqvm, false); - return SQRESULT_NOTNULL; - } - - // Shouldn't happen but I like sanity checks. - CBaseClient* pClient = &g_pClientArray[pPlayer->m_nPlayerIndex - 1]; - if (!pClient) - { - spdlog::warn("NSDisconnectPlayer(): player entity has null CBaseClient!"); - - g_pSquirrel<context>->pushbool(sqvm, false); - return SQRESULT_NOTNULL; - } - - if (reason) - { - CBaseClient__Disconnect(pClient, 1, reason); - } - else - { - CBaseClient__Disconnect(pClient, 1, "Disconnected by the server."); - } - - g_pSquirrel<context>->pushbool(sqvm, true); - return SQRESULT_NOTNULL; -} diff --git a/NorthstarDLL/scripts/server/scriptuserinfo.cpp b/NorthstarDLL/scripts/server/scriptuserinfo.cpp deleted file mode 100644 index c53a9d22..00000000 --- a/NorthstarDLL/scripts/server/scriptuserinfo.cpp +++ /dev/null @@ -1,104 +0,0 @@ -#include "squirrel/squirrel.h" -#include "engine/r2engine.h" -#include "server/r2server.h" - -// clang-format off -ADD_SQFUNC("string", GetUserInfoKVString_Internal, "entity player, string key, string defaultValue = \"\"", - "Gets the string value of a given player's userinfo convar by name", ScriptContext::SERVER) -// clang-format on -{ - const CBasePlayer* pPlayer = g_pSquirrel<ScriptContext::SERVER>->template getentity<CBasePlayer>(sqvm, 1); - if (!pPlayer) - { - g_pSquirrel<ScriptContext::SERVER>->raiseerror(sqvm, "player is null"); - return SQRESULT_ERROR; - } - - const char* pKey = g_pSquirrel<ScriptContext::SERVER>->getstring(sqvm, 2); - const char* pDefaultValue = g_pSquirrel<ScriptContext::SERVER>->getstring(sqvm, 3); - - const char* pResult = g_pClientArray[pPlayer->m_nPlayerIndex - 1].m_ConVars->GetString(pKey, pDefaultValue); - g_pSquirrel<ScriptContext::SERVER>->pushstring(sqvm, pResult); - return SQRESULT_NOTNULL; -} - -// clang-format off -ADD_SQFUNC("asset", GetUserInfoKVAsset_Internal, "entity player, string key, asset defaultValue = $\"\"", - "Gets the asset value of a given player's userinfo convar by name", ScriptContext::SERVER) -// clang-format on -{ - const CBasePlayer* pPlayer = g_pSquirrel<ScriptContext::SERVER>->template getentity<CBasePlayer>(sqvm, 1); - if (!pPlayer) - { - g_pSquirrel<ScriptContext::SERVER>->raiseerror(sqvm, "player is null"); - return SQRESULT_ERROR; - } - - const char* pKey = g_pSquirrel<ScriptContext::SERVER>->getstring(sqvm, 2); - const char* pDefaultValue; - g_pSquirrel<ScriptContext::SERVER>->getasset(sqvm, 3, &pDefaultValue); - - const char* pResult = g_pClientArray[pPlayer->m_nPlayerIndex - 1].m_ConVars->GetString(pKey, pDefaultValue); - g_pSquirrel<ScriptContext::SERVER>->pushasset(sqvm, pResult); - return SQRESULT_NOTNULL; -} - -// clang-format off -ADD_SQFUNC("int", GetUserInfoKVInt_Internal, "entity player, string key, int defaultValue = 0", - "Gets the int value of a given player's userinfo convar by name", ScriptContext::SERVER) -// clang-format on -{ - const CBasePlayer* pPlayer = g_pSquirrel<ScriptContext::SERVER>->template getentity<CBasePlayer>(sqvm, 1); - if (!pPlayer) - { - g_pSquirrel<ScriptContext::SERVER>->raiseerror(sqvm, "player is null"); - return SQRESULT_ERROR; - } - - const char* pKey = g_pSquirrel<ScriptContext::SERVER>->getstring(sqvm, 2); - const int iDefaultValue = g_pSquirrel<ScriptContext::SERVER>->getinteger(sqvm, 3); - - const int iResult = g_pClientArray[pPlayer->m_nPlayerIndex - 1].m_ConVars->GetInt(pKey, iDefaultValue); - g_pSquirrel<ScriptContext::SERVER>->pushinteger(sqvm, iResult); - return SQRESULT_NOTNULL; -} - -// clang-format off -ADD_SQFUNC("float", GetUserInfoKVFloat_Internal, "entity player, string key, float defaultValue = 0", - "Gets the float value of a given player's userinfo convar by name", ScriptContext::SERVER) -// clang-format on -{ - const CBasePlayer* pPlayer = g_pSquirrel<ScriptContext::SERVER>->getentity<CBasePlayer>(sqvm, 1); - if (!pPlayer) - { - g_pSquirrel<ScriptContext::SERVER>->raiseerror(sqvm, "player is null"); - return SQRESULT_ERROR; - } - - const char* pKey = g_pSquirrel<ScriptContext::SERVER>->getstring(sqvm, 2); - const float flDefaultValue = g_pSquirrel<ScriptContext::SERVER>->getfloat(sqvm, 3); - - const float flResult = g_pClientArray[pPlayer->m_nPlayerIndex - 1].m_ConVars->GetFloat(pKey, flDefaultValue); - g_pSquirrel<ScriptContext::SERVER>->pushfloat(sqvm, flResult); - return SQRESULT_NOTNULL; -} - -// clang-format off -ADD_SQFUNC("bool", GetUserInfoKVBool_Internal, "entity player, string key, bool defaultValue = false", - "Gets the bool value of a given player's userinfo convar by name", ScriptContext::SERVER) -// clang-format on -{ - const CBasePlayer* pPlayer = g_pSquirrel<ScriptContext::SERVER>->getentity<CBasePlayer>(sqvm, 1); - if (!pPlayer) - { - g_pSquirrel<ScriptContext::SERVER>->raiseerror(sqvm, "player is null"); - return SQRESULT_ERROR; - } - - const char* pKey = g_pSquirrel<ScriptContext::SERVER>->getstring(sqvm, 2); - const bool bDefaultValue = g_pSquirrel<ScriptContext::SERVER>->getbool(sqvm, 3); - - const bool bResult = g_pClientArray[pPlayer->m_nPlayerIndex - 1].m_ConVars->GetInt(pKey, bDefaultValue); - g_pSquirrel<ScriptContext::SERVER>->pushbool(sqvm, bResult); - return SQRESULT_NOTNULL; -} |