From 4a3be5449e27893afc933471fef89c78368c5720 Mon Sep 17 00:00:00 2001 From: Edo Date: Thu, 20 Apr 2023 11:17:15 +0200 Subject: [PATCH 01/13] [General]: Small update (#951) --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6944b407..18ba7bc2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0.3.0/) and this project adheres to [Semantic Versioning](http://semver.org/). +The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0.3.0/). ## r4190 - 2023-04-19 From 8d63b23cd936b7a523347de7f76acaf03f8b3693 Mon Sep 17 00:00:00 2001 From: Edo Date: Thu, 20 Apr 2023 11:38:43 +0200 Subject: [PATCH 02/13] [Localization]: Update contributors list (#952) --- CHANGELOG.md | 2 +- src/Components/Modules/Localization.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18ba7bc2..a3f5169e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0.3.0/). -## r4190 - 2023-04-19 +## r4193 - 2023-04-19 ### Added diff --git a/src/Components/Modules/Localization.cpp b/src/Components/Modules/Localization.cpp index 413203d8..e7f44f83 100644 --- a/src/Components/Modules/Localization.cpp +++ b/src/Components/Modules/Localization.cpp @@ -137,6 +137,7 @@ namespace Components "Dasfonia", "Deity", "Dizzy", + "Evan/Eve" "HardNougat", "INeedGames", "JTAG", From 1c29eaf229045d86cad96fcbcf6f83bff25865f8 Mon Sep 17 00:00:00 2001 From: Edo Date: Thu, 20 Apr 2023 12:28:30 +0200 Subject: [PATCH 03/13] [Branding]: Update (#953) --- premake5.lua | 1 + src/Components/Modules/Branding.cpp | 36 ++++++++++----------- src/Components/Modules/Console.cpp | 45 +++++++------------------- src/Components/Modules/Party.cpp | 2 +- src/Components/Modules/ServerInfo.cpp | 6 ++-- src/Components/Modules/ServerList.cpp | 2 +- src/Components/Modules/ServerList.hpp | 2 +- src/Components/Modules/ZoneBuilder.cpp | 2 +- src/Resource.rc | 4 +-- 9 files changed, 39 insertions(+), 61 deletions(-) diff --git a/premake5.lua b/premake5.lua index f81f657a..aa016eb8 100644 --- a/premake5.lua +++ b/premake5.lua @@ -160,6 +160,7 @@ newaction { versionHeader:write("\n") versionHeader:write("// New revision definition. Will be used from now on\n") versionHeader:write("#define REVISION " .. revNumber .. "\n") + versionHeader:write("#define REVISION_STR \"r" .. revNumber .. "\"\n") versionHeader:write("\n") versionHeader:write("// Alias definitions\n") versionHeader:write("#define VERSION GIT_DESCRIBE\n") diff --git a/src/Components/Modules/Branding.cpp b/src/Components/Modules/Branding.cpp index e95e32bb..7e926eec 100644 --- a/src/Components/Modules/Branding.cpp +++ b/src/Components/Modules/Branding.cpp @@ -40,34 +40,34 @@ namespace Components { Utils::Hook::Call(0x4EFF80)(localClientNum); - if (Branding::CGDrawVersion.get()) + if (CGDrawVersion.get()) { - Branding::CG_DrawVersion(); + CG_DrawVersion(); } } const char* Branding::GetBuildNumber() { - return VERSION " latest " __DATE__ " " __TIME__; + return REVISION_STR " latest " __DATE__ " " __TIME__; } const char* Branding::GetVersionString() { // IW4x is technically a beta return Utils::String::VA("%s %s build %s %s", - BUILD_TYPE, "(Beta)", Branding::GetBuildNumber(), reinterpret_cast(0x7170A0)); + BUILD_TYPE, "(Beta)", GetBuildNumber(), reinterpret_cast(0x7170A0)); } void Branding::Dvar_SetVersionString(const Game::dvar_t* dvar, [[maybe_unused]] const char* value) { - const auto* result = Branding::GetVersionString(); + const auto* result = GetVersionString(); Utils::Hook::Call(0x4A9580)(dvar, result); } // Branding this might be a good idea in case this LSP logging ever gets turned on for some reason void Branding::MSG_WriteVersionStringHeader(Game::msg_t* msg, [[maybe_unused]] const char* string) { - const auto* result = Branding::GetVersionString(); + const auto* result = GetVersionString(); Utils::Hook::Call(0x463820)(msg, result); } @@ -95,50 +95,50 @@ namespace Components Branding::Branding() { - Branding::RegisterBrandingDvars(); + RegisterBrandingDvars(); // UI version string - Utils::Hook::Set(0x43F73B, "IW4x - " GIT_TAG); + Utils::Hook::Set(0x43F73B, "IW4x - " REVISION_STR); // Short version dvar - Utils::Hook::Set(0x60BD91, GIT_TAG); + Utils::Hook::Set(0x60BD91, REVISION_STR); // Com_Init_Try_Block_Function Utils::Hook::Set(0x60BAF4, BUILD_TYPE); - Utils::Hook::Set(0x60BAEf, GIT_TAG); + Utils::Hook::Set(0x60BAEf, REVISION_STR); Utils::Hook::Set(0x60BAE5, __DATE__); // G_InitGame Utils::Hook::Set(0x48EBA1, __DATE__); - Utils::Hook(0x4B12B0, Branding::GetBuildNumber, HOOK_JUMP).install()->quick(); + Utils::Hook(0x4B12B0, GetBuildNumber, HOOK_JUMP).install()->quick(); // Version string color static Game::vec4_t buildLocColor = {1.0f, 1.0f, 1.0f, 0.8f}; Utils::Hook::Set(0x43F710, buildLocColor); // Place ui version string to bottom right corner (ui_buildlocation) - Utils::Hook(0x6310A0, Branding::Dvar_RegisterUIBuildLocation, HOOK_CALL).install()->quick(); // Dvar_RegisterVec2 + Utils::Hook(0x6310A0, Dvar_RegisterUIBuildLocation, HOOK_CALL).install()->quick(); // Dvar_RegisterVec2 - Utils::Hook(0x60BD81, Branding::Dvar_SetVersionString, HOOK_CALL).install()->quick(); + Utils::Hook(0x60BD81, Dvar_SetVersionString, HOOK_CALL).install()->quick(); - Utils::Hook(0x4DA842, Branding::MSG_WriteVersionStringHeader, HOOK_CALL).install()->quick(); + Utils::Hook(0x4DA842, MSG_WriteVersionStringHeader, HOOK_CALL).install()->quick(); // Hook CG_DrawFullScreenDebugOverlays so we may render the version when it's appropriate - Utils::Hook(0x5AC975, Branding::CG_DrawVersion_Hk, HOOK_CALL).install()->quick(); + Utils::Hook(0x5AC975, CG_DrawVersion_Hk, HOOK_CALL).install()->quick(); // Console title if (ZoneBuilder::IsEnabled()) { - Utils::Hook::Set(0x4289E8, "IW4x (" GIT_TAG "): ZoneBuilder"); + Utils::Hook::Set(0x4289E8, "IW4x (" REVISION_STR "): ZoneBuilder"); } else if (Dedicated::IsEnabled()) { - Utils::Hook::Set(0x4289E8, "IW4x (" GIT_TAG "): Dedicated"); + Utils::Hook::Set(0x4289E8, "IW4x (" REVISION_STR "): Dedicated"); } else { - Utils::Hook::Set(0x4289E8, "IW4x (" GIT_TAG "): Console"); + Utils::Hook::Set(0x4289E8, "IW4x (" REVISION_STR "): Console"); } } } diff --git a/src/Components/Modules/Console.cpp b/src/Components/Modules/Console.cpp index 0a91504d..941c3b5c 100644 --- a/src/Components/Modules/Console.cpp +++ b/src/Components/Modules/Console.cpp @@ -96,14 +96,14 @@ namespace Components } else if (IsWindow(GetWindow()) != FALSE) { - SetWindowTextA(GetWindow(), Utils::String::VA("IW4x(" GIT_TAG ") : %s", hostname.data())); + SetWindowTextA(GetWindow(), Utils::String::VA("IW4x(" REVISION_STR ") : %s", hostname.data())); } } void Console::ShowPrompt() { wattron(InputWindow, COLOR_PAIR(10) | A_BOLD); - wprintw(InputWindow, "%s> ", GIT_TAG); + wprintw(InputWindow, "%s> ", REVISION_STR); } void Console::RefreshOutput() @@ -427,38 +427,15 @@ namespace Components RefreshOutput(); } - HFONT CALLBACK Console::ReplaceFont( - [[maybe_unused]] int cHeight, - int cWidth, - int cEscapement, - int cOrientation, - [[maybe_unused]] int cWeight, - DWORD bItalic, - DWORD bUnderline, - DWORD bStrikeOut, - DWORD iCharSet, - [[maybe_unused]] DWORD iOutPrecision, - DWORD iClipPrecision, - [[maybe_unused]] DWORD iQuality, - [[maybe_unused]] DWORD iPitchAndFamily, - [[maybe_unused]] LPCSTR pszFaceName) + HFONT CALLBACK Console::ReplaceFont([[maybe_unused]] int cHeight, int cWidth, int cEscapement, int cOrientation, [[maybe_unused]] int cWeight, DWORD bItalic, DWORD bUnderline, + DWORD bStrikeOut, DWORD iCharSet, [[maybe_unused]] DWORD iOutPrecision, DWORD iClipPrecision, [[maybe_unused]] DWORD iQuality, + [[maybe_unused]] DWORD iPitchAndFamily, [[maybe_unused]] LPCSTR pszFaceName) { - HFONT font = CreateFontA( - 12, - cWidth, - cEscapement, - cOrientation, - 700, - bItalic, - bUnderline, - bStrikeOut, - iCharSet, - OUT_RASTER_PRECIS, - iClipPrecision, - NONANTIALIASED_QUALITY, - 0x31, - "Terminus (TTF)" - ); // Terminus (TTF) + HFONT font = CreateFontA(12, cWidth, cEscapement, cOrientation, 700, bItalic, + bUnderline, bStrikeOut, iCharSet, OUT_RASTER_PRECIS, + iClipPrecision, NONANTIALIASED_QUALITY, 0x31, + "Terminus (TTF)" + ); return font; } @@ -860,7 +837,7 @@ namespace Components AssertOffset(Game::clientUIActive_t, keyCatchers, 0x9B0); // Console '%s: %s> ' string - Utils::Hook::Set(0x5A44B4, "IW4x_MP: " GIT_TAG "> "); + Utils::Hook::Set(0x5A44B4, "IW4x MP: " REVISION_STR "> "); // Patch console color static float consoleColor[] = { 0.70f, 1.00f, 0.00f, 1.00f }; diff --git a/src/Components/Modules/Party.cpp b/src/Components/Modules/Party.cpp index c70231ac..0c85560f 100644 --- a/src/Components/Modules/Party.cpp +++ b/src/Components/Modules/Party.cpp @@ -386,7 +386,7 @@ namespace Components info.set("bots", std::to_string(botCount)); info.set("sv_maxclients", std::to_string(maxClientCount)); info.set("protocol", std::to_string(PROTOCOL)); - info.set("version", GIT_TAG); + info.set("version", REVISION_STR); info.set("checksum", std::to_string(Game::Sys_Milliseconds())); info.set("mapname", Dvar::Var("mapname").get()); info.set("isPrivate", *password ? "1" : "0"); diff --git a/src/Components/Modules/ServerInfo.cpp b/src/Components/Modules/ServerInfo.cpp index b342a142..164bc52a 100644 --- a/src/Components/Modules/ServerInfo.cpp +++ b/src/Components/Modules/ServerInfo.cpp @@ -58,7 +58,7 @@ namespace Components { Dvar::Var("uiSi_ServerName").set(serverInfo->hostname); Dvar::Var("uiSi_MaxClients").set(serverInfo->clients); - Dvar::Var("uiSi_Version").set(serverInfo->shortversion); + Dvar::Var("uiSi_Version").set(serverInfo->version); Dvar::Var("uiSi_SecurityLevel").set(serverInfo->securityLevel); Dvar::Var("uiSi_isPrivate").set(serverInfo->password ? "@MENU_YES" : "@MENU_NO"); Dvar::Var("uiSi_Hardcore").set(serverInfo->hardcore ? "@MENU_ENABLED" : "@MENU_DISABLED"); @@ -149,7 +149,7 @@ namespace Components info.set("gamename", "IW4"); info.set("sv_maxclients", std::to_string(maxClientCount)); info.set("protocol", std::to_string(PROTOCOL)); - info.set("version", GIT_TAG); + info.set("version", REVISION_STR); info.set("version", (*Game::version)->current.string); info.set("mapname", (*Game::sv_mapname)->current.string); info.set("isPrivate", *password ? "1" : "0"); @@ -261,7 +261,7 @@ namespace Components Dvar::Var("uiSi_ServerName").set(info.get("sv_hostname")); Dvar::Var("uiSi_MaxClients").set(info.get("sv_maxclients")); - Dvar::Var("uiSi_Version").set(info.get("shortversion")); + Dvar::Var("uiSi_Version").set(info.get("version")); Dvar::Var("uiSi_SecurityLevel").set(info.get("sv_securityLevel")); Dvar::Var("uiSi_isPrivate").set(info.get("isPrivate") == "0" ? "@MENU_NO" : "@MENU_YES"); Dvar::Var("uiSi_Hardcore").set(info.get("g_hardcore") == "0" ? "@MENU_DISABLED" : "@MENU_ENABLED"); diff --git a/src/Components/Modules/ServerList.cpp b/src/Components/Modules/ServerList.cpp index cca7be6e..efabd032 100644 --- a/src/Components/Modules/ServerList.cpp +++ b/src/Components/Modules/ServerList.cpp @@ -522,7 +522,7 @@ namespace Components server.hostname = info.get("hostname"); server.mapname = info.get("mapname"); server.gametype = info.get("gametype"); - server.shortversion = info.get("shortversion"); + server.version = info.get("version"); server.mod = info.get("fs_game"); server.matchType = std::strtol(info.get("matchtype").data(), nullptr, 10); server.clients = std::strtol(info.get("clients").data(), nullptr, 10); diff --git a/src/Components/Modules/ServerList.hpp b/src/Components/Modules/ServerList.hpp index af088b1e..2f69f5d4 100644 --- a/src/Components/Modules/ServerList.hpp +++ b/src/Components/Modules/ServerList.hpp @@ -17,7 +17,7 @@ namespace Components std::string mapname; std::string gametype; std::string mod; - std::string shortversion; + std::string version; std::size_t hash; int clients; int bots; diff --git a/src/Components/Modules/ZoneBuilder.cpp b/src/Components/Modules/ZoneBuilder.cpp index be5813b7..f1c54bf6 100644 --- a/src/Components/Modules/ZoneBuilder.cpp +++ b/src/Components/Modules/ZoneBuilder.cpp @@ -978,7 +978,7 @@ namespace Components } Logger::Print(" --------------------------------------------------------------------------------\n"); - Logger::Print(" IW4x ZoneBuilder - {}\n", VERSION); + Logger::Print(" IW4x ZoneBuilder - {}\n", REVISION_STR); Logger::Print(" Commands:\n"); Logger::Print("\t-buildzone [zone]: builds a zone from a csv located in zone_source\n"); Logger::Print("\t-buildall: builds all zones in zone_source\n"); diff --git a/src/Resource.rc b/src/Resource.rc index 9936e4b1..8cbfe655 100644 --- a/src/Resource.rc +++ b/src/Resource.rc @@ -69,12 +69,12 @@ BEGIN #else VALUE "FileDescription", "IW4 client modification" #endif - VALUE "FileVersion", GIT_TAG + VALUE "FileVersion", REVISION_STR VALUE "InternalName", "iw4x" VALUE "LegalCopyright", "Copyright 2023 The XLabsProject Team. All rights reserved." VALUE "OriginalFilename", "iw4x.dll" VALUE "ProductName", "IW4x" - VALUE "ProductVersion", GIT_TAG + VALUE "ProductVersion", REVISION_STR END END BLOCK "VarFileInfo" From 6b0f6cc395ccac8c68ffe0c401a5e50b5ef73a63 Mon Sep 17 00:00:00 2001 From: Edo Date: Thu, 20 Apr 2023 14:11:13 +0200 Subject: [PATCH 04/13] [General]: Remove unused macro (#954) --- src/Components/Modules/Branding.cpp | 3 +-- src/Components/Modules/ServerList.hpp | 3 --- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Components/Modules/Branding.cpp b/src/Components/Modules/Branding.cpp index 7e926eec..d35580da 100644 --- a/src/Components/Modules/Branding.cpp +++ b/src/Components/Modules/Branding.cpp @@ -74,8 +74,7 @@ namespace Components Game::dvar_t* Branding::Dvar_RegisterUIBuildLocation(const char* dvarName, [[maybe_unused]] float x, [[maybe_unused]] float y, float min, float max, [[maybe_unused]] int flags, const char* description) { - return Game::Dvar_RegisterVec2(dvarName, -60.0f, - 474.0f, min, max, Game::DVAR_ROM, description); + return Game::Dvar_RegisterVec2(dvarName, -60.0f, 472.0f, min, max, Game::DVAR_ROM, description); } void Branding::RegisterBrandingDvars() diff --git a/src/Components/Modules/ServerList.hpp b/src/Components/Modules/ServerList.hpp index 2f69f5d4..a0ebfc28 100644 --- a/src/Components/Modules/ServerList.hpp +++ b/src/Components/Modules/ServerList.hpp @@ -1,8 +1,5 @@ #pragma once -// This enables version filtering -#define VERSION_FILTER - namespace Components { class ServerList : public Component From e7ac9365d829c39f6f8822f40f859e7152f8414f Mon Sep 17 00:00:00 2001 From: Edo Date: Thu, 20 Apr 2023 16:04:05 +0200 Subject: [PATCH 05/13] [Download]: Fix com_dedicated (#955) --- src/Components/Modules/Download.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/Modules/Download.cpp b/src/Components/Modules/Download.cpp index 41cc285c..1c43324b 100644 --- a/src/Components/Modules/Download.cpp +++ b/src/Components/Modules/Download.cpp @@ -442,7 +442,7 @@ namespace Components info["status"] = status.to_json(); info["host"] = host.to_json(); info["map_rotation"] = MapRotation::to_json(); - info["dedicated"] = Dedicated::com_dedicated->current.value; + info["dedicated"] = Dedicated::com_dedicated->current.integer; std::vector players; From b3a0c521d20d265a7511b047b70e468232d94b9d Mon Sep 17 00:00:00 2001 From: Edo Date: Thu, 20 Apr 2023 16:30:51 +0200 Subject: [PATCH 06/13] [General Moment]: Create SECURITY.md (#956) --- CHANGELOG.md | 1 + SECURITY.md | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 SECURITY.md diff --git a/CHANGELOG.md b/CHANGELOG.md index a3f5169e..7296ac3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0. ### Changed - `sv_mapRotationCurrent` supports `exec` directive for executing cfg scripts from the `game_settings` folder +- `SetPing` GSC method is now deprecated. ### Fixed diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..ab88d3a6 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,17 @@ +## iw4x-client Security +We take security very seriously at XLabsProject. We welcome any peer review of our 100% free software source code to ensure nobody's IW4x clients or servers are ever compromised or hacked. + +### Where should I report security issues? + +In order to give the community time to respond and upgrade we strongly urge you report all security issues privately. +Please e-mail MauriceHeumann@gmail.com directly to provide details and repro steps. + +### Other key people + +In the exceptional case that you do not receive a response within a reasonable time frame from our lead developer, please contact any of the following people: +- Future/diamante0018: iw4x-sp@proton.me + +We will try respond as soon as possible, but please note: + +### This is an entirely free software project. It is maintained in our spare time. +### We cannot guarantee quick responses but we very much appreciate your discretion when reporting security vulnerabilities. From 39b9b9818cd9d5bada3ec8e6c6ae2bd3b8ae229a Mon Sep 17 00:00:00 2001 From: Edo Date: Thu, 20 Apr 2023 19:20:00 +0200 Subject: [PATCH 07/13] [Bots]: Use modern c++ lambda for loading file once (#957) --- CHANGELOG.md | 2 +- src/Components/Modules/Bots.cpp | 55 ++++++++++++++++----------------- src/Components/Modules/Bots.hpp | 6 ++-- 3 files changed, 30 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7296ac3f..2de00a75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0. ### Changed -- `sv_mapRotationCurrent` supports `exec` directive for executing cfg scripts from the `game_settings` folder +- `sv_mapRotationCurrent` supports `exec` directive for executing cfg scripts from the `game_settings` folder (#916) - `SetPing` GSC method is now deprecated. ### Fixed diff --git a/src/Components/Modules/Bots.cpp b/src/Components/Modules/Bots.cpp index a598c4ef..0daebf16 100644 --- a/src/Components/Modules/Bots.cpp +++ b/src/Components/Modules/Bots.cpp @@ -13,11 +13,11 @@ namespace Components { constexpr std::size_t MAX_NAME_LENGTH = 16; - std::vector Bots::BotNames; - const Game::dvar_t* Bots::sv_randomBotNames; const Game::dvar_t* Bots::sv_replaceBots; + std::size_t Bots::botDataIndex; + struct BotMovementInfo { std::int32_t buttons; // Actions @@ -54,27 +54,21 @@ namespace Components { "activate", Game::CMD_BUTTON_ACTIVATE }, }; - void Bots::RandomizeBotNames() + std::vector Bots::LoadBotNames() { - std::random_device rd; - std::mt19937 gen(rd()); - std::ranges::shuffle(BotNames, gen); - } + std::vector result; - void Bots::LoadBotNames() - { FileSystem::File bots("bots.txt"); - if (!bots.exists()) { - return; + return result; } auto data = Utils::String::Split(bots.getBuffer(), '\n'); for (auto& entry : data) { - // Take into account for CR line endings + // Take into account CR line endings Utils::String::Replace(entry, "\r", ""); // Remove whitespace Utils::String::Trim(entry); @@ -100,38 +94,41 @@ namespace Components entry = entry.substr(0, MAX_NAME_LENGTH - 1); - BotNames.emplace_back(entry, clanAbbrev); + result.emplace_back(entry, clanAbbrev); } - if (sv_randomBotNames->current.enabled) - { - RandomizeBotNames(); - } + return result; } int Bots::BuildConnectString(char* buffer, const char* connectString, int num, int, int protocol, int checksum, int statVer, int statStuff, int port) { - static std::size_t botId = 0; // Loop over the BotNames vector - static bool loadedNames = false; // Load file only once std::string botName; std::string clanName; - if (!loadedNames) + static const auto botNames = []() -> std::vector { - loadedNames = true; - LoadBotNames(); - } + auto names = LoadBotNames(); - if (!BotNames.empty()) + if (sv_randomBotNames->current.enabled) + { + std::random_device rd; + std::mt19937 gen(rd()); + std::ranges::shuffle(names, gen); + } + + return names; + }(); + + if (!botNames.empty()) { - botId %= BotNames.size(); - const auto index = botId++; - botName = BotNames[index].first; - clanName = BotNames[index].second; + botDataIndex %= botNames.size(); + const auto index = botDataIndex++; + botName = botNames[index].first; + clanName = botNames[index].second; } else { - botName = std::format("bot{}", ++botId); + botName = std::format("bot{}", port); clanName = "BOT"s; } diff --git a/src/Components/Modules/Bots.hpp b/src/Components/Modules/Bots.hpp index 9d7526e1..b7cf2315 100644 --- a/src/Components/Modules/Bots.hpp +++ b/src/Components/Modules/Bots.hpp @@ -11,13 +11,13 @@ namespace Components private: using botData = std::pair< std::string, std::string>; - static std::vector BotNames; static const Game::dvar_t* sv_randomBotNames; static const Game::dvar_t* sv_replaceBots; - static void RandomizeBotNames(); - static void LoadBotNames(); + static std::size_t botDataIndex; + + static std::vector LoadBotNames(); static int BuildConnectString(char* buffer, const char* connectString, int num, int, int protocol, int checksum, int statVer, int statStuff, int port); static void Spawn(unsigned int count); From aa3f0d414a407ecf3c0d19230de501dbbe3e6b35 Mon Sep 17 00:00:00 2001 From: Edo Date: Thu, 20 Apr 2023 19:32:27 +0200 Subject: [PATCH 08/13] [Bots]: Use correct parameter (#958) --- src/Components/Modules/Bots.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/Modules/Bots.cpp b/src/Components/Modules/Bots.cpp index 0daebf16..70fc6efe 100644 --- a/src/Components/Modules/Bots.cpp +++ b/src/Components/Modules/Bots.cpp @@ -128,7 +128,7 @@ namespace Components } else { - botName = std::format("bot{}", port); + botName = std::format("bot{}", num); clanName = "BOT"s; } From 63711ddd5125338dd7fa793bb2c31538da2f8f29 Mon Sep 17 00:00:00 2001 From: Edo Date: Fri, 21 Apr 2023 11:08:18 +0200 Subject: [PATCH 09/13] [General]: Update build.yml (#959) --- .github/workflows/build.yml | 4 +-- premake5.lua | 41 ++++++++++++++++++---------- src/Components/Modules/Branding.cpp | 18 +++++++++++- src/Components/Modules/Console.cpp | 14 +++++++++- src/Components/Modules/Singleton.cpp | 5 ++++ src/Utils/String.hpp | 4 +-- 6 files changed, 65 insertions(+), 21 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7586564b..951fd023 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -24,7 +24,7 @@ jobs: - Release steps: - name: Check out files - uses: actions/checkout@v3.3.0 + uses: actions/checkout@v3.5.2 with: submodules: true fetch-depth: 0 @@ -72,7 +72,7 @@ jobs: # Set up committer info and GPG key - name: Install SSH key - uses: shimataro/ssh-key-action@v2.5.0 + uses: shimataro/ssh-key-action@v2.5.1 with: key: ${{ secrets.XLABS_MASTER_SSH_PRIVATE_KEY }} known_hosts: 'just-a-placeholder-so-we-dont-get-errors' diff --git a/premake5.lua b/premake5.lua index aa016eb8..41cda692 100644 --- a/premake5.lua +++ b/premake5.lua @@ -17,19 +17,6 @@ function cstrquote(value) return result end --- Converts tags in "vX.X.X" format to an array of numbers {X,X,X}. --- In the case where the format does not work fall back to old {4,2,REVISION}. -function vertonumarr(value, vernumber) - vernum = {} - for num in string.gmatch(value, "%d+") do - table.insert(vernum, tonumber(num)) - end - if #vernum < 3 then - return {4,2,tonumber(vernumber)} - end - return vernum -end - dependencies = { basePath = "./deps" } @@ -108,7 +95,7 @@ newaction { newaction { trigger = "generate-buildinfo", - description = "Sets up build information file like version.h.", + description = "Sets up build information file. Output will be stored in version.h.", onWorkspace = function(wks) -- get revision number via git local proc = assert(io.popen("git rev-list --count HEAD", "r")) @@ -129,6 +116,26 @@ newaction { proc = assert(io.popen("git describe --tags --abbrev=0")) local tagName = assert(proc:read('*l')) + -- get current branch name + proc = assert(io.popen("git branch --show-current")) + local branchName = proc:read('*l') + + -- branch for ci + if branchName == nil or branchName == '' then + proc = assert(io.popen("git show -s --pretty=%d HEAD")) + local branchInfo = proc:read('*l') + m = string.match(branchInfo, ".+,.+, ([^)]+)") + if m ~= nil then + branchName = m + end + end + + if branchName == nil then + branchName = "develop" + end + + print("Detected branch: " .. branchName) + -- get old version number from version.hpp if any local oldVersion = "(none)" local oldVersionHeader = io.open(wks.location .. "/src/version.h", "r") @@ -157,10 +164,16 @@ newaction { versionHeader:write("#define GIT_DESCRIBE " .. gitDescribeOutputQuoted .. "\n") versionHeader:write("#define GIT_DIRTY " .. revDirty .. "\n") versionHeader:write("#define GIT_TAG " .. cstrquote(tagName) .. "\n") + versionHeader:write("#define GIT_BRANCH " .. cstrquote(branchName) .. "\n") versionHeader:write("\n") versionHeader:write("// New revision definition. Will be used from now on\n") versionHeader:write("#define REVISION " .. revNumber .. "\n") versionHeader:write("#define REVISION_STR \"r" .. revNumber .. "\"\n") + + if branchName == "develop" then + versionHeader:write("#define EXPERIMENTAL_BUILD" .. "\n") + end + versionHeader:write("\n") versionHeader:write("// Alias definitions\n") versionHeader:write("#define VERSION GIT_DESCRIBE\n") diff --git a/src/Components/Modules/Branding.cpp b/src/Components/Modules/Branding.cpp index d35580da..8263cf5f 100644 --- a/src/Components/Modules/Branding.cpp +++ b/src/Components/Modules/Branding.cpp @@ -48,7 +48,11 @@ namespace Components const char* Branding::GetBuildNumber() { +#ifdef EXPERIMENTAL_BUILD + return REVISION_STR "-develop latest " __DATE__ " " __TIME__; +#else return REVISION_STR " latest " __DATE__ " " __TIME__; +#endif } const char* Branding::GetVersionString() @@ -97,14 +101,22 @@ namespace Components RegisterBrandingDvars(); // UI version string +#ifdef EXPERIMENTAL_BUILD + Utils::Hook::Set(0x43F73B, "IW4x - " REVISION_STR "-develop"); +#else Utils::Hook::Set(0x43F73B, "IW4x - " REVISION_STR); +#endif // Short version dvar Utils::Hook::Set(0x60BD91, REVISION_STR); // Com_Init_Try_Block_Function Utils::Hook::Set(0x60BAF4, BUILD_TYPE); +#ifdef EXPERIMENTAL_BUILD + Utils::Hook::Set(0x60BAEf, REVISION_STR "-develop"); +#else Utils::Hook::Set(0x60BAEf, REVISION_STR); +#endif Utils::Hook::Set(0x60BAE5, __DATE__); // G_InitGame @@ -133,7 +145,11 @@ namespace Components } else if (Dedicated::IsEnabled()) { - Utils::Hook::Set(0x4289E8, "IW4x (" REVISION_STR "): Dedicated"); +#ifdef EXPERIMENTAL_BUILD + Utils::Hook::Set(0x4289E8, "IW4x " REVISION_STR "-develop: Dedicated"); +#else + Utils::Hook::Set(0x4289E8, "IW4x " REVISION_STR ": Dedicated"); +#endif } else { diff --git a/src/Components/Modules/Console.cpp b/src/Components/Modules/Console.cpp index 941c3b5c..8be532f7 100644 --- a/src/Components/Modules/Console.cpp +++ b/src/Components/Modules/Console.cpp @@ -96,14 +96,22 @@ namespace Components } else if (IsWindow(GetWindow()) != FALSE) { - SetWindowTextA(GetWindow(), Utils::String::VA("IW4x(" REVISION_STR ") : %s", hostname.data())); +#ifdef EXPERIMENTAL_BUILD + SetWindowTextA(GetWindow(), Utils::String::Format("IW4x " REVISION_STR "-develop : %s", hostname)); +#else + SetWindowTextA(GetWindow(), Utils::String::Format("IW4x " REVISION_STR " : %s", hostname)); +#endif } } void Console::ShowPrompt() { wattron(InputWindow, COLOR_PAIR(10) | A_BOLD); +#ifdef EXPERIMENTAL_BUILD + wprintw(InputWindow, "%s-develop> ", REVISION_STR); +#else wprintw(InputWindow, "%s> ", REVISION_STR); +#endif } void Console::RefreshOutput() @@ -837,7 +845,11 @@ namespace Components AssertOffset(Game::clientUIActive_t, keyCatchers, 0x9B0); // Console '%s: %s> ' string +#ifdef EXPERIMENTAL_BUILD + Utils::Hook::Set(0x5A44B4, "IW4x MP: " REVISION_STR "-develop> "); +#else Utils::Hook::Set(0x5A44B4, "IW4x MP: " REVISION_STR "> "); +#endif // Patch console color static float consoleColor[] = { 0.70f, 1.00f, 0.00f, 1.00f }; diff --git a/src/Components/Modules/Singleton.cpp b/src/Components/Modules/Singleton.cpp index 5b419c0e..9ae0b43b 100644 --- a/src/Components/Modules/Singleton.cpp +++ b/src/Components/Modules/Singleton.cpp @@ -18,7 +18,12 @@ namespace Components if (Flags::HasFlag("version")) { printf("%s", "IW4x " VERSION " (built " __DATE__ " " __TIME__ ")\n"); +#ifdef EXPERIMENTAL_BUILD + printf("Revision: %i - develop\n", REVISION); +#else printf("Revision: %i\n", REVISION); +#endif + ExitProcess(EXIT_SUCCESS); } diff --git a/src/Utils/String.hpp b/src/Utils/String.hpp index 826ffbd2..0c90d90b 100644 --- a/src/Utils/String.hpp +++ b/src/Utils/String.hpp @@ -90,10 +90,8 @@ namespace Utils::String [[nodiscard]] const char* Format(std::string_view fmt, Args&&... args) { static thread_local std::string vaBuffer; - vaBuffer.clear(); - (SanitizeFormatArgs(args), ...); - std::vformat_to(std::back_inserter(vaBuffer), fmt, std::make_format_args(args...)); + std::vformat(fmt, std::make_format_args(args...)).swap(vaBuffer); return vaBuffer.data(); } From 1439f32bdec47b65adb2439ce2d73c407d2e7e6e Mon Sep 17 00:00:00 2001 From: Edo Date: Fri, 21 Apr 2023 11:31:45 +0200 Subject: [PATCH 10/13] [Branding]: Undo this (#960) --- src/Components/Modules/Branding.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Components/Modules/Branding.cpp b/src/Components/Modules/Branding.cpp index 8263cf5f..0164b6d4 100644 --- a/src/Components/Modules/Branding.cpp +++ b/src/Components/Modules/Branding.cpp @@ -101,11 +101,7 @@ namespace Components RegisterBrandingDvars(); // UI version string -#ifdef EXPERIMENTAL_BUILD - Utils::Hook::Set(0x43F73B, "IW4x - " REVISION_STR "-develop"); -#else Utils::Hook::Set(0x43F73B, "IW4x - " REVISION_STR); -#endif // Short version dvar Utils::Hook::Set(0x60BD91, REVISION_STR); From 4dcbe32c54a805b016e42ef4abdb3782da96ea18 Mon Sep 17 00:00:00 2001 From: Edo Date: Sat, 22 Apr 2023 10:13:55 +0200 Subject: [PATCH 11/13] [Utils]: Update InfoString (#961) --- src/Utils/InfoString.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Utils/InfoString.cpp b/src/Utils/InfoString.cpp index 0dbd6429..206f936e 100644 --- a/src/Utils/InfoString.cpp +++ b/src/Utils/InfoString.cpp @@ -51,13 +51,9 @@ namespace Utils std::string InfoString::build() const { std::string infoString; - - auto first = true; for (const auto& [key, value] : this->keyValuePairs_) { - if (first) first = false; - else infoString.append("\\"); - + infoString.append("\\"); infoString.append(key); infoString.append("\\"); infoString.append(value); From 42e5132c5ed3f70cb7933ae87340c8b39e8562f4 Mon Sep 17 00:00:00 2001 From: Edo Date: Sat, 22 Apr 2023 14:58:15 +0200 Subject: [PATCH 12/13] [ClientCommand]: Improve GSC methods (#962) --- src/Components/Modules/ClientCommand.cpp | 20 +++++++++++++++++++- src/Components/Modules/ClientCommand.hpp | 9 +++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/Components/Modules/ClientCommand.cpp b/src/Components/Modules/ClientCommand.cpp index a1fc116a..a1747309 100644 --- a/src/Components/Modules/ClientCommand.cpp +++ b/src/Components/Modules/ClientCommand.cpp @@ -9,11 +9,23 @@ namespace Components { std::unordered_map> ClientCommand::HandlersSV; + bool ClientCommand::CheatsEnabled; + + ClientCommand::CheatsScopedLock::CheatsScopedLock() + { + CheatsEnabled = true; + } + + ClientCommand::CheatsScopedLock::~CheatsScopedLock() + { + CheatsEnabled = false; + } + bool ClientCommand::CheatsOk(const Game::gentity_s* ent) { const auto entNum = ent->s.number; - if (!(*Game::g_cheats)->current.enabled) + if (!(*Game::g_cheats)->current.enabled && !CheatsEnabled) { Logger::Debug("Cheats are disabled!"); Game::SV_GameSendServerCommand(entNum, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_CHEATSNOTENABLED\"", 0x65)); @@ -351,12 +363,16 @@ namespace Components GSC::Script::AddMethod("Noclip", [](const Game::scr_entref_t entref) // gsc: self Noclip(); { auto* ent = GSC::Script::Scr_GetPlayerEntity(entref); + + CheatsScopedLock cheatsLock; Cmd_Noclip_f(ent, nullptr); }); GSC::Script::AddMethod("Ufo", [](const Game::scr_entref_t entref) // gsc: self Ufo(); { auto* ent = GSC::Script::Scr_GetPlayerEntity(entref); + + CheatsScopedLock cheatsLock; Cmd_UFO_f(ent, nullptr); }); } @@ -502,6 +518,8 @@ namespace Components // Hook call to ClientCommand in SV_ExecuteClientCommand so we may add custom commands Utils::Hook(0x6259FA, ClientCommandStub, HOOK_CALL).install()->quick(); + CheatsEnabled = false; + AddCheatCommands(); AddScriptFunctions(); AddScriptMethods(); diff --git a/src/Components/Modules/ClientCommand.hpp b/src/Components/Modules/ClientCommand.hpp index b6b39cb5..cb545bfe 100644 --- a/src/Components/Modules/ClientCommand.hpp +++ b/src/Components/Modules/ClientCommand.hpp @@ -13,6 +13,15 @@ namespace Components private: static std::unordered_map> HandlersSV; + static bool CheatsEnabled; + + class CheatsScopedLock + { + public: + CheatsScopedLock(); + ~CheatsScopedLock(); + }; + static void ClientCommandStub(int clientNum); static void AddCheatCommands(); static void AddDevelopmentCommands(); From a43b95cbaa1105fd4e591cad708364b9872beaac Mon Sep 17 00:00:00 2001 From: Edo Date: Sat, 22 Apr 2023 18:56:29 +0200 Subject: [PATCH 13/13] [General]: Small cleanup (#963) --- CHANGELOG.md | 18 ++++++++++++++++++ src/Components/Modules/Debug.cpp | 2 +- src/Components/Modules/SoundMutexFix.cpp | 14 +++++++------- src/Components/Modules/SoundMutexFix.hpp | 4 ++-- src/Game/Engine/ScopedCriticalSection.cpp | 21 ++++++++++----------- 5 files changed, 38 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2de00a75..72cfcf32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,23 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0.3.0/). +## r4208 - 2023-04-22 + +### Changed + +- `Noclip` GSC method does not require `sv_cheats` to be set to "1" for it to work (#962) +- `Ufo` GSC method does not require `sv_cheats` to be set to "1" for it to work (#962) + +### Fixed + +- Fix `InfoString` output (#961) +- Fix parsing of the server info (client-side) (#953) +- Fix bug in the /info TCP endpoint (#955) + +### Known issues + +- Sound issue fix is experimental as the bug is not fully understood. + ## r4193 - 2023-04-19 ### Added @@ -20,6 +37,7 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0. ### Fixed - `sv_privatePassword` will work as intended (#908) +- Fix crash when loading bots.txt file (#927) ### Known issues diff --git a/src/Components/Modules/Debug.cpp b/src/Components/Modules/Debug.cpp index 4e7b7c95..a5c66fb3 100644 --- a/src/Components/Modules/Debug.cpp +++ b/src/Components/Modules/Debug.cpp @@ -317,7 +317,7 @@ namespace Components void Debug::Com_BugNameInc_f() { - char buf[260]{}; + char buf[512]{}; if (std::strlen(BugName->current.string) < 4) { diff --git a/src/Components/Modules/SoundMutexFix.cpp b/src/Components/Modules/SoundMutexFix.cpp index 935ffefd..5a3c66b9 100644 --- a/src/Components/Modules/SoundMutexFix.cpp +++ b/src/Components/Modules/SoundMutexFix.cpp @@ -23,18 +23,18 @@ namespace Components // team switch and intermission. // - std::mutex SoundMutexFix::SNDMutex; + std::mutex SoundMutexFix::CloseStreamMutex; - void __stdcall SoundMutexFix::LockSoundMutex(int unk) + void WINAPI SoundMutexFix::AIL_close_stream_Stub(int h_stream) { - std::lock_guard lock(SNDMutex); + std::lock_guard lock(CloseStreamMutex); - DWORD funcPtr = *reinterpret_cast(0x6D7554); // AIL_close_stream - Utils::Hook::Call(funcPtr)(unk); + const auto ptr = *reinterpret_cast(0x6D7554); // AIL_close_stream + Utils::Hook::Call(ptr)(h_stream); } SoundMutexFix::SoundMutexFix() { - Utils::Hook(0x689EFE, &LockSoundMutex, HOOK_JUMP).install()->quick(); + Utils::Hook(0x689EFE, &AIL_close_stream_Stub, HOOK_JUMP).install()->quick(); } -} \ No newline at end of file +} diff --git a/src/Components/Modules/SoundMutexFix.hpp b/src/Components/Modules/SoundMutexFix.hpp index ef62050f..5c4d8988 100644 --- a/src/Components/Modules/SoundMutexFix.hpp +++ b/src/Components/Modules/SoundMutexFix.hpp @@ -9,7 +9,7 @@ namespace Components SoundMutexFix(); private: - static std::mutex SNDMutex; - static void _stdcall LockSoundMutex(int unk); + static std::mutex CloseStreamMutex; + static void WINAPI AIL_close_stream_Stub(int h_stream); }; } diff --git a/src/Game/Engine/ScopedCriticalSection.cpp b/src/Game/Engine/ScopedCriticalSection.cpp index 9a756c94..8b62ef4f 100644 --- a/src/Game/Engine/ScopedCriticalSection.cpp +++ b/src/Game/Engine/ScopedCriticalSection.cpp @@ -10,23 +10,22 @@ namespace Game::Engine { Sys_EnterCriticalSection(this->s_); this->hasOwnership_ = true; + return; + } + + if (type == SCOPED_CRITSECT_TRY) + { + this->hasOwnership_ = Sys_TryEnterCriticalSection(this->s_); } else { - if (type == SCOPED_CRITSECT_TRY) + if (type == SCOPED_CRITSECT_RELEASE) { - this->hasOwnership_ = Sys_TryEnterCriticalSection(this->s_); + Sys_LeaveCriticalSection(this->s_); + this->isScopedRelease_ = true; } - else - { - if (type == SCOPED_CRITSECT_RELEASE) - { - Sys_LeaveCriticalSection(this->s_); - this->isScopedRelease_ = true; - } - this->hasOwnership_ = false; - } + this->hasOwnership_ = false; } }