diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6b7622272..8aebf4953 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,6 +26,7 @@ jobs: shell: bash run: | sed -i 's/DEV/${{ env.NORTHSTAR_VERSION }}/g' NorthstarLauncher/resources.rc + sed -i 's/DEV/${{ env.NORTHSTAR_VERSION }}/g' NorthstarDLL/resources.rc FILEVERSION=$(echo ${{ env.NORTHSTAR_VERSION }} | tr '.' ',' | sed -E 's/-rc[0-9]+//' | tr -d '[:alpha:]') sed -i "s/0,0,0,1/${FILEVERSION}/g" NorthstarDLL/ns_version.h - name: Build diff --git a/BUILD.md b/BUILD.md index b44817f2c..06dc1fb9c 100644 --- a/BUILD.md +++ b/BUILD.md @@ -3,6 +3,7 @@ The following steps will allow you to compile your own NorthstarLauncher executa *This guide assumes you have already installed Northstar as shown in [this page](https://r2northstar.gitbook.io/r2northstar-wiki/installing-northstar/basic-setup)* +## Windows ### Steps 1. **Install Git** from [this link](https://git-scm.com) 2. **Clone** the [R2Northstar/NorthstarLauncher](https://github.com/R2Northstar/NorthstarLauncher) repo with submodules using this command `git clone --recurse-submodules https://github.com/R2Northstar/NorthstarLauncher.git` @@ -39,3 +40,12 @@ Developers who can work a command line may be interested in using [Visual Studio - Run `cmake . -G "Ninja"` to generate build files. - Run `cmake --build .` to build the project. + +## Linux +### Steps +1. Clone the GitHub repo +2. Use `cd` to navigate to the cloned repo's directory +3. Then, run the following commands in order: +* `docker build --rm -t northstar-build-fedora .` +* `docker run --rm -it -e CC=cl -e CXX=cl --mount type=bind,source="$(pwd)",destination=/build northstar-build-fedora cmake . -DCMAKE_BUILD_TYPE=Release -DCMAKE_SYSTEM_NAME=Windows -G "Ninja"` +* `docker run --rm -it -e CC=cl -e CXX=cl --mount type=bind,source="$(pwd)",destination=/build northstar-build-fedora cmake --build .` diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..261d649fa --- /dev/null +++ b/Dockerfile @@ -0,0 +1,26 @@ +FROM registry.fedoraproject.org/fedora-toolbox:38 +RUN dnf update -y && \ + dnf install -y \ + git \ + wine \ + wine-mono \ + python3 \ + msitools \ + python3-simplejson \ + python3-six \ + cmake \ + ninja-build \ + make \ + samba \ + libunwind && \ + dnf clean all && \ + mkdir /opt/msvc/ /build + +RUN git config --global --add safe.directory /build +RUN git clone https://github.com/mstorsjo/msvc-wine && \ + ./msvc-wine/vsdownload.py --accept-license --dest /opt/msvc/ && \ + ./msvc-wine/install.sh /opt/msvc/ && \ + rm -rf ~/.wine ./msvc-wine/ && \ + git config --global --add safe.directory '/build' +ENV PATH="/opt/msvc/bin/x64:${PATH}" +WORKDIR /build/ diff --git a/NorthstarDLL/CMakeLists.txt b/NorthstarDLL/CMakeLists.txt index 126812e9b..a7ca10283 100644 --- a/NorthstarDLL/CMakeLists.txt +++ b/NorthstarDLL/CMakeLists.txt @@ -4,6 +4,7 @@ find_package(minhook REQUIRED) find_package(libcurl REQUIRED) add_library(NorthstarDLL SHARED + "resources.rc" "client/audio.cpp" "client/audio.h" "client/chatcommand.cpp" diff --git a/NorthstarDLL/core/filesystem/filesystem.h b/NorthstarDLL/core/filesystem/filesystem.h index 560b8c2ca..ac1c5986d 100644 --- a/NorthstarDLL/core/filesystem/filesystem.h +++ b/NorthstarDLL/core/filesystem/filesystem.h @@ -19,19 +19,7 @@ OFFSET_STRUCT(VPKFileEntry) // clang-format on #pragma pack(pop) -#pragma pack(push, 1) -// clang-format off -struct VPKData -{ - STRUCT_SIZE(0x50); - FIELDS(0x0, - char* directory; - char* filename; - char* extension; - ) -}; -// clang-format on -#pragma pack(pop) +struct VPKData; enum SearchPathAdd_t { diff --git a/NorthstarDLL/dedicated/dedicatedlogtoclient.cpp b/NorthstarDLL/dedicated/dedicatedlogtoclient.cpp index 8d19372f3..a48b1b39b 100644 --- a/NorthstarDLL/dedicated/dedicatedlogtoclient.cpp +++ b/NorthstarDLL/dedicated/dedicatedlogtoclient.cpp @@ -1,4 +1,3 @@ -#include "pch.h" #include "dedicatedlogtoclient.h" #include "engine/r2engine.h" diff --git a/NorthstarDLL/logging/loghooks.cpp b/NorthstarDLL/logging/loghooks.cpp index 53a85c1bd..41e1bce23 100644 --- a/NorthstarDLL/logging/loghooks.cpp +++ b/NorthstarDLL/logging/loghooks.cpp @@ -249,7 +249,7 @@ ON_DLL_LOAD_RELIESON("engine.dll", EngineSpewFuncHooks, ConVar, (CModule module) { AUTOHOOK_DISPATCH_MODULE(engine.dll) - Cvar_spewlog_enable = new ConVar("spewlog_enable", "1", FCVAR_NONE, "Enables/disables whether the engine spewfunc should be logged"); + Cvar_spewlog_enable = new ConVar("spewlog_enable", "0", FCVAR_NONE, "Enables/disables whether the engine spewfunc should be logged"); } ON_DLL_LOAD_CLIENT_RELIESON("client.dll", ClientPrintHooks, ConVar, (CModule module)) diff --git a/NorthstarDLL/mods/modmanager.cpp b/NorthstarDLL/mods/modmanager.cpp index c54314c05..1ca51ad7a 100644 --- a/NorthstarDLL/mods/modmanager.cpp +++ b/NorthstarDLL/mods/modmanager.cpp @@ -16,6 +16,7 @@ #include #include #include +#include ModManager* g_pModManager; @@ -611,32 +612,35 @@ void ModManager::LoadMods() // get mod directories std::filesystem::directory_iterator classicModsDir = fs::directory_iterator(GetModFolderPath()); std::filesystem::directory_iterator remoteModsDir = fs::directory_iterator(GetRemoteModFolderPath()); + std::filesystem::directory_iterator thunderstoreModsDir = fs::directory_iterator(GetThunderstoreModFolderPath()); - for (std::filesystem::directory_iterator modIterator : {classicModsDir, remoteModsDir}) - for (fs::directory_entry dir : modIterator) - if (fs::exists(dir.path() / "mod.json")) - modDirs.push_back(dir.path()); + for (fs::directory_entry dir : classicModsDir) + if (fs::exists(dir.path() / "mod.json")) + modDirs.push_back(dir.path()); - // Special case for Thunderstore mods dir - std::filesystem::directory_iterator thunderstoreModsDir = fs::directory_iterator(GetThunderstoreModFolderPath()); + // Special case for Thunderstore and remote mods directories // Set up regex for `AUTHOR-MOD-VERSION` pattern std::regex pattern(R"(.*\\([a-zA-Z0-9_]+)-([a-zA-Z0-9_]+)-(\d+\.\d+\.\d+))"); - for (fs::directory_entry dir : thunderstoreModsDir) + + for (fs::directory_iterator dirIterator : {thunderstoreModsDir, remoteModsDir}) { - fs::path modsDir = dir.path() / "mods"; // Check for mods folder in the Thunderstore mod - // Use regex to match `AUTHOR-MOD-VERSION` pattern - if (!std::regex_match(dir.path().string(), pattern)) - { - spdlog::warn("The following directory did not match 'AUTHOR-MOD-VERSION': {}", modsDir.string()); - continue; // skip loading mod that doesn't match - } - if (fs::exists(modsDir) && fs::is_directory(modsDir)) + for (fs::directory_entry dir : dirIterator) { - for (fs::directory_entry subDir : fs::directory_iterator(modsDir)) + fs::path modsDir = dir.path() / "mods"; // Check for mods folder in the Thunderstore mod + // Use regex to match `AUTHOR-MOD-VERSION` pattern + if (!std::regex_match(dir.path().string(), pattern)) { - if (fs::exists(subDir.path() / "mod.json")) + spdlog::warn("The following directory did not match 'AUTHOR-MOD-VERSION': {}", dir.path().string()); + continue; // skip loading mod that doesn't match + } + if (fs::exists(modsDir) && fs::is_directory(modsDir)) + { + for (fs::directory_entry subDir : fs::directory_iterator(modsDir)) { - modDirs.push_back(subDir.path()); + if (fs::exists(subDir.path() / "mod.json")) + { + modDirs.push_back(subDir.path()); + } } } } diff --git a/NorthstarDLL/mods/modsavefiles.cpp b/NorthstarDLL/mods/modsavefiles.cpp index 6676ec344..f8e5848c6 100644 --- a/NorthstarDLL/mods/modsavefiles.cpp +++ b/NorthstarDLL/mods/modsavefiles.cpp @@ -1,4 +1,3 @@ -#include "pch.h" #include #include #include diff --git a/NorthstarDLL/pch.cpp b/NorthstarDLL/pch.cpp deleted file mode 100644 index 64b7eef6d..000000000 --- a/NorthstarDLL/pch.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// pch.cpp: source file corresponding to the pre-compiled header - -#include "pch.h" - -// When you are using pre-compiled headers, this source file is necessary for compilation to succeed. diff --git a/NorthstarDLL/plugins/pluginbackend.cpp b/NorthstarDLL/plugins/pluginbackend.cpp index b442d702d..091ddd2f8 100644 --- a/NorthstarDLL/plugins/pluginbackend.cpp +++ b/NorthstarDLL/plugins/pluginbackend.cpp @@ -1,4 +1,3 @@ -#include "pch.h" #include "pluginbackend.h" #include "plugin_abi.h" #include "server/serverpresence.h" diff --git a/NorthstarDLL/plugins/pluginbackend.h b/NorthstarDLL/plugins/pluginbackend.h index ef42c5089..898b3a994 100644 --- a/NorthstarDLL/plugins/pluginbackend.h +++ b/NorthstarDLL/plugins/pluginbackend.h @@ -1,5 +1,4 @@ #pragma once -#include "pch.h" #include "plugin_abi.h" #include "shared/gamepresence.h" diff --git a/NorthstarDLL/plugins/plugins.cpp b/NorthstarDLL/plugins/plugins.cpp index 9ba4707a9..0c4c7fd60 100644 --- a/NorthstarDLL/plugins/plugins.cpp +++ b/NorthstarDLL/plugins/plugins.cpp @@ -7,6 +7,7 @@ #include "core/convar/convar.h" #include "server/serverpresence.h" #include +#include #include "util/version.h" #include "pluginbackend.h" @@ -196,14 +197,7 @@ inline void FindPlugins(fs::path pluginPath, std::vector& paths) return; } - fs::recursive_directory_iterator iterator(pluginPath); - // ensure iterator is not empty - if (std::filesystem::begin(iterator) != std::filesystem::end(iterator)) - { - return; - } - - for (auto const& entry : iterator) + for (const fs::directory_entry& entry : fs::recursive_directory_iterator(pluginPath)) { if (fs::is_regular_file(entry) && entry.path().extension() == ".dll") paths.emplace_back(entry.path()); @@ -218,9 +212,11 @@ bool PluginManager::LoadPlugins() return false; } + fs::create_directories(GetThunderstoreModFolderPath()); + std::vector paths; - pluginPath = GetNorthstarPrefix() + "/plugins"; + pluginPath = GetNorthstarPrefix() + "\\plugins"; PluginNorthstarData data {}; std::string ns_version {version}; @@ -237,12 +233,20 @@ bool PluginManager::LoadPlugins() FindPlugins(pluginPath, paths); - // Special case for Thunderstore plugin dirs - - for (fs::directory_entry dir : fs::directory_iterator(GetThunderstoreModFolderPath())) + // Special case for Thunderstore mods dir + std::filesystem::directory_iterator thunderstoreModsDir = fs::directory_iterator(GetThunderstoreModFolderPath()); + // Set up regex for `AUTHOR-MOD-VERSION` pattern + std::regex pattern(R"(.*\\([a-zA-Z0-9_]+)-([a-zA-Z0-9_]+)-(\d+\.\d+\.\d+))"); + for (fs::directory_entry dir : thunderstoreModsDir) { - fs::path pluginDir = dir.path() / "plugins"; - FindPlugins(pluginDir, paths); + fs::path pluginsDir = dir.path() / "plugins"; + // Use regex to match `AUTHOR-MOD-VERSION` pattern + if (!std::regex_match(dir.path().string(), pattern)) + { + spdlog::warn("The following directory did not match 'AUTHOR-MOD-VERSION': {}", dir.path().string()); + continue; // skip loading package that doesn't match + } + FindPlugins(pluginsDir, paths); } if (paths.empty()) diff --git a/NorthstarDLL/resource1.h b/NorthstarDLL/resource1.h new file mode 100644 index 000000000..bb584502c --- /dev/null +++ b/NorthstarDLL/resource1.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by resources.rc +// +#define IDI_ICON1 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/NorthstarDLL/resources.rc b/NorthstarDLL/resources.rc new file mode 100644 index 000000000..7e996617b --- /dev/null +++ b/NorthstarDLL/resources.rc @@ -0,0 +1,79 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource1.h" +#include "../NorthstarDLL/ns_version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource1.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION NORTHSTAR_VERSION + PRODUCTVERSION NORTHSTAR_VERSION + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080904b0" + BEGIN + VALUE "CompanyName", "Northstar Developers" + VALUE "FileVersion", "DEV" + VALUE "InternalName", "Northstar.dll" + VALUE "LegalCopyright", "Copyright (C) 2021" + VALUE "OriginalFilename", "Northstar.dll" + VALUE "ProductVersion", "DEV" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x809, 1200 + END +END + +///////////////////////////////////////////////////////////////////////////// + + diff --git a/NorthstarDLL/scripts/scriptjson.h b/NorthstarDLL/scripts/scriptjson.h index 09926bef3..b747106b2 100644 --- a/NorthstarDLL/scripts/scriptjson.h +++ b/NorthstarDLL/scripts/scriptjson.h @@ -1,6 +1,5 @@ #pragma once -#include "pch.h" #include "rapidjson/document.h" #include "rapidjson/writer.h" #include "rapidjson/stringbuffer.h" diff --git a/NorthstarDLL/shared/gamepresence.cpp b/NorthstarDLL/shared/gamepresence.cpp index 86a875267..11cb7adeb 100644 --- a/NorthstarDLL/shared/gamepresence.cpp +++ b/NorthstarDLL/shared/gamepresence.cpp @@ -1,5 +1,3 @@ -#include "pch.h" - #include "gamepresence.h" #include "plugins/pluginbackend.h" #include "plugins/plugins.h" diff --git a/NorthstarDLL/shared/gamepresence.h b/NorthstarDLL/shared/gamepresence.h index 167f83aba..439ec65c2 100644 --- a/NorthstarDLL/shared/gamepresence.h +++ b/NorthstarDLL/shared/gamepresence.h @@ -1,6 +1,5 @@ - #pragma once -#include "pch.h" + #include "server/serverpresence.h" class GameStateServerPresenceReporter : public ServerPresenceReporter diff --git a/NorthstarDLL/squirrel/squirrel.cpp b/NorthstarDLL/squirrel/squirrel.cpp index 43dd0cadf..0ee04508c 100644 --- a/NorthstarDLL/squirrel/squirrel.cpp +++ b/NorthstarDLL/squirrel/squirrel.cpp @@ -893,7 +893,7 @@ ON_DLL_LOAD_RELIESON("server.dll", ServerSquirrel, ConCommand, (CModule module)) MAKEHOOK(module.Offset(0x26E20), &DestroyVMHook, &DestroyVM); MAKEHOOK(module.Offset(0x799E0), &ScriptCompileErrorHook, &SQCompileError); MAKEHOOK(module.Offset(0x1D5C0), &CallScriptInitCallbackHook, &CallScriptInitCallback); - MAKEHOOK(module.Offset(0x17BE0), &CSquirrelVM_initHook, &CSquirrelVM_init); + MAKEHOOK(module.Offset(0x1B7E0), &CSquirrelVM_initHook, &CSquirrelVM_init); // FCVAR_CHEAT and FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS allows clients to execute this, but since it's unsafe we only allow it when cheats // are enabled for script_client and script_ui, we don't use cheats, so clients can execute them on themselves all they want RegisterConCommand( diff --git a/loader_wsock32_proxy/CMakeLists.txt b/loader_wsock32_proxy/CMakeLists.txt index 3c21d0101..3157f6c55 100644 --- a/loader_wsock32_proxy/CMakeLists.txt +++ b/loader_wsock32_proxy/CMakeLists.txt @@ -6,8 +6,6 @@ add_library(loader_wsock32_proxy SHARED "dllmain.cpp" "loader.cpp" "loader.h" - "pch.cpp" - "pch.h" "wsock32.asm" "wsock32.def" ) diff --git a/loader_wsock32_proxy/dllmain.cpp b/loader_wsock32_proxy/dllmain.cpp index c5610042b..4cc4f26e8 100644 --- a/loader_wsock32_proxy/dllmain.cpp +++ b/loader_wsock32_proxy/dllmain.cpp @@ -1,4 +1,3 @@ -#include "pch.h" #include "loader.h" #include diff --git a/loader_wsock32_proxy/loader.cpp b/loader_wsock32_proxy/loader.cpp index c5046e2ed..3e46c1a62 100644 --- a/loader_wsock32_proxy/loader.cpp +++ b/loader_wsock32_proxy/loader.cpp @@ -1,10 +1,12 @@ -#include "pch.h" #include "loader.h" #include #include #include #include #include +#include + +namespace fs = std::filesystem; void LibraryLoadError(DWORD dwMessageId, const wchar_t* libName, const wchar_t* location) { @@ -45,18 +47,55 @@ bool LoadNorthstar() { FARPROC Hook_Init = nullptr; { - swprintf_s(buffer1, L"%s\\Northstar.dll", exePath); - auto hHookModule = LoadLibraryExW(buffer1, 0, LOAD_WITH_ALTERED_SEARCH_PATH); + std::string strProfile = "R2Northstar"; + char* clachar = strstr(GetCommandLineA(), "-profile="); + if (clachar) + { + std::string cla = std::string(clachar); + if (strncmp(cla.substr(9, 1).c_str(), "\"", 1)) + { + int space = cla.find(" "); + std::string dirname = cla.substr(9, space - 9); + std::cout << "[*] Found profile in command line arguments: " << dirname << std::endl; + strProfile = dirname.c_str(); + } + else + { + std::string quote = "\""; + int quote1 = cla.find(quote); + int quote2 = (cla.substr(quote1 + 1)).find(quote); + std::string dirname = cla.substr(quote1 + 1, quote2); + std::cout << "[*] Found profile in command line arguments: " << dirname << std::endl; + strProfile = dirname; + } + } + else + { + std::cout << "[*] Profile was not found in command line arguments. Using default: R2Northstar" << std::endl; + strProfile = "R2Northstar"; + } + + wchar_t buffer[8192]; + + // Check if "Northstar.dll" exists in profile directory, if it doesnt fall back to root + swprintf_s(buffer, L"%s\\%s\\Northstar.dll", exePath, std::wstring(strProfile.begin(), strProfile.end()).c_str()); + + if (!fs::exists(fs::path(buffer))) + swprintf_s(buffer, L"%s\\Northstar.dll", exePath); + + std::wcout << L"[*] Using: " << buffer << std::endl; + + HMODULE hHookModule = LoadLibraryExW(buffer, 0, 8u); if (hHookModule) Hook_Init = GetProcAddress(hHookModule, "InitialiseNorthstar"); if (!hHookModule || Hook_Init == nullptr) { - LibraryLoadError(GetLastError(), L"Northstar.dll", buffer1); + LibraryLoadError(GetLastError(), L"Northstar.dll", buffer); return false; } } - ((bool (*)())Hook_Init)(); + return true; } diff --git a/loader_wsock32_proxy/pch.cpp b/loader_wsock32_proxy/pch.cpp deleted file mode 100644 index 64b7eef6d..000000000 --- a/loader_wsock32_proxy/pch.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// pch.cpp: source file corresponding to the pre-compiled header - -#include "pch.h" - -// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.