From 61bae28625c73eec2357d0711900cdc46218f861 Mon Sep 17 00:00:00 2001 From: X Labs Bot Date: Wed, 3 May 2023 19:21:33 +0200 Subject: [PATCH 01/39] Merge release r4251 (#1005) Co-authored-by: Edo From 35141b11068c73b8bddd5bf3d0fa81f97162c9b5 Mon Sep 17 00:00:00 2001 From: Edo Date: Wed, 3 May 2023 18:32:24 +0100 Subject: [PATCH 02/39] [General]: Forgot this (#1006) --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aecace85..2862b491 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0. - Add GSC client field `ping` as a read-only field (#1002) - Add GSC client field `address` as a read-only field (#1003) -- Add to the iw4x-rawfiles common_scripts\utility GSC script `getIP` function. +- Add to the iw4x-rawfiles `common_scripts\utility` GSC script `getIP` function. ### Fixed From 42110d586d09fff044ee0b539faf53041ca01d03 Mon Sep 17 00:00:00 2001 From: Edo Date: Wed, 3 May 2023 22:44:11 +0100 Subject: [PATCH 03/39] [SoundFix]: Disable as this seems fixed (#1007) --- src/Components/Loader.cpp | 2 -- src/Components/Modules/SoundMutexFix.cpp | 40 ------------------------ src/Components/Modules/SoundMutexFix.hpp | 15 --------- 3 files changed, 57 deletions(-) delete mode 100644 src/Components/Modules/SoundMutexFix.cpp delete mode 100644 src/Components/Modules/SoundMutexFix.hpp diff --git a/src/Components/Loader.cpp b/src/Components/Loader.cpp index cce1e935..8f9d9bf5 100644 --- a/src/Components/Loader.cpp +++ b/src/Components/Loader.cpp @@ -49,7 +49,6 @@ #include "Modules/ServerList.hpp" #include "Modules/Session.hpp" #include "Modules/SlowMotion.hpp" -#include "Modules/SoundMutexFix.hpp" #include "Modules/StartupMessages.hpp" #include "Modules/Stats.hpp" #include "Modules/StringTable.hpp" @@ -163,7 +162,6 @@ namespace Components Register(new ServerList()); Register(new Session()); Register(new SlowMotion()); - Register(new SoundMutexFix()); Register(new StartupMessages()); Register(new Stats()); Register(new StringTable()); diff --git a/src/Components/Modules/SoundMutexFix.cpp b/src/Components/Modules/SoundMutexFix.cpp deleted file mode 100644 index 5a3c66b9..00000000 --- a/src/Components/Modules/SoundMutexFix.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include "SoundMutexFix.hpp" - -namespace Components -{ - // This component is a workaround for issue https://github.com/XLabsProject/iw4x-client/issues/80 - // In case the link goes down, this is a "game hangs randomly" issue: - // - // Investigations on the issue pointed out it comes from a situation on Intel processors where - // WaitForSingleObjectA is ignored by a thread, for some (?) reason. - // - // This locks up the game randomly, mostly at the end of rounds or when too many things happen at - // once, due to trying to stop sounds (AIL_Stop_sounds) and playing streams at the same time, - // rushing for the same resource via AIL_lock_mutex. - // - // This bug has been reproduced on mp_terminal, mp_overgrown, mp_rust, with and without bots, - // and so far this has been the only way to circumvent it afaik. This component wraps - // miles' mutex into another mutex, created below, and for some reason (?) that mutex is - // respected when miles' is not. - // - // As soon as a real fix is found, please discard this fix. In the meantime, it should not - // have side effects too bad - worst case it might cause a slight performance drop during - // team switch and intermission. - // - - std::mutex SoundMutexFix::CloseStreamMutex; - - void WINAPI SoundMutexFix::AIL_close_stream_Stub(int h_stream) - { - std::lock_guard lock(CloseStreamMutex); - - const auto ptr = *reinterpret_cast(0x6D7554); // AIL_close_stream - Utils::Hook::Call(ptr)(h_stream); - } - - SoundMutexFix::SoundMutexFix() - { - Utils::Hook(0x689EFE, &AIL_close_stream_Stub, HOOK_JUMP).install()->quick(); - } -} diff --git a/src/Components/Modules/SoundMutexFix.hpp b/src/Components/Modules/SoundMutexFix.hpp deleted file mode 100644 index 5c4d8988..00000000 --- a/src/Components/Modules/SoundMutexFix.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include - -namespace Components -{ - class SoundMutexFix : public Component - { - public: - SoundMutexFix(); - - private: - static std::mutex CloseStreamMutex; - static void WINAPI AIL_close_stream_Stub(int h_stream); - }; -} From 4f4ef3184060ef3debfb489d247c84a5e23ccfcb Mon Sep 17 00:00:00 2001 From: Edo Date: Thu, 4 May 2023 08:30:21 +0100 Subject: [PATCH 04/39] [CHANGELOG]: Rewrite this entry (#1008) --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2862b491..baa46085 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -114,7 +114,7 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0. - Test Clients will no longer receive names from the Xlabs Patreon website. The old behaviour was restored (#852) - Enabled `OpenFile` GSC function (#862) - Enabled `CloseFile` GSC function (#862) -- Chat system uses "reliable message" to mitigate message duplication (#873) +- Chat system will now use `SV_CMD_RELIABLE` commands to mitigate message duplication (#873) - The built-in GSC compiler no longer throws fatal errors when overriding a built-in function or method (IW3 behaviour) (#880) - `CastFloat` GSC function was renamed to `Float` (#880) From e018f6c8fd7128f080ae00ebe6351fa7c8b07ca0 Mon Sep 17 00:00:00 2001 From: Edo Date: Thu, 4 May 2023 18:40:38 +0100 Subject: [PATCH 05/39] [Voice]: Add debug print (#1009) --- src/Components/Modules/Voice.cpp | 1 + src/Game/Engine/FastCriticalSection.cpp | 39 +++++++++++++++++++++++++ src/Game/Engine/FastCriticalSection.hpp | 24 +++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 src/Game/Engine/FastCriticalSection.cpp create mode 100644 src/Game/Engine/FastCriticalSection.hpp diff --git a/src/Components/Modules/Voice.cpp b/src/Components/Modules/Voice.cpp index b578e9f3..5379eb6c 100644 --- a/src/Components/Modules/Voice.cpp +++ b/src/Components/Modules/Voice.cpp @@ -320,6 +320,7 @@ namespace Components auto* clc = Game::CL_GetLocalClientConnection(0); if (!Game::NET_CompareBaseAdr(clc->serverAddress, *address)) { + Logger::Debug("Ignoring stray 'v' network message from '{}'", Game::NET_AdrToString(*address)); return; } diff --git a/src/Game/Engine/FastCriticalSection.cpp b/src/Game/Engine/FastCriticalSection.cpp new file mode 100644 index 00000000..82ae7082 --- /dev/null +++ b/src/Game/Engine/FastCriticalSection.cpp @@ -0,0 +1,39 @@ +#include +#include "FastCriticalSection.hpp" + +namespace Game::Engine +{ + FastCriticalSectionScopeRead::FastCriticalSectionScopeRead(FastCriticalSection* cs) + : cs_(cs) + { + if (this->cs_) + { + Sys_LockRead(this->cs_); + } + } + + FastCriticalSectionScopeRead::~FastCriticalSectionScopeRead() + { + if (this->cs_) + { + Sys_UnlockRead(this->cs_); + } + } + + FastCriticalSectionScopeWrite::FastCriticalSectionScopeWrite(FastCriticalSection* cs) + : cs_(cs) + { + if (this->cs_) + { + Sys_LockWrite(this->cs_); + } + } + + FastCriticalSectionScopeWrite::~FastCriticalSectionScopeWrite() + { + if (this->cs_) + { + Sys_UnlockWrite(this->cs_); + } + } +} diff --git a/src/Game/Engine/FastCriticalSection.hpp b/src/Game/Engine/FastCriticalSection.hpp new file mode 100644 index 00000000..c50ba734 --- /dev/null +++ b/src/Game/Engine/FastCriticalSection.hpp @@ -0,0 +1,24 @@ +#pragma once + +namespace Game::Engine +{ + class FastCriticalSectionScopeRead + { + public: + FastCriticalSectionScopeRead(FastCriticalSection* cs); + ~FastCriticalSectionScopeRead(); + + private: + FastCriticalSection* cs_; + }; + + class FastCriticalSectionScopeWrite + { + public: + FastCriticalSectionScopeWrite(FastCriticalSection* cs); + ~FastCriticalSectionScopeWrite(); + + private: + FastCriticalSection* cs_; + }; +} From 00bc10ac3cdc90d6a2def289dc79f69362b7cebd Mon Sep 17 00:00:00 2001 From: Edo Date: Thu, 4 May 2023 19:18:35 +0100 Subject: [PATCH 06/39] [General]: Syntax cleanup in utils (#1010) --- src/Utils/Cryptography.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/Utils/Cryptography.cpp b/src/Utils/Cryptography.cpp index dd4047c7..66b791a2 100644 --- a/src/Utils/Cryptography.cpp +++ b/src/Utils/Cryptography.cpp @@ -25,7 +25,7 @@ namespace Utils pos += sprintf_s(&buffer[pos], sizeof(buffer) - pos, "%X", ~timeGetTime() ^ GenerateInt()); pos += sprintf_s(&buffer[pos], sizeof(buffer) - pos, "%X", GenerateInt()); - return std::string(buffer, static_cast(pos)); + return std::string{ buffer, static_cast(pos) }; } std::uint32_t Rand::GenerateInt() @@ -62,13 +62,13 @@ namespace Utils if (!key.isValid()) return {}; std::uint8_t buffer[512]; - DWORD length = sizeof(buffer); + unsigned long length = sizeof(buffer); ltc_mp = ltm_desc; register_prng(&sprng_desc); ecc_sign_hash(reinterpret_cast(message.data()), message.size(), buffer, &length, nullptr, find_prng("sprng"), key.getKeyPtr()); - return {reinterpret_cast(buffer), length}; + return std::string{ reinterpret_cast(buffer), length }; } bool ECC::VerifyMessage(Key key, const std::string& message, const std::string& signature) @@ -78,7 +78,9 @@ namespace Utils ltc_mp = ltm_desc; int result = 0; - return (ecc_verify_hash(reinterpret_cast(signature.data()), signature.size(), reinterpret_cast(message.data()), message.size(), &result, key.getKeyPtr()) == CRYPT_OK && result != 0); + return (ecc_verify_hash(reinterpret_cast(signature.data()), signature.size(), + reinterpret_cast(message.data()), message.size(), + &result, key.getKeyPtr()) == CRYPT_OK && result != 0); } #pragma endregion @@ -104,7 +106,7 @@ namespace Utils if (!key.isValid()) return {}; std::uint8_t buffer[512]; - DWORD length = sizeof(buffer); + unsigned long length = sizeof(buffer); register_prng(&sprng_desc); register_hash(&sha1_desc); @@ -113,7 +115,7 @@ namespace Utils rsa_sign_hash(reinterpret_cast(message.data()), message.size(), buffer, &length, NULL, find_prng("sprng"), find_hash("sha1"), 0, key.getKeyPtr()); - return {reinterpret_cast(buffer), length}; + return std::string{ reinterpret_cast(buffer), length }; } bool RSA::VerifyMessage(Key key, const std::string& message, const std::string& signature) @@ -185,7 +187,7 @@ namespace Utils tiger_process(&state, data, length); tiger_done(&state, buffer); - std::string hash(reinterpret_cast(buffer), sizeof(buffer)); + std::string hash{ reinterpret_cast(buffer), sizeof(buffer) }; if (!hex) return hash; return String::DumpHex(hash, {}); @@ -209,7 +211,7 @@ namespace Utils sha1_process(&state, data, length); sha1_done(&state, buffer); - std::string hash(reinterpret_cast(buffer), sizeof(buffer)); + std::string hash{ reinterpret_cast(buffer), sizeof(buffer) }; if (!hex) return hash; return String::DumpHex(hash, {}); @@ -233,7 +235,7 @@ namespace Utils sha256_process(&state, data, length); sha256_done(&state, buffer); - std::string hash(reinterpret_cast(buffer), sizeof(buffer)); + std::string hash{ reinterpret_cast(buffer), sizeof(buffer) }; if (!hex) return hash; return String::DumpHex(hash, {}); @@ -257,7 +259,7 @@ namespace Utils sha512_process(&state, data, length); sha512_done(&state, buffer); - std::string hash(reinterpret_cast(buffer), sizeof(buffer)); + std::string hash{ reinterpret_cast(buffer), sizeof(buffer) }; if (!hex) return hash; return String::DumpHex(hash, {}); From 6001044ae6b04a92c8ead32dfe4380aacbd438bd Mon Sep 17 00:00:00 2001 From: Edo Date: Fri, 5 May 2023 19:14:53 +0100 Subject: [PATCH 07/39] [Network]: Better reverse of print OOB handler (#1011) --- CHANGELOG.md | 4 ++++ src/Components/Modules/Gamepad.cpp | 8 ++++---- src/Components/Modules/Network.cpp | 13 +++++++------ src/Game/Functions.cpp | 2 +- src/Game/Functions.hpp | 4 ++-- 5 files changed, 18 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index baa46085..8e493d53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,10 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0. - Chat system will go back to using `SV_CMD_CAN_IGNORE` commands (#972) +### Security + +- Check the address of the sender for the `print` OOB packet (#969) + ### Fixed - Fix bug with how `sv_mapRotationCurrent` is parsed (#977) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index f2515a65..b7552c67 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -1235,11 +1235,11 @@ namespace Components if (Game::Key_IsCatcherActive(localClientNum, Game::KEYCATCH_LOCATION_SELECTION) && pressedOrUpdated) { - if (key == Game::K_BUTTON_B || keyState.keys[key].binding && strcmp(keyState.keys[key].binding, "+actionslot 4") == 0) + if (key == Game::K_BUTTON_B || keyState.keys[key].binding && std::strcmp(keyState.keys[key].binding, "+actionslot 4") == 0) { keyState.locSelInputState = Game::LOC_SEL_INPUT_CANCEL; } - else if (key == Game::K_BUTTON_A || keyState.keys[key].binding && strcmp(keyState.keys[key].binding, "+attack") == 0) + else if (key == Game::K_BUTTON_A || keyState.keys[key].binding && std::strcmp(keyState.keys[key].binding, "+attack") == 0) { keyState.locSelInputState = Game::LOC_SEL_INPUT_CONFIRM; } @@ -1926,7 +1926,7 @@ namespace Components continue; } - if (Game::playerKeys[0].keys[keyNum].binding && strcmp(Game::playerKeys[0].keys[keyNum].binding, gamePadCmd) == 0) + if (Game::playerKeys[0].keys[keyNum].binding && std::strcmp(Game::playerKeys[0].keys[keyNum].binding, gamePadCmd) == 0) { (*keys)[keyCount++] = keyNum; @@ -1946,7 +1946,7 @@ namespace Components continue; } - if (Game::playerKeys[0].keys[keyNum].binding && strcmp(Game::playerKeys[0].keys[keyNum].binding, cmd) == 0) + if (Game::playerKeys[0].keys[keyNum].binding && std::strcmp(Game::playerKeys[0].keys[keyNum].binding, cmd) == 0) { (*keys)[keyCount++] = keyNum; diff --git a/src/Components/Modules/Network.cpp b/src/Components/Modules/Network.cpp index 800b4ce0..38ccc6ef 100644 --- a/src/Components/Modules/Network.cpp +++ b/src/Components/Modules/Network.cpp @@ -408,19 +408,20 @@ namespace Components SendRaw(address, address.getString()); }); - OnClientPacket("print", []([[maybe_unused]] const Address& address, [[maybe_unused]] const std::string& data) + OnClientPacketRaw("print", [](Game::netadr_t* address, Game::msg_t* msg) { auto* clc = Game::CL_GetLocalClientConnection(0); - if (!Game::NET_CompareBaseAdr(clc->serverAddress, *address.get())) + if (!Game::NET_CompareBaseAdr(clc->serverAddress, *address)) { return; } - char buffer[2048]{}; + char printBuf[2048]{}; - Game::I_strncpyz(clc->serverMessage, data.data(), sizeof(clc->serverMessage)); - Game::Com_sprintf(buffer, sizeof(buffer), "%s", data.data()); - Game::Com_PrintMessage(Game::CON_CHANNEL_CLIENT, buffer, 0); + const auto* s = Game::MSG_ReadBigString(msg); + Game::I_strncpyz(clc->serverMessage, s, sizeof(clc->serverMessage)); + Game::Com_sprintf(printBuf, sizeof(printBuf), "%s", s); + Game::Com_PrintMessage(Game::CON_CHANNEL_CLIENT, printBuf, false); }); } } diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index 51e4e8d6..97de97b1 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -93,7 +93,7 @@ namespace Game MSG_ReadLong_t MSG_ReadLong = MSG_ReadLong_t(0x4C9550); MSG_ReadShort_t MSG_ReadShort = MSG_ReadShort_t(0x40BDD0); MSG_ReadInt64_t MSG_ReadInt64 = MSG_ReadInt64_t(0x4F1850); - MSG_ReadString_t MSG_ReadString = MSG_ReadString_t(0x60E2B0); + MSG_ReadBigString_t MSG_ReadBigString = MSG_ReadBigString_t(0x60E2B0); MSG_ReadStringLine_t MSG_ReadStringLine = MSG_ReadStringLine_t(0x4FEF30); MSG_WriteByte_t MSG_WriteByte = MSG_WriteByte_t(0x48C520); MSG_WriteData_t MSG_WriteData = MSG_WriteData_t(0x4F4120); diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index a34bea03..b694b0b8 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -233,8 +233,8 @@ namespace Game typedef __int64(*MSG_ReadInt64_t)(msg_t* msg); extern MSG_ReadInt64_t MSG_ReadInt64; - typedef char*(*MSG_ReadString_t)(msg_t* msg, char* string, unsigned int maxChars); - extern MSG_ReadString_t MSG_ReadString; + typedef char*(*MSG_ReadBigString_t)(msg_t* msg); + extern MSG_ReadBigString_t MSG_ReadBigString; typedef char*(*MSG_ReadStringLine_t)(msg_t *msg, char *string, unsigned int maxChars); extern MSG_ReadStringLine_t MSG_ReadStringLine; From da1c5bfcf6d9b5ee6880d89114ca01baca4b44a9 Mon Sep 17 00:00:00 2001 From: Edo Date: Fri, 5 May 2023 19:42:34 +0100 Subject: [PATCH 08/39] [Network]: Use push_back (#1012) --- src/Components/Modules/Network.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Components/Modules/Network.cpp b/src/Components/Modules/Network.cpp index 38ccc6ef..76746907 100644 --- a/src/Components/Modules/Network.cpp +++ b/src/Components/Modules/Network.cpp @@ -193,7 +193,7 @@ namespace Components // EDIT: Most 3rd party tools expect a line break, so let's use that instead! std::string packet; packet.append(command); - packet.append("\n", 1); + packet.push_back('\n'); packet.append(data); Send(type, target, packet); @@ -303,7 +303,7 @@ namespace Components return false; } - const std::string data(reinterpret_cast(message->data) + offset, message->cursize - offset); + const std::string data{ reinterpret_cast(message->data) + offset, message->cursize - offset }; auto target = Address{ address }; handler->second(target, data); From d7d06ea47bb172d804dde691a6f8e096e6d81810 Mon Sep 17 00:00:00 2001 From: Edo Date: Sat, 6 May 2023 14:20:56 +0100 Subject: [PATCH 09/39] [Command]: Refactor (#1013) --- src/Components/Modules/Auth.cpp | 2 +- src/Components/Modules/Bans.cpp | 13 +++-- src/Components/Modules/Bans.hpp | 2 + src/Components/Modules/Bots.cpp | 68 ++++++++++++----------- src/Components/Modules/Bots.hpp | 2 + src/Components/Modules/CardTitles.cpp | 3 +- src/Components/Modules/Chat.cpp | 22 +++++--- src/Components/Modules/Chat.hpp | 2 +- src/Components/Modules/ClanTags.cpp | 2 +- src/Components/Modules/Command.cpp | 8 +-- src/Components/Modules/Command.hpp | 12 ++-- src/Components/Modules/Debug.cpp | 2 +- src/Components/Modules/Debug.hpp | 2 +- src/Components/Modules/Dedicated.cpp | 9 +-- src/Components/Modules/FastFiles.cpp | 4 +- src/Components/Modules/Friends.cpp | 29 ---------- src/Components/Modules/Friends.hpp | 2 - src/Components/Modules/Gamepad.cpp | 10 ++-- src/Components/Modules/Gamepad.hpp | 10 ++-- src/Components/Modules/IPCPipe.cpp | 2 +- src/Components/Modules/Logger.cpp | 19 +++---- src/Components/Modules/MapDump.cpp | 2 +- src/Components/Modules/MapRotation.cpp | 4 +- src/Components/Modules/Maps.cpp | 4 +- src/Components/Modules/Menus.cpp | 9 +-- src/Components/Modules/Network.cpp | 32 +++++++++++ src/Components/Modules/Network.hpp | 2 + src/Components/Modules/Node.cpp | 17 +++--- src/Components/Modules/Node.hpp | 2 +- src/Components/Modules/Party.cpp | 4 +- src/Components/Modules/QuickPatch.cpp | 2 +- src/Components/Modules/RCon.cpp | 6 +- src/Components/Modules/RawFiles.cpp | 4 +- src/Components/Modules/ServerCommands.hpp | 2 +- src/Components/Modules/Stats.cpp | 4 +- src/Components/Modules/StructuredData.cpp | 14 ----- src/Components/Modules/ZoneBuilder.cpp | 18 +++--- src/Components/Modules/Zones.cpp | 13 +---- src/DllMain.cpp | 12 ++-- src/Game/Client.cpp | 1 + src/Game/Functions.cpp | 3 +- src/Game/Functions.hpp | 5 +- src/STDInclude.hpp | 6 +- 43 files changed, 190 insertions(+), 201 deletions(-) diff --git a/src/Components/Modules/Auth.cpp b/src/Components/Modules/Auth.cpp index 3024699b..4b0ee31a 100644 --- a/src/Components/Modules/Auth.cpp +++ b/src/Components/Modules/Auth.cpp @@ -511,7 +511,7 @@ namespace Components if (!Dedicated::IsEnabled() && !ZoneBuilder::IsEnabled()) { - Command::Add("securityLevel", [](Command::Params* params) + Command::Add("securityLevel", [](const Command::Params* params) { if (params->size() < 2) { diff --git a/src/Components/Modules/Bans.cpp b/src/Components/Modules/Bans.cpp index ae3be8af..69cc4e6e 100644 --- a/src/Components/Modules/Bans.cpp +++ b/src/Components/Modules/Bans.cpp @@ -232,9 +232,9 @@ namespace Components SaveBans(&list); } - Bans::Bans() + void Bans::AddServerCommands() { - Command::Add("banClient", [](Command::Params* params) + Command::AddSV("banClient", [](const Command::Params* params) { if (!Dedicated::IsRunning()) { @@ -278,11 +278,11 @@ namespace Components return; } - const std::string reason = params->size() < 3 ? "EXE_ERR_BANNED_PERM" : params->join(2); + const auto reason = params->size() < 3 ? "EXE_ERR_BANNED_PERM"s : params->join(2); BanClient(cl, reason); }); - Command::Add("unbanClient", [](Command::Params* params) + Command::AddSV("unbanClient", [](const Command::Params* params) { if (!Dedicated::IsRunning()) { @@ -317,4 +317,9 @@ namespace Components } }); } + + Bans::Bans() + { + Events::OnSVInit(AddServerCommands); + } } diff --git a/src/Components/Modules/Bans.hpp b/src/Components/Modules/Bans.hpp index 8545d94b..61aa981b 100644 --- a/src/Components/Modules/Bans.hpp +++ b/src/Components/Modules/Bans.hpp @@ -29,5 +29,7 @@ namespace Components static void LoadBans(BanList* list); static void SaveBans(const BanList* list); + + static void AddServerCommands(); }; } diff --git a/src/Components/Modules/Bots.cpp b/src/Components/Modules/Bots.cpp index cad90b55..ee8c6397 100644 --- a/src/Components/Modules/Bots.cpp +++ b/src/Components/Modules/Bots.cpp @@ -407,37 +407,9 @@ namespace Components } } - Bots::Bots() + void Bots::AddServerCommands() { - AssertOffset(Game::client_s, bIsTestClient, 0x41AF0); - AssertOffset(Game::client_s, ping, 0x212C8); - AssertOffset(Game::client_s, gentity, 0x212A0); - - // Replace connect string - Utils::Hook::Set(0x48ADA6, "connect bot%d \"\\cg_predictItems\\1\\cl_anonymous\\0\\color\\4\\head\\default\\model\\multi\\snaps\\20\\rate\\5000\\name\\%s\\clanAbbrev\\%s\\protocol\\%d\\checksum\\%d\\statver\\%d %u\\qport\\%d\""); - - // Intercept sprintf for the connect string - Utils::Hook(0x48ADAB, BuildConnectString, HOOK_CALL).install()->quick(); - - Utils::Hook(0x627021, SV_BotUserMove_Hk, HOOK_CALL).install()->quick(); - Utils::Hook(0x627241, SV_BotUserMove_Hk, HOOK_CALL).install()->quick(); - - Utils::Hook(0x441B80, G_SelectWeaponIndex_Hk, HOOK_JUMP).install()->quick(); - - Utils::Hook(0x459654, SV_GetClientPing_Hk, HOOK_CALL).install()->quick(); - - sv_randomBotNames = Game::Dvar_RegisterBool("sv_randomBotNames", false, Game::DVAR_NONE, "Randomize the bots' names"); - sv_replaceBots = Game::Dvar_RegisterBool("sv_replaceBots", false, Game::DVAR_NONE, "Test clients will be replaced by connecting players when the server is full."); - - // Reset BotMovementInfo.active when client is dropped - Events::OnClientDisconnect([](const int clientNum) -> void - { - g_botai[clientNum].active = false; - }); - - CleanBotArray(); - - Command::Add("spawnBot", [](Command::Params* params) + Command::AddSV("spawnBot", [](const Command::Params* params) { if (!Dedicated::IsRunning()) { @@ -467,8 +439,7 @@ namespace Components if (input == end) { - Logger::Warning(Game::CON_CHANNEL_DONT_FILTER, "{} is not a valid input\nUsage: {} optional or optional <\"all\">\n", - input, params->get(0)); + Logger::Warning(Game::CON_CHANNEL_DONT_FILTER, "{} is not a valid input\nUsage: {} optional or optional <\"all\">\n", input, params->get(0)); return; } } @@ -480,6 +451,39 @@ namespace Components Spawn(count); }); + } + + Bots::Bots() + { + AssertOffset(Game::client_s, bIsTestClient, 0x41AF0); + AssertOffset(Game::client_s, ping, 0x212C8); + AssertOffset(Game::client_s, gentity, 0x212A0); + + // Replace connect string + Utils::Hook::Set(0x48ADA6, "connect bot%d \"\\cg_predictItems\\1\\cl_anonymous\\0\\color\\4\\head\\default\\model\\multi\\snaps\\20\\rate\\5000\\name\\%s\\clanAbbrev\\%s\\protocol\\%d\\checksum\\%d\\statver\\%d %u\\qport\\%d\""); + + // Intercept sprintf for the connect string + Utils::Hook(0x48ADAB, BuildConnectString, HOOK_CALL).install()->quick(); + + Utils::Hook(0x627021, SV_BotUserMove_Hk, HOOK_CALL).install()->quick(); + Utils::Hook(0x627241, SV_BotUserMove_Hk, HOOK_CALL).install()->quick(); + + Utils::Hook(0x441B80, G_SelectWeaponIndex_Hk, HOOK_JUMP).install()->quick(); + + Utils::Hook(0x459654, SV_GetClientPing_Hk, HOOK_CALL).install()->quick(); + + sv_randomBotNames = Game::Dvar_RegisterBool("sv_randomBotNames", false, Game::DVAR_NONE, "Randomize the bots' names"); + sv_replaceBots = Game::Dvar_RegisterBool("sv_replaceBots", false, Game::DVAR_NONE, "Test clients will be replaced by connecting players when the server is full."); + + // Reset BotMovementInfo.active when client is dropped + Events::OnClientDisconnect([](const int clientNum) -> void + { + g_botai[clientNum].active = false; + }); + + Events::OnSVInit(AddServerCommands); + + CleanBotArray(); AddScriptMethods(); diff --git a/src/Components/Modules/Bots.hpp b/src/Components/Modules/Bots.hpp index 81a38bb8..30925db3 100644 --- a/src/Components/Modules/Bots.hpp +++ b/src/Components/Modules/Bots.hpp @@ -36,5 +36,7 @@ namespace Components static bool IsFull(); static void CleanBotArray(); + + static void AddServerCommands(); }; } diff --git a/src/Components/Modules/CardTitles.cpp b/src/Components/Modules/CardTitles.cpp index d3e44442..3ff49ffb 100644 --- a/src/Components/Modules/CardTitles.cpp +++ b/src/Components/Modules/CardTitles.cpp @@ -202,7 +202,7 @@ namespace Components std::memset(&CustomTitles, 0, sizeof(char[Game::MAX_CLIENTS][18])); - ServerCommands::OnCommand(21, [](Command::Params* params) + ServerCommands::OnCommand(21, [](const Command::Params* params) { if (std::strcmp(params->get(1), "customTitles") == 0) { @@ -214,7 +214,6 @@ namespace Components } return false; - }); Utils::Hook(0x62EB26, GetPlayerCardClientInfoStub).install()->quick(); diff --git a/src/Components/Modules/Chat.cpp b/src/Components/Modules/Chat.cpp index 5b7ecf38..3ace57fc 100644 --- a/src/Components/Modules/Chat.cpp +++ b/src/Components/Modules/Chat.cpp @@ -380,9 +380,9 @@ namespace Components }); } - void Chat::AddChatCommands() + void Chat::AddServerCommands() { - Command::AddSV("muteClient", [](Command::Params* params) + Command::AddSV("muteClient", [](const Command::Params* params) { if (!Dedicated::IsRunning()) { @@ -405,7 +405,7 @@ namespace Components } }); - Command::AddSV("unmute", [](Command::Params* params) + Command::AddSV("unmute", [](const Command::Params* params) { if (!Dedicated::IsRunning()) { @@ -446,7 +446,7 @@ namespace Components } }); - Command::AddSV("say", [](Command::Params* params) + Command::AddSV("say", [](const Command::Params* params) { if (!Dedicated::IsRunning()) { @@ -471,7 +471,7 @@ namespace Components } }); - Command::AddSV("tell", [](Command::Params* params) + Command::AddSV("tell", [](const Command::Params* params) { if (!Dedicated::IsRunning()) { @@ -499,7 +499,7 @@ namespace Components } }); - Command::AddSV("sayraw", [](Command::Params* params) + Command::AddSV("sayraw", [](const Command::Params* params) { if (!Dedicated::IsRunning()) { @@ -514,7 +514,7 @@ namespace Components Logger::Print("Raw: {}\n", message); }); - Command::AddSV("tellraw", [](Command::Params* params) + Command::AddSV("tellraw", [](const Command::Params* params) { if (!Dedicated::IsRunning()) { @@ -610,7 +610,7 @@ namespace Components cg_chatWidth = Dvar::Register("cg_chatWidth", 52, 1, std::numeric_limits::max(), Game::DVAR_ARCHIVE, "The normalized maximum width of a chat message"); sv_disableChat = Dvar::Register("sv_disableChat", false, Game::DVAR_NONE, "Disable chat messages from clients"); - Events::OnSVInit(AddChatCommands); + Events::OnSVInit(AddServerCommands); LoadMutedList(); @@ -622,6 +622,12 @@ namespace Components // Change logic that does word splitting with new lines for chat messages to support fonticons Utils::Hook(0x592E10, CG_AddToTeamChat_Stub, HOOK_JUMP).install()->quick(); + // Add back removed command from CoD4 + Command::Add("mp_QuickMessage", []() -> void + { + Command::Execute("openmenu quickmessage"); + }); + AddScriptFunctions(); // Avoid duplicates diff --git a/src/Components/Modules/Chat.hpp b/src/Components/Modules/Chat.hpp index 5a33d118..b054f468 100644 --- a/src/Components/Modules/Chat.hpp +++ b/src/Components/Modules/Chat.hpp @@ -42,7 +42,7 @@ namespace Components static void SaveMutedList(const muteList& list); static void LoadMutedList(); - static void AddChatCommands(); + static void AddServerCommands(); static int GetCallbackReturn(); static int ChatCallback(Game::gentity_s* self, const char* codePos, const char* message, int mode); diff --git a/src/Components/Modules/ClanTags.cpp b/src/Components/Modules/ClanTags.cpp index 2dd4a956..8e049e3c 100644 --- a/src/Components/Modules/ClanTags.cpp +++ b/src/Components/Modules/ClanTags.cpp @@ -240,7 +240,7 @@ namespace Components std::memset(&ClientState, 0, sizeof(char[Game::MAX_CLIENTS][MAX_CLAN_NAME_LENGTH])); - ServerCommands::OnCommand(22, [](Command::Params* params) + ServerCommands::OnCommand(22, [](const Command::Params* params) { if (std::strcmp(params->get(1), "clanNames") == 0) { diff --git a/src/Components/Modules/Command.cpp b/src/Components/Modules/Command.cpp index c4a0e4ff..8ff9a88b 100644 --- a/src/Components/Modules/Command.cpp +++ b/src/Components/Modules/Command.cpp @@ -2,8 +2,8 @@ namespace Components { - std::unordered_map> Command::FunctionMap; - std::unordered_map> Command::FunctionMapSV; + std::unordered_map Command::FunctionMap; + std::unordered_map Command::FunctionMapSV; std::string Command::Params::join(const int index) const { @@ -68,7 +68,7 @@ namespace Components }); } - void Command::Add(const char* name, const std::function& callback) + void Command::Add(const char* name, const commandCallback& callback) { const auto command = Utils::String::ToLower(name); @@ -80,7 +80,7 @@ namespace Components FunctionMap.insert_or_assign(command, callback); } - void Command::AddSV(const char* name, const std::function& callback) + void Command::AddSV(const char* name, const commandCallback& callback) { if (Loader::IsPregame()) { diff --git a/src/Components/Modules/Command.hpp b/src/Components/Modules/Command.hpp index 41cb5ec9..5b6477fc 100644 --- a/src/Components/Modules/Command.hpp +++ b/src/Components/Modules/Command.hpp @@ -54,19 +54,21 @@ namespace Components Command(); - static Game::cmd_function_s* Allocate(); + using commandCallback = std::function; static void Add(const char* name, const std::function& callback); - static void Add(const char* name, const std::function& callback); + static void Add(const char* name, const commandCallback& callback); static void AddRaw(const char* name, void(*callback)(), bool key = false); - static void AddSV(const char* name, const std::function& callback); + static void AddSV(const char* name, const commandCallback& callback); static void Execute(std::string command, bool sync = true); static Game::cmd_function_s* Find(const std::string& command); private: - static std::unordered_map> FunctionMap; - static std::unordered_map> FunctionMapSV; + static std::unordered_map FunctionMap; + static std::unordered_map FunctionMapSV; + + static Game::cmd_function_s* Allocate(); static void AddRawSV(const char* name, void(*callback)()); diff --git a/src/Components/Modules/Debug.cpp b/src/Components/Modules/Debug.cpp index a5c66fb3..768bb510 100644 --- a/src/Components/Modules/Debug.cpp +++ b/src/Components/Modules/Debug.cpp @@ -272,7 +272,7 @@ namespace Components assert(0 && "a"); } - void Debug::Com_Bug_f(Command::Params* params) + void Debug::Com_Bug_f(const Command::Params* params) { char newFileName[MAX_PATH]{}; char to_ospath[MAX_OSPATH]{}; diff --git a/src/Components/Modules/Debug.hpp b/src/Components/Modules/Debug.hpp index 57691886..fe83cf7a 100644 --- a/src/Components/Modules/Debug.hpp +++ b/src/Components/Modules/Debug.hpp @@ -40,7 +40,7 @@ namespace Components static void CG_DrawDebugOverlays_Hk(int localClientNum); static void Com_Assert_f(); - static void Com_Bug_f(Command::Params* params); + static void Com_Bug_f(const Command::Params* params); static void Com_BugNameInc_f(); static void CL_InitDebugDvars(); diff --git a/src/Components/Modules/Dedicated.cpp b/src/Components/Modules/Dedicated.cpp index 100a1ab2..e2e5b2e8 100644 --- a/src/Components/Modules/Dedicated.cpp +++ b/src/Components/Modules/Dedicated.cpp @@ -267,7 +267,6 @@ namespace Components Game::DvarValue value; value.integer = 0; Game::Dvar_SetVariant(const_cast(com_dedicated), value, Game::DVAR_SOURCE_INTERNAL); - } }); @@ -291,14 +290,10 @@ namespace Components } else { - for (int i = 0; i < ARRAYSIZE(PlayerGuids); ++i) - { - PlayerGuids[i][0].bits = 0; - PlayerGuids[i][1].bits = 0; - } + ZeroMemory(PlayerGuids, sizeof(PlayerGuids)); // Intercept server commands - ServerCommands::OnCommand(20, [](Command::Params* params) + ServerCommands::OnCommand(20, [](const Command::Params* params) { for (int client = 0; client < 18; client++) { diff --git a/src/Components/Modules/FastFiles.cpp b/src/Components/Modules/FastFiles.cpp index e56732f1..d2a35cbd 100644 --- a/src/Components/Modules/FastFiles.cpp +++ b/src/Components/Modules/FastFiles.cpp @@ -609,7 +609,7 @@ namespace Components }, Scheduler::Pipeline::RENDERER); } - Command::Add("loadzone", [](Command::Params* params) + Command::Add("loadzone", [](const Command::Params* params) { if (params->size() < 2) return; @@ -621,7 +621,7 @@ namespace Components Game::DB_LoadXAssets(&info, 1, true); }); - Command::Add("awaitDatabase", [](Command::Params*) + Command::Add("awaitDatabase", []() { Logger::Print("Waiting for database...\n"); while (!Game::Sys_IsDatabaseReady()) std::this_thread::sleep_for(100ms); diff --git a/src/Components/Modules/Friends.cpp b/src/Components/Modules/Friends.cpp index dea87d13..8f884641 100644 --- a/src/Components/Modules/Friends.cpp +++ b/src/Components/Modules/Friends.cpp @@ -461,21 +461,6 @@ namespace Components Friends::CurrentFriend = index; } - void Friends::AddFriend(SteamID user) - { - if (Steam::Proxy::ClientFriends && Steam::Proxy::SteamFriends) - { - if (Steam::Proxy::ClientFriends.invoke("AddFriend", user)) - { - Toast::Show("cardicon_joystick", Steam::Proxy::SteamFriends->GetFriendPersonaName(user), "friend request sent", 3000); - } - else - { - Toast::Show("cardicon_stop", Steam::Proxy::SteamFriends->GetFriendPersonaName(user), "unable to send friend request", 3000); - } - } - } - int Friends::GetGame(SteamID user) { int appId = 0; @@ -574,20 +559,6 @@ namespace Components Friends::CLAnonymous = Dvar::Register("cl_anonymous", false, Game::DVAR_ARCHIVE, "Enable invisible mode for Steam"); Friends::CLNotifyFriendState = Dvar::Register("cl_notifyFriendState", true, Game::DVAR_ARCHIVE, "Update friends about current game status"); - Command::Add("addFriend", [](Command::Params* params) - { - if (params->size() < 2) - { - Logger::Print("Usage: {} \n", params->get(0)); - return; - } - - SteamID id; - id.bits = std::strtoull(params->get(1), nullptr, 16); - - Friends::AddFriend(id); - }); - // Hook Live_ShowFriendsList Utils::Hook(0x4D6C70, []() { diff --git a/src/Components/Modules/Friends.hpp b/src/Components/Modules/Friends.hpp index 4bc0075f..e59cfdab 100644 --- a/src/Components/Modules/Friends.hpp +++ b/src/Components/Modules/Friends.hpp @@ -19,8 +19,6 @@ namespace Components static void RequestPresence(SteamID user); static std::string GetPresence(SteamID user, const std::string& key); - static void AddFriend(SteamID user); - static int GetGame(SteamID user); static bool IsInvisible(); diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index b7552c67..0fe01d91 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -1760,7 +1760,7 @@ namespace Components return Game::GPAD_MAP_NONE; } - void Gamepad::Axis_Bind_f(Command::Params* params) + void Gamepad::Axis_Bind_f(const Command::Params* params) { if (params->size() < 4) { @@ -1796,7 +1796,7 @@ namespace Components Gamepad_BindAxis(0, physicalAxis, virtualAxis, mapping); } - void Gamepad::Axis_Unbindall_f(Command::Params*) + void Gamepad::Axis_Unbindall_f() { auto& gamePadGlobal = gamePadGlobals[0]; @@ -1807,19 +1807,19 @@ namespace Components } } - void Gamepad::Bind_GP_SticksConfigs_f(Command::Params*) + void Gamepad::Bind_GP_SticksConfigs_f() { const auto* stickConfigName = gpad_sticksConfig.get(); Game::Cbuf_AddText(0, Utils::String::VA("exec %s\n", stickConfigName)); } - void Gamepad::Bind_GP_ButtonsConfigs_f(Command::Params*) + void Gamepad::Bind_GP_ButtonsConfigs_f() { const auto* buttonConfigName = gpad_buttonConfig.get(); Game::Cbuf_AddText(0, Utils::String::VA("exec %s\n", buttonConfigName)); } - void Gamepad::Scores_Toggle_f(Command::Params*) + void Gamepad::Scores_Toggle_f() { if (Game::cgArray[0].nextSnap) { diff --git a/src/Components/Modules/Gamepad.hpp b/src/Components/Modules/Gamepad.hpp index 5ff132d2..3409d80c 100644 --- a/src/Components/Modules/Gamepad.hpp +++ b/src/Components/Modules/Gamepad.hpp @@ -184,11 +184,11 @@ namespace Components static Game::GamepadPhysicalAxis StringToPhysicalAxis(const char* str); static Game::GamepadVirtualAxis StringToVirtualAxis(const char* str); static Game::GamepadMapping StringToGamePadMapping(const char* str); - static void Axis_Bind_f(Command::Params* params); - static void Axis_Unbindall_f(Command::Params* params); - static void Bind_GP_SticksConfigs_f(Command::Params* params); - static void Bind_GP_ButtonsConfigs_f(Command::Params* params); - static void Scores_Toggle_f(Command::Params* params); + static void Axis_Bind_f(const Command::Params* params); + static void Axis_Unbindall_f(); + static void Bind_GP_SticksConfigs_f(); + static void Bind_GP_ButtonsConfigs_f(); + static void Scores_Toggle_f(); static void InitDvars(); static void CG_RegisterDvars_Hk(); diff --git a/src/Components/Modules/IPCPipe.cpp b/src/Components/Modules/IPCPipe.cpp index 64d9a31d..f14132d7 100644 --- a/src/Components/Modules/IPCPipe.cpp +++ b/src/Components/Modules/IPCPipe.cpp @@ -225,7 +225,7 @@ namespace Components }); // Test pipe functionality by sending pings - Command::Add("ipcping", []([[maybe_unused]] Command::Params* params) + Command::Add("ipcping", []() { Logger::Print("Sending ping to pipe!\n"); Write("ping", {}); diff --git a/src/Components/Modules/Logger.cpp b/src/Components/Modules/Logger.cpp index 851b04ea..033f377b 100644 --- a/src/Components/Modules/Logger.cpp +++ b/src/Components/Modules/Logger.cpp @@ -274,20 +274,20 @@ namespace Components void Logger::AddServerCommands() { - Command::AddSV("log_add", [](Command::Params* params) + Command::AddSV("log_add", [](const Command::Params* params) { if (params->size() < 2) return; std::unique_lock lock(LoggingMutex); Network::Address addr(params->get(1)); - if (std::find(LoggingAddresses[0].begin(), LoggingAddresses[0].end(), addr) == LoggingAddresses[0].end()) + if (std::ranges::find(LoggingAddresses[0], addr) == LoggingAddresses[0].end()) { LoggingAddresses[0].push_back(addr); } }); - Command::AddSV("log_del", [](Command::Params* params) + Command::AddSV("log_del", [](const Command::Params* params) { if (params->size() < 2) return; @@ -304,8 +304,7 @@ namespace Components { Network::Address addr(params->get(1)); - const auto i = std::find(LoggingAddresses[0].begin(), LoggingAddresses[0].end(), addr); - if (i != LoggingAddresses[0].end()) + if (const auto i = std::ranges::find(LoggingAddresses[0], addr); i != LoggingAddresses[0].end()) { LoggingAddresses[0].erase(i); Print("Address {} removed\n", addr.getString()); @@ -317,7 +316,7 @@ namespace Components } }); - Command::AddSV("log_list", []([[maybe_unused]] Command::Params* params) + Command::AddSV("log_list", []([[maybe_unused]] const Command::Params* params) { Print("# ID: Address\n"); Print("-------------\n"); @@ -330,20 +329,20 @@ namespace Components } }); - Command::AddSV("g_log_add", [](Command::Params* params) + Command::AddSV("g_log_add", [](const Command::Params* params) { if (params->size() < 2) return; std::unique_lock lock(LoggingMutex); const Network::Address addr(params->get(1)); - if (std::find(LoggingAddresses[1].begin(), LoggingAddresses[1].end(), addr) == LoggingAddresses[1].end()) + if (std::ranges::find(LoggingAddresses[1], addr) == LoggingAddresses[1].end()) { LoggingAddresses[1].push_back(addr); } }); - Command::AddSV("g_log_del", [](Command::Params* params) + Command::AddSV("g_log_del", [](const Command::Params* params) { if (params->size() < 2) return; @@ -372,7 +371,7 @@ namespace Components } }); - Command::AddSV("g_log_list", [](Command::Params*) + Command::AddSV("g_log_list", []([[maybe_unused]] const Command::Params* params) { Print("# ID: Address\n"); Print("-------------\n"); diff --git a/src/Components/Modules/MapDump.cpp b/src/Components/Modules/MapDump.cpp index db84fa6e..c4dc4bcc 100644 --- a/src/Components/Modules/MapDump.cpp +++ b/src/Components/Modules/MapDump.cpp @@ -434,7 +434,7 @@ namespace Components MapDump::MapDump() { - Command::Add("dumpmap", [](Command::Params*) + Command::Add("dumpmap", []() { if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled()) { diff --git a/src/Components/Modules/MapRotation.cpp b/src/Components/Modules/MapRotation.cpp index e3f109ff..0d8f463a 100644 --- a/src/Components/Modules/MapRotation.cpp +++ b/src/Components/Modules/MapRotation.cpp @@ -176,7 +176,7 @@ namespace Components void MapRotation::AddMapRotationCommands() { - Command::AddSV("addMap", [](Command::Params* params) + Command::AddSV("addMap", [](const Command::Params* params) { if (params->size() < 2) { @@ -187,7 +187,7 @@ namespace Components DedicatedRotation.addEntry("map", params->get(1)); }); - Command::AddSV("addGametype", [](Command::Params* params) + Command::AddSV("addGametype", [](const Command::Params* params) { if (params->size() < 2) { diff --git a/src/Components/Modules/Maps.cpp b/src/Components/Modules/Maps.cpp index 072319f5..46ff7ff4 100644 --- a/src/Components/Modules/Maps.cpp +++ b/src/Components/Modules/Maps.cpp @@ -838,7 +838,7 @@ namespace Components Utils::Hook(0x5A9D51, Maps::LoadMapLoadscreenStub, HOOK_CALL).install()->quick(); Utils::Hook(0x5B34DD, Maps::LoadMapLoadscreenStub, HOOK_CALL).install()->quick(); - Command::Add("delayReconnect", []([[maybe_unused]] Command::Params* params) + Command::Add("delayReconnect", []() { Scheduler::Once([] { @@ -852,7 +852,7 @@ namespace Components Utils::Hook(0x4A7251, Maps::LoadNewMapCommand, HOOK_CALL).install()->quick(); } - // Download the map before a maprotation if necessary + // Download the map before a map rotation if necessary // Conflicts with Theater's SV map rotation check, but this one is safer! Utils::Hook(0x5AA91C, Maps::RotateCheckStub, HOOK_CALL).install()->quick(); diff --git a/src/Components/Modules/Menus.cpp b/src/Components/Modules/Menus.cpp index 0328a1bd..44f58e10 100644 --- a/src/Components/Modules/Menus.cpp +++ b/src/Components/Modules/Menus.cpp @@ -828,7 +828,7 @@ namespace Components // make Com_Error and similar go back to main_text instead of menu_xboxlive. Utils::Hook::SetString(0x6FC790, "main_text"); - Command::Add("openmenu", [](Command::Params* params) + Command::Add("openmenu", [](const Command::Params* params) { if (params->size() != 2) { @@ -845,7 +845,7 @@ namespace Components Game::Menus_OpenByName(Game::uiContext, params->get(1)); }); - Command::Add("reloadmenus", []([[maybe_unused]] Command::Params* params) + Command::Add("reloadmenus", []() { // Close all menus Game::Menus_CloseAll(Game::uiContext); @@ -868,11 +868,6 @@ namespace Components } }); - Command::Add("mp_QuickMessage", [](Command::Params*) - { - Command::Execute("openmenu quickmessage"); - }); - // Define custom menus here Add("ui_mp/changelog.menu"); Add("ui_mp/theater_menu.menu"); diff --git a/src/Components/Modules/Network.cpp b/src/Components/Modules/Network.cpp index 76746907..53e74399 100644 --- a/src/Components/Modules/Network.cpp +++ b/src/Components/Modules/Network.cpp @@ -341,6 +341,33 @@ namespace Components } } + int Network::Sys_StringToSockaddr_Hk(const char* s, sockaddr* sadr) + { + hostent* h; + ZeroMemory(sadr, sizeof(*sadr)); + + ((sockaddr_in*)sadr)->sin_family = AF_INET; + ((sockaddr_in*)sadr)->sin_port = 0; + + if (Game::I_isdigit(*s)) + { + // ReSharper disable once CppDeprecatedEntity + *(int*)&((sockaddr_in*)sadr)->sin_addr = static_cast(::inet_addr(s)); + } + else + { + // ReSharper disable once CppDeprecatedEntity + if ((h = ::gethostbyname(s)) == nullptr) + { + return false; + } + + *(int*)&((sockaddr_in*)sadr)->sin_addr = *(int*)h->h_addr_list[0]; + } + + return true; + } + Network::Network() { AssertSize(Game::netadr_t, 20); @@ -374,6 +401,10 @@ namespace Components // Handle client packets Utils::Hook(0x5AA703, CL_HandleCommandStub, HOOK_JUMP).install()->quick(); + // Use the version of Sys_StringToSockaddr made by 3arc + Utils::Hook(0x44E23C, Sys_StringToSockaddr_Hk, HOOK_CALL).install()->quick(); + Utils::Hook(0x64D480, Sys_StringToSockaddr_Hk, HOOK_CALL).install()->quick(); + // Disable unused OOB packets handlers just to be sure Utils::Hook::Set(0x5AA5B6, 0xEB); // CL_SteamServerAuth Utils::Hook::Set(0x5AA69F, 0xEB); // echo @@ -413,6 +444,7 @@ namespace Components auto* clc = Game::CL_GetLocalClientConnection(0); if (!Game::NET_CompareBaseAdr(clc->serverAddress, *address)) { + Logger::Debug("Ignoring stray 'print' network message from '{}'", Game::NET_AdrToString(*address)); return; } diff --git a/src/Components/Modules/Network.hpp b/src/Components/Modules/Network.hpp index 547628ed..d9e2e020 100644 --- a/src/Components/Modules/Network.hpp +++ b/src/Components/Modules/Network.hpp @@ -89,6 +89,8 @@ namespace Components static bool CL_HandleCommand(Game::netadr_t* address, const char* command, Game::msg_t* message); static void CL_HandleCommandStub(); + + static int Sys_StringToSockaddr_Hk(const char* s, sockaddr* sadr); }; } diff --git a/src/Components/Modules/Node.cpp b/src/Components/Modules/Node.cpp index cb122cc7..2e655361 100644 --- a/src/Components/Modules/Node.cpp +++ b/src/Components/Modules/Node.cpp @@ -13,7 +13,7 @@ namespace Components std::recursive_mutex Node::Mutex; std::vector Node::Nodes; - bool Node::wasIngame = false; + bool Node::WasIngame = false; bool Node::Entry::isValid() { @@ -154,14 +154,14 @@ namespace Components { if (ServerList::UseMasterServer) return; // don't run node frame if master server is active - if (*Game::clcState > 0) + if (Game::CL_GetLocalClientConnectionState(0) != Game::CA_DISCONNECTED) { - wasIngame = true; - return; // don't run while ingame because it can still cause lag spikes on lower end PCs + WasIngame = true; + return; // don't run while in-game because it can still cause lag spikes on lower end PCs } } - if (wasIngame) // our last frame we were ingame and now we aren't so touch all nodes + if (WasIngame) // our last frame we were in-game and now we aren't so touch all nodes { for (auto i = Node::Nodes.begin(); i != Node::Nodes.end();++i) { @@ -170,7 +170,8 @@ namespace Components i->lastRequest.reset(); i->lastResponse.reset(); } - wasIngame = false; + + WasIngame = false; } static Utils::Time::Interval frameLimit; @@ -344,7 +345,7 @@ namespace Components Scheduler::OnGameInitialized(loadNodes, Scheduler::Pipeline::MAIN); - Command::Add("listnodes", [](Command::Params*) + Command::Add("listnodes", [](const Command::Params*) { Logger::Print("Nodes: {}\n", Node::Nodes.size()); @@ -355,7 +356,7 @@ namespace Components } }); - Command::Add("addnode", [](Command::Params* params) + Command::Add("addnode", [](const Command::Params* params) { if (params->size() < 2) return; Node::Add({ params->get(1) }); diff --git a/src/Components/Modules/Node.hpp b/src/Components/Modules/Node.hpp index e6e992ad..35623d52 100644 --- a/src/Components/Modules/Node.hpp +++ b/src/Components/Modules/Node.hpp @@ -44,7 +44,7 @@ namespace Components private: static std::recursive_mutex Mutex; static std::vector Nodes; - static bool wasIngame; + static bool WasIngame; static void HandleResponse(Network::Address address, const std::string& data); diff --git a/src/Components/Modules/Party.cpp b/src/Components/Modules/Party.cpp index 0c85560f..8dfad7db 100644 --- a/src/Components/Modules/Party.cpp +++ b/src/Components/Modules/Party.cpp @@ -293,7 +293,7 @@ namespace Components Utils::Hook::Xor(0x4D376D, Game::DVAR_LATCH); Utils::Hook::Xor(0x5E3789, Game::DVAR_LATCH); - Command::Add("connect", [](Command::Params* params) + Command::Add("connect", [](const Command::Params* params) { if (params->size() < 2) { @@ -311,7 +311,7 @@ namespace Components } }); - Command::Add("reconnect", [](Command::Params*) + Command::Add("reconnect", []() { Connect(Container.target); }); diff --git a/src/Components/Modules/QuickPatch.cpp b/src/Components/Modules/QuickPatch.cpp index b4086ff9..c8c900cf 100644 --- a/src/Components/Modules/QuickPatch.cpp +++ b/src/Components/Modules/QuickPatch.cpp @@ -522,7 +522,7 @@ namespace Components Command::Add("unlockstats", QuickPatch::UnlockStats); - Command::Add("dumptechsets", [](Command::Params* param) + Command::Add("dumptechsets", [](const Command::Params* param) { if (param->size() != 2) { diff --git a/src/Components/Modules/RCon.cpp b/src/Components/Modules/RCon.cpp index 70b8e785..d7074420 100644 --- a/src/Components/Modules/RCon.cpp +++ b/src/Components/Modules/RCon.cpp @@ -21,7 +21,7 @@ namespace Components void RCon::AddCommands() { - Command::Add("rcon", [](Command::Params* params) + Command::Add("rcon", [](const Command::Params* params) { if (params->size() < 2) return; @@ -60,7 +60,7 @@ namespace Components Logger::Print("You are connected to an invalid server\n"); }); - Command::Add("remoteCommand", [](Command::Params* params) + Command::Add("remoteCommand", [](const Command::Params* params) { if (params->size() < 2) return; @@ -79,7 +79,7 @@ namespace Components } }); - Command::AddSV("RconWhitelistAdd", [](Command::Params* params) + Command::AddSV("RconWhitelistAdd", [](const Command::Params* params) { if (params->size() < 2) { diff --git a/src/Components/Modules/RawFiles.cpp b/src/Components/Modules/RawFiles.cpp index d914d38d..aecb2cde 100644 --- a/src/Components/Modules/RawFiles.cpp +++ b/src/Components/Modules/RawFiles.cpp @@ -124,7 +124,7 @@ namespace Components Utils::Hook(0x631640, GetMenuBuffer, HOOK_JUMP).install()->quick(); Utils::Hook(0x463500, Com_LoadInfoString_Hk, HOOK_JUMP).install()->quick(); - Command::Add("dumpraw", [](Command::Params* params) + Command::Add("dumpraw", [](const Command::Params* params) { if (params->size() < 2) { @@ -140,7 +140,7 @@ namespace Components return; } - const char* data = Game::Scr_AddSourceBuffer(nullptr, file.getName().data(), nullptr, false); + const auto* data = Game::Scr_AddSourceBuffer(nullptr, file.getName().data(), nullptr, false); if (data) { diff --git a/src/Components/Modules/ServerCommands.hpp b/src/Components/Modules/ServerCommands.hpp index ee46e676..3d8002b8 100644 --- a/src/Components/Modules/ServerCommands.hpp +++ b/src/Components/Modules/ServerCommands.hpp @@ -7,7 +7,7 @@ namespace Components public: ServerCommands(); - using serverCommandHandler = std::function; + using serverCommandHandler = std::function; static void OnCommand(std::int32_t cmd, const serverCommandHandler& callback); private: diff --git a/src/Components/Modules/Stats.cpp b/src/Components/Modules/Stats.cpp index 9472a1d0..d23739a6 100644 --- a/src/Components/Modules/Stats.cpp +++ b/src/Components/Modules/Stats.cpp @@ -162,7 +162,7 @@ namespace Components Utils::Hook::Set(0x4CC5F9, 0xEB); // 'M' Seems to be used on Xbox only for parsing platform specific ranks - ServerCommands::OnCommand('M', [](Command::Params* params) + ServerCommands::OnCommand('M', [](const Command::Params* params) { const auto* arg1 = params->get(1); const auto* arg2 = params->get(2); @@ -171,7 +171,7 @@ namespace Components return true; }); - Command::Add("statGet", []([[maybe_unused]] Command::Params* params) + Command::Add("statGet", [](const Command::Params* params) { if (params->size() < 2) { diff --git a/src/Components/Modules/StructuredData.cpp b/src/Components/Modules/StructuredData.cpp index e8dd0ca1..121a0f8c 100644 --- a/src/Components/Modules/StructuredData.cpp +++ b/src/Components/Modules/StructuredData.cpp @@ -157,20 +157,6 @@ namespace Components // 15 or more custom classes Utils::Hook::Set(0x60A2FE, NUM_CUSTOM_CLASSES); - -#ifdef _DEBUG - // Reset empty names - Command::Add("checkClasses", [](Command::Params*) - { - for (int i = 0; i < NUM_CUSTOM_CLASSES; ++i) - { - // TODO: Correctly lookup using structured data - char* className = (reinterpret_cast(0x1AD3694) - 4 + 3003 + (64 * i) + 0x29); - if (!*className) strcpy_s(className, 24, Game::SEH_StringEd_GetString(Utils::String::VA("CLASS_SLOT%i", i + 1))); - } - }); -#endif - return; } AssetHandler::OnLoad([](Game::XAssetType type, Game::XAssetHeader asset, const std::string& filename, bool* /*restrict*/) diff --git a/src/Components/Modules/ZoneBuilder.cpp b/src/Components/Modules/ZoneBuilder.cpp index f1c54bf6..6a26a07c 100644 --- a/src/Components/Modules/ZoneBuilder.cpp +++ b/src/Components/Modules/ZoneBuilder.cpp @@ -1211,7 +1211,7 @@ namespace Components } }); - Command::Add("verifyzone", [](Command::Params* params) + Command::Add("verifyzone", [](const Command::Params* params) { if (params->size() < 2) return; @@ -1250,7 +1250,7 @@ namespace Components Logger::Print("\n"); }); - Command::Add("buildzone", [](Command::Params* params) + Command::Add("buildzone", [](const Command::Params* params) { if (params->size() < 2) return; @@ -1260,7 +1260,7 @@ namespace Components Zone(zoneName).build(); }); - Command::Add("buildall", []([[maybe_unused]] Command::Params* params) + Command::Add("buildall", []() { auto path = std::format("{}\\zone_source", (*Game::fs_basepath)->current.string); auto zoneSources = FileSystem::GetSysFileList(path, "csv", false); @@ -1327,7 +1327,7 @@ namespace Components } }); - Command::Add("buildtechsets", [](Command::Params*) + Command::Add("buildtechsets", [](const Command::Params*) { Utils::IO::CreateDir("zone_source/techsets"); Utils::IO::CreateDir("zone/techsets"); @@ -1580,7 +1580,7 @@ namespace Components Zone("techsets/techsets").build(); }); - Command::Add("listassets", [](Command::Params* params) + Command::Add("listassets", [](const Command::Params* params) { if (params->size() < 2) return; Game::XAssetType type = Game::DB_GetXAssetNameType(params->get(1)); @@ -1595,7 +1595,7 @@ namespace Components } }); - Command::Add("loadtempzone", [](Command::Params* params) + Command::Add("loadtempzone", [](const Command::Params* params) { if (params->size() < 2) return; @@ -1609,7 +1609,7 @@ namespace Components } }); - Command::Add("unloadtempzones", [](Command::Params*) + Command::Add("unloadtempzones", [](const Command::Params*) { Game::XZoneInfo info; info.name = nullptr; @@ -1619,7 +1619,7 @@ namespace Components AssetHandler::FindOriginalAsset(Game::XAssetType::ASSET_TYPE_RAWFILE, "default"); // Lock until zone is unloaded }); - Command::Add("materialInfoDump", [](Command::Params*) + Command::Add("materialInfoDump", [](const Command::Params*) { Game::DB_EnumXAssets(Game::ASSET_TYPE_MATERIAL, [](Game::XAssetHeader header, void*) { @@ -1628,7 +1628,7 @@ namespace Components }, nullptr, false); }); - Command::Add("iwiDump", [](Command::Params* params) + Command::Add("iwiDump", [](const Command::Params* params) { if (params->size() < 2) return; diff --git a/src/Components/Modules/Zones.cpp b/src/Components/Modules/Zones.cpp index 115306a5..17226290 100644 --- a/src/Components/Modules/Zones.cpp +++ b/src/Components/Modules/Zones.cpp @@ -1,4 +1,4 @@ -#include +#include #include @@ -3482,7 +3482,7 @@ namespace Components if (ZoneBuilder::IsEnabled()) { - Command::Add("decryptImages", [](Command::Params*) + Command::Add("decryptImages", []() { auto images = FileSystem::GetSysFileList("iw4x/images", "iwi"); Logger::Print("decrypting {} images...\n", images.size()); @@ -3516,7 +3516,7 @@ namespace Components Logger::Print("decrypted {} images!\n", images.size()); }); - Command::Add("decryptSounds", []([[maybe_unused]] Command::Params* params) + Command::Add("decryptSounds", []() { auto sounds = FileSystem::GetSysFileList("iw4x/sound", "iwi"); Logger::Print("decrypting {} sounds...\n", sounds.size()); @@ -3653,13 +3653,6 @@ namespace Components Utils::Hook(0x4597DD, Zones::LoadStatement, HOOK_CALL).install()->quick(); Utils::Hook(0x471A39, Zones::LoadWindowImage, HOOK_JUMP).install()->quick(); - -#ifdef DEBUG - // Easy dirty disk debugging - Utils::Hook::Set(0x4CF7F0, 0xC3CC); - // disable _invoke_watson to allow debugging - Utils::Hook::Set(0x6B9602, 0xCCCC); -#endif } } #pragma optimize( "", on ) diff --git a/src/DllMain.cpp b/src/DllMain.cpp index 1bcf5707..3f92b015 100644 --- a/src/DllMain.cpp +++ b/src/DllMain.cpp @@ -58,12 +58,12 @@ BOOL APIENTRY DllMain(HINSTANCE /*hinstDLL*/, DWORD fdwReason, LPVOID /*lpvReser if (!binary || std::memcmp(binary, BASEGAME_NAME, 14) != 0) #endif { - MessageBoxA(nullptr, - "Failed to load game binary.\n" - "You did not install the iw4x-rawfiles!\n" - "Please use the XLabs launcher to run the game. For support, please visit https://xlabs.dev/support_iw4x_client", - "ERROR", - MB_ICONERROR + MessageBoxA(nullptr, + "Failed to load game binary.\n" + "You did not install the iw4x-rawfiles!\n" + "Please use the XLabs launcher to run the game. For support, please visit https://xlabs.dev/support_iw4x_client", + "ERROR", + MB_ICONERROR ); return FALSE; } diff --git a/src/Game/Client.cpp b/src/Game/Client.cpp index 77a8e6cf..de491e1d 100644 --- a/src/Game/Client.cpp +++ b/src/Game/Client.cpp @@ -58,6 +58,7 @@ namespace Game connstate_t CL_GetLocalClientConnectionState(const int localClientNum) { + AssertOffset(clientUIActive_t, connectionState, 0x9B8); AssertIn(localClientNum, STATIC_MAX_LOCAL_CLIENTS); return clientUIActives[localClientNum].connectionState; diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index 97de97b1..86afc062 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -238,6 +238,7 @@ namespace Game I_strncpyz_t I_strncpyz = I_strncpyz_t(0x4D6F80); I_CleanStr_t I_CleanStr = I_CleanStr_t(0x4AD470); + I_isdigit_t I_isdigit = I_isdigit_t(0x4E71E0); XNAddrToString_t XNAddrToString = XNAddrToString_t(0x452690); @@ -318,8 +319,6 @@ namespace Game infoParm_t* infoParams = reinterpret_cast(0x79D260); // Count 0x1E - clientState_t* clcState = reinterpret_cast(0xB2C540); - GfxScene* scene = reinterpret_cast(0x6944914); Console* con = reinterpret_cast(0x9FCCF8); diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index b694b0b8..843bc7f5 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -554,6 +554,9 @@ namespace Game typedef char*(*I_CleanStr_t)(char* string); extern I_CleanStr_t I_CleanStr; + typedef bool(*I_isdigit_t)(int c); + extern I_isdigit_t I_isdigit; + typedef void(*XNAddrToString_t)(const XNADDR* xnaddr, char* str); extern XNAddrToString_t XNAddrToString; @@ -659,8 +662,6 @@ namespace Game extern infoParm_t* infoParams; - extern clientState_t* clcState; - extern GfxScene* scene; extern Console* con; diff --git a/src/STDInclude.hpp b/src/STDInclude.hpp index aa045a9f..59bbb4ea 100644 --- a/src/STDInclude.hpp +++ b/src/STDInclude.hpp @@ -2,15 +2,11 @@ #ifndef RC_INVOKED -#define VC_EXTRALEAN #define WIN32_LEAN_AND_MEAN #define _CRT_SECURE_NO_WARNINGS +#define _WINSOCK_DEPRECATED_NO_WARNINGS #define _USE_MATH_DEFINES -// Requires Visual Leak Detector plugin: http://vld.codeplex.com/ -#define VLD_FORCE_ENABLE -//#include - #include #include #include From e107b205514d6aa95abc9013acf67c840bdab776 Mon Sep 17 00:00:00 2001 From: Edo Date: Sat, 6 May 2023 15:09:19 +0100 Subject: [PATCH 10/39] [StructuredData]: Fix (#1014) --- src/Components/Modules/AssetHandler.cpp | 64 +++++++++---------- .../Modules/AssetInterfaces/IXModel.hpp | 2 +- .../Modules/AssetInterfaces/IXModelSurfs.hpp | 2 +- src/Components/Modules/StructuredData.cpp | 4 +- 4 files changed, 37 insertions(+), 35 deletions(-) diff --git a/src/Components/Modules/AssetHandler.cpp b/src/Components/Modules/AssetHandler.cpp index 825fb0f0..5995d3c4 100644 --- a/src/Components/Modules/AssetHandler.cpp +++ b/src/Components/Modules/AssetHandler.cpp @@ -47,7 +47,7 @@ namespace Components std::vector> AssetHandler::EmptyAssets; - std::map AssetHandler::TemporaryAssets[Game::XAssetType::ASSET_TYPE_COUNT]; + std::map AssetHandler::TemporaryAssets[Game::ASSET_TYPE_COUNT]; void AssetHandler::RegisterInterface(IAsset* iAsset) { @@ -73,7 +73,7 @@ namespace Components void AssetHandler::ClearTemporaryAssets() { - for (int i = 0; i < Game::XAssetType::ASSET_TYPE_COUNT; ++i) + for (int i = 0; i < Game::ASSET_TYPE_COUNT; ++i) { AssetHandler::TemporaryAssets[i].clear(); } @@ -108,7 +108,7 @@ namespace Components Game::XAssetHeader AssetHandler::FindTemporaryAsset(Game::XAssetType type, const char* filename) { Game::XAssetHeader header = { nullptr }; - if (type >= Game::XAssetType::ASSET_TYPE_COUNT) return header; + if (type >= Game::ASSET_TYPE_COUNT) return header; auto tempPool = &AssetHandler::TemporaryAssets[type]; auto entry = tempPool->find(filename); @@ -224,7 +224,7 @@ namespace Components void AssetHandler::ModifyAsset(Game::XAssetType type, Game::XAssetHeader asset, const std::string& name) { - if (type == Game::XAssetType::ASSET_TYPE_MATERIAL && (name == "gfx_distortion_knife_trail" || name == "gfx_distortion_heat_far" || name == "gfx_distortion_ring_light" || name == "gfx_distortion_heat") && asset.material->info.sortKey >= 43) + if (type == Game::ASSET_TYPE_MATERIAL && (name == "gfx_distortion_knife_trail" || name == "gfx_distortion_heat_far" || name == "gfx_distortion_ring_light" || name == "gfx_distortion_heat") && asset.material->info.sortKey >= 43) { if (Zones::Version() >= VERSION_ALPHA2) { @@ -236,18 +236,18 @@ namespace Components } } - if (type == Game::XAssetType::ASSET_TYPE_MATERIAL && (name == "wc/codo_ui_viewer_black_decal3" || name == "wc/codo_ui_viewer_black_decal2" || name == "wc/hint_arrows01" || name == "wc/hint_arrows02")) + if (type == Game::ASSET_TYPE_MATERIAL && (name == "wc/codo_ui_viewer_black_decal3" || name == "wc/codo_ui_viewer_black_decal2" || name == "wc/hint_arrows01" || name == "wc/hint_arrows02")) { asset.material->info.sortKey = 0xE; } - if (type == Game::XAssetType::ASSET_TYPE_VEHICLE && Zones::Version() >= VERSION_ALPHA2) + if (type == Game::ASSET_TYPE_VEHICLE && Zones::Version() >= VERSION_ALPHA2) { asset.vehDef->turretWeapon = nullptr; } // Fix shader const stuff - if (type == Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET && Zones::Version() >= 359 && Zones::Version() < 448) + if (type == Game::ASSET_TYPE_TECHNIQUE_SET && Zones::Version() >= 359 && Zones::Version() < 448) { for (int i = 0; i < 48; ++i) { @@ -272,7 +272,7 @@ namespace Components } } - if (type == Game::XAssetType::ASSET_TYPE_GFXWORLD && Zones::Version() >= 316) + if (type == Game::ASSET_TYPE_GFXWORLD && Zones::Version() >= 316) { asset.gfxWorld->sortKeyEffectDecal = 39; asset.gfxWorld->sortKeyEffectAuto = 48; @@ -408,7 +408,7 @@ namespace Components ZoneBuilder::Zone::AssetRecursionMarker _(builder); Game::XAssetHeader header = { nullptr }; - if (type >= Game::XAssetType::ASSET_TYPE_COUNT) return header; + if (type >= Game::ASSET_TYPE_COUNT) return header; auto tempPool = &AssetHandler::TemporaryAssets[type]; auto entry = tempPool->find(filename); @@ -476,7 +476,7 @@ namespace Components void AssetHandler::MissingAssetError(int severity, const char* format, const char* type, const char* name) { - if (Dedicated::IsEnabled() && Game::DB_GetXAssetNameType(type) == Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET) return; + if (Dedicated::IsEnabled() && Game::DB_GetXAssetNameType(type) == Game::ASSET_TYPE_TECHNIQUE_SET) return; Utils::Hook::Call(0x4F8C70)(severity, format, type, name); // Print error } @@ -571,37 +571,37 @@ namespace Components AssetHandler::OnLoad([](Game::XAssetType type, Game::XAssetHeader asset, std::string name, bool*) { - if (Dvar::Var("r_noVoid").get() && type == Game::XAssetType::ASSET_TYPE_XMODEL && name == "void") + if (Dvar::Var("r_noVoid").get() && type == Game::ASSET_TYPE_XMODEL && name == "void") { asset.model->numLods = 0; } }); - Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_GAMEWORLD_SP, 1); - Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_IMAGE, ZoneBuilder::IsEnabled() ? 14336 * 2 : 7168); - Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_LOADED_SOUND, 2700 * 2); - Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_FX, 1200 * 2); - Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_LOCALIZE_ENTRY, 14000); - Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_XANIMPARTS, 8192 * 2); - Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_XMODEL, 5125 * 2); - Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_PHYSPRESET, 128); - Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_PIXELSHADER, ZoneBuilder::IsEnabled() ? 0x4000 : 10000); - Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_VERTEXSHADER, ZoneBuilder::IsEnabled() ? 0x2000 : 3072); - Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_MATERIAL, 8192 * 2); - Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_VERTEXDECL, ZoneBuilder::IsEnabled() ? 0x400 : 196); - Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_WEAPON, WEAPON_LIMIT); - Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_STRINGTABLE, 800); - Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_IMPACT_FX, 8); + Game::ReallocateAssetPool(Game::ASSET_TYPE_GAMEWORLD_SP, 1); + Game::ReallocateAssetPool(Game::ASSET_TYPE_IMAGE, ZoneBuilder::IsEnabled() ? 14336 * 2 : 7168); + Game::ReallocateAssetPool(Game::ASSET_TYPE_LOADED_SOUND, 2700 * 2); + Game::ReallocateAssetPool(Game::ASSET_TYPE_FX, 1200 * 2); + Game::ReallocateAssetPool(Game::ASSET_TYPE_LOCALIZE_ENTRY, 14000); + Game::ReallocateAssetPool(Game::ASSET_TYPE_XANIMPARTS, 8192 * 2); + Game::ReallocateAssetPool(Game::ASSET_TYPE_XMODEL, 5125 * 2); + Game::ReallocateAssetPool(Game::ASSET_TYPE_PHYSPRESET, 128); + Game::ReallocateAssetPool(Game::ASSET_TYPE_PIXELSHADER, ZoneBuilder::IsEnabled() ? 0x4000 : 10000); + Game::ReallocateAssetPool(Game::ASSET_TYPE_VERTEXSHADER, ZoneBuilder::IsEnabled() ? 0x2000 : 3072); + Game::ReallocateAssetPool(Game::ASSET_TYPE_MATERIAL, 8192 * 2); + Game::ReallocateAssetPool(Game::ASSET_TYPE_VERTEXDECL, ZoneBuilder::IsEnabled() ? 0x400 : 196); + Game::ReallocateAssetPool(Game::ASSET_TYPE_WEAPON, WEAPON_LIMIT); + Game::ReallocateAssetPool(Game::ASSET_TYPE_STRINGTABLE, 800); + Game::ReallocateAssetPool(Game::ASSET_TYPE_IMPACT_FX, 8); // Register asset interfaces if (ZoneBuilder::IsEnabled()) { - Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_MAP_ENTS, 10); - Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_XMODEL_SURFS, 8192 * 2); - Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET, 0x2000); - Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_FONT, 32); - Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_RAWFILE, 2048); - Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_LEADERBOARD, 500); + Game::ReallocateAssetPool(Game::ASSET_TYPE_MAP_ENTS, 10); + Game::ReallocateAssetPool(Game::ASSET_TYPE_XMODEL_SURFS, 8192 * 2); + Game::ReallocateAssetPool(Game::ASSET_TYPE_TECHNIQUE_SET, 0x2000); + Game::ReallocateAssetPool(Game::ASSET_TYPE_FONT, 32); + Game::ReallocateAssetPool(Game::ASSET_TYPE_RAWFILE, 2048); + Game::ReallocateAssetPool(Game::ASSET_TYPE_LEADERBOARD, 500); AssetHandler::RegisterInterface(new Assets::IFont_s()); AssetHandler::RegisterInterface(new Assets::IWeapon()); diff --git a/src/Components/Modules/AssetInterfaces/IXModel.hpp b/src/Components/Modules/AssetInterfaces/IXModel.hpp index c43ffec2..2c68489a 100644 --- a/src/Components/Modules/AssetInterfaces/IXModel.hpp +++ b/src/Components/Modules/AssetInterfaces/IXModel.hpp @@ -5,7 +5,7 @@ namespace Assets class IXModel : public Components::AssetHandler::IAsset { public: - Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_XMODEL; } + Game::XAssetType getType() override { return Game::ASSET_TYPE_XMODEL; } void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; diff --git a/src/Components/Modules/AssetInterfaces/IXModelSurfs.hpp b/src/Components/Modules/AssetInterfaces/IXModelSurfs.hpp index e43f009d..b4b3bbcd 100644 --- a/src/Components/Modules/AssetInterfaces/IXModelSurfs.hpp +++ b/src/Components/Modules/AssetInterfaces/IXModelSurfs.hpp @@ -5,7 +5,7 @@ namespace Assets class IXModelSurfs : public Components::AssetHandler::IAsset { public: - Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_XMODEL_SURFS; } + Game::XAssetType getType() override { return Game::ASSET_TYPE_XMODEL_SURFS; } void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; diff --git a/src/Components/Modules/StructuredData.cpp b/src/Components/Modules/StructuredData.cpp index 121a0f8c..7830dae9 100644 --- a/src/Components/Modules/StructuredData.cpp +++ b/src/Components/Modules/StructuredData.cpp @@ -157,12 +157,14 @@ namespace Components // 15 or more custom classes Utils::Hook::Set(0x60A2FE, NUM_CUSTOM_CLASSES); + + return; } AssetHandler::OnLoad([](Game::XAssetType type, Game::XAssetHeader asset, const std::string& filename, bool* /*restrict*/) { // Only intercept playerdatadef loading - if (type != Game::XAssetType::ASSET_TYPE_STRUCTURED_DATA_DEF || filename != "mp/playerdata.def") return; + if (type != Game::ASSET_TYPE_STRUCTURED_DATA_DEF || filename != "mp/playerdata.def") return; // Store asset Game::StructuredDataDefSet* data = asset.structuredDataDefSet; From 9526c7aa7404caa1c3e019d89800a63880e9c3b1 Mon Sep 17 00:00:00 2001 From: Edo Date: Sat, 6 May 2023 20:47:10 +0100 Subject: [PATCH 11/39] Update CHANGELOG.md (#1015) --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e493d53..42c37a22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,7 +29,7 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0. ### Fixed - Fix bug with Steam Proxy (#991) -- Fix bug with the `say` GSC notify in regards to hidden commands (#989) +- Fix bug with the `say` GSC notify in regards to hidden chat messages (#989) ### Removed From 54f6162a7ab37baca8668aadf455bdf6d34f4f59 Mon Sep 17 00:00:00 2001 From: Edo Date: Sun, 7 May 2023 15:26:06 +0100 Subject: [PATCH 12/39] [Events]: Cleanup (#1016) --- src/Components/Modules/Download.cpp | 6 +++--- src/Components/Modules/Events.cpp | 24 ++++++++++++++++++++++++ src/Components/Modules/Events.hpp | 6 ++++++ src/Components/Modules/Network.cpp | 25 ------------------------- src/Components/Modules/Network.hpp | 8 -------- src/Game/Zone.cpp | 2 +- 6 files changed, 34 insertions(+), 37 deletions(-) diff --git a/src/Components/Modules/Download.cpp b/src/Components/Modules/Download.cpp index 1c43324b..ae0d1c6c 100644 --- a/src/Components/Modules/Download.cpp +++ b/src/Components/Modules/Download.cpp @@ -697,7 +697,7 @@ namespace Components mg_mgr_init(&Mgr); - Network::OnStart([] + Events::OnNetworkInit([]() -> void { const auto* nc = mg_http_listen(&Mgr, Utils::String::VA(":%hu", Network::GetPort()), &EventHandler, &Mgr); if (!nc) @@ -709,7 +709,7 @@ namespace Components ServerRunning = true; Terminate = false; - ServerThread = Utils::Thread::CreateNamedThread("Mongoose", [] + ServerThread = Utils::Thread::CreateNamedThread("Mongoose", []() -> void { Com_InitThreadData(); @@ -722,7 +722,7 @@ namespace Components } else { - Events::OnDvarInit([] + Events::OnDvarInit([]() -> void { UIDlTimeLeft = Dvar::Register("ui_dl_timeLeft", "", Game::DVAR_NONE, ""); UIDlProgress = Dvar::Register("ui_dl_progress", "", Game::DVAR_NONE, ""); diff --git a/src/Components/Modules/Events.cpp b/src/Components/Modules/Events.cpp index 7d69b3a7..8d889a10 100644 --- a/src/Components/Modules/Events.cpp +++ b/src/Components/Modules/Events.cpp @@ -9,6 +9,7 @@ namespace Components Utils::Signal Events::ClientInitSignal; Utils::Signal Events::ServerInitSignal; Utils::Signal Events::DvarInitSignal; + Utils::Signal Events::NetworkInitSignal; void Events::OnClientDisconnect(const Utils::Slot& callback) { @@ -45,6 +46,11 @@ namespace Components DvarInitSignal.connect(callback); } + void Events::OnNetworkInit(const Utils::Slot& callback) + { + NetworkInitSignal.connect(callback); + } + /* * Should be called when a client drops from the server * but not "between levels" (Quake-III-Arena) @@ -101,6 +107,22 @@ namespace Components Utils::Hook::Call(0x60AD10)(); // Com_InitDvars } + void Events::NetworkStart() + { + NetworkInitSignal(); + NetworkInitSignal.clear(); + } + + __declspec(naked) void Events::NET_OpenSocks_Hk() + { + __asm + { + mov eax, 64D900h + call eax + jmp NetworkStart + } + } + Events::Events() { Utils::Hook(0x625235, ClientDisconnect_Hk, HOOK_CALL).install()->quick(); // SV_FreeClient @@ -117,5 +139,7 @@ namespace Components Utils::Hook(0x60BB3A, Com_InitDvars_Hk, HOOK_CALL).install()->quick(); // Com_Init_Try_Block_Function Utils::Hook(0x4D3665, SV_Init_Hk, HOOK_CALL).install()->quick(); // SV_Init + + Utils::Hook(0x4FD4D4, NET_OpenSocks_Hk, HOOK_JUMP).install()->quick(); // NET_OpenIP } } diff --git a/src/Components/Modules/Events.hpp b/src/Components/Modules/Events.hpp index c8d3e6a9..439ad120 100644 --- a/src/Components/Modules/Events.hpp +++ b/src/Components/Modules/Events.hpp @@ -30,6 +30,8 @@ namespace Components // Client & Server (triggered once) static void OnDvarInit(const Utils::Slot& callback); + static void OnNetworkInit(const Utils::Slot& callback); + private: static Utils::Signal ClientDisconnectSignal; static Utils::Signal ClientConnectSignal; @@ -38,6 +40,7 @@ namespace Components static Utils::Signal ClientInitSignal; static Utils::Signal ServerInitSignal; static Utils::Signal DvarInitSignal; + static Utils::Signal NetworkInitSignal; static void ClientDisconnect_Hk(int clientNum); static void SV_UserinfoChanged_Hk(Game::client_s* cl); @@ -46,5 +49,8 @@ namespace Components static void CL_InitOnceForAllClients_HK(); static void SV_Init_Hk(); static void Com_InitDvars_Hk(); + + static void NetworkStart(); + static void NET_OpenSocks_Hk(); }; } diff --git a/src/Components/Modules/Network.cpp b/src/Components/Modules/Network.cpp index 53e74399..cdc0e1db 100644 --- a/src/Components/Modules/Network.cpp +++ b/src/Components/Modules/Network.cpp @@ -2,7 +2,6 @@ namespace Components { - Utils::Signal Network::StartupSignal; // Packet interception std::unordered_map Network::CL_Callbacks; std::unordered_map Network::CL_RawCallbacks; @@ -152,11 +151,6 @@ namespace Components return (this->getType() != Game::NA_BAD && this->getType() >= Game::NA_BOT && this->getType() <= Game::NA_IP); } - void Network::OnStart(const Utils::Slot& callback) - { - StartupSignal.connect(callback); - } - void Network::Send(Game::netsrc_t type, const Address& target, const std::string& data) { // Do not use NET_OutOfBandPrint. It only supports non-binary data! @@ -228,12 +222,6 @@ namespace Components BroadcastRange(100, 65536, data); } - void Network::NetworkStart() - { - StartupSignal(); - StartupSignal.clear(); - } - std::uint16_t Network::GetPort() { assert((*Game::port)); @@ -241,16 +229,6 @@ namespace Components return static_cast((*Game::port)->current.unsignedInt); } - __declspec(naked) void Network::NetworkStartStub() - { - __asm - { - mov eax, 64D900h - call eax - jmp NetworkStart - } - } - __declspec(naked) void Network::PacketErrorCheck() { __asm @@ -392,9 +370,6 @@ namespace Components // Parse port as short in Net_AddrToString Utils::Hook::Set(0x4698E3, "%u.%u.%u.%u:%hu"); - // Install startup handler - Utils::Hook(0x4FD4D4, NetworkStartStub, HOOK_JUMP).install()->quick(); - // Prevent recvfrom error spam Utils::Hook(0x46531A, PacketErrorCheck, HOOK_JUMP).install()->quick(); diff --git a/src/Components/Modules/Network.hpp b/src/Components/Modules/Network.hpp index d9e2e020..838e9db8 100644 --- a/src/Components/Modules/Network.hpp +++ b/src/Components/Modules/Network.hpp @@ -46,16 +46,12 @@ namespace Components Game::netadr_t address; }; - typedef void(CallbackRaw)(); - using networkCallback = std::function; using networkRawCallback = std::function; Network(); static std::uint16_t GetPort(); - - static void OnStart(const Utils::Slot& callback); // Send quake-styled binary data static void Send(const Address& target, const std::string& data); @@ -77,13 +73,9 @@ namespace Components static void OnClientPacketRaw(const std::string& command, const networkRawCallback& callback); private: - static Utils::Signal StartupSignal; static std::unordered_map CL_Callbacks; static std::unordered_map CL_RawCallbacks; - static void NetworkStart(); - static void NetworkStartStub(); - static void PacketErrorCheck(); static bool CL_HandleCommand(Game::netadr_t* address, const char* command, Game::msg_t* message); diff --git a/src/Game/Zone.cpp b/src/Game/Zone.cpp index 2bc7155b..68ef430d 100644 --- a/src/Game/Zone.cpp +++ b/src/Game/Zone.cpp @@ -22,7 +22,7 @@ namespace Game assert((size >= 0)); #pragma warning(push) #pragma warning(disable: 6250) - [[maybe_unused]] const auto result = VirtualFree(ptr, size, MEM_DECOMMIT); + VirtualFree(ptr, size, MEM_DECOMMIT); #pragma warning(pop) } From c87e6971e7ee4038d680ec79445958ccd21a7b3f Mon Sep 17 00:00:00 2001 From: Edo Date: Sun, 7 May 2023 19:16:58 +0100 Subject: [PATCH 13/39] [Dvars]: Remove cheat flag from jump_height (#1017) --- src/Components/Modules/Dvar.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Components/Modules/Dvar.cpp b/src/Components/Modules/Dvar.cpp index 665abae7..83f43f83 100644 --- a/src/Components/Modules/Dvar.cpp +++ b/src/Components/Modules/Dvar.cpp @@ -459,6 +459,9 @@ namespace Components // un-cheat jump_slowdownEnable Utils::Hook::Xor(0x4EFABE, Game::DVAR_CHEAT); + // un-cheat jump_height + Utils::Hook::Xor(0x4EFA5C, Game::DVAR_CHEAT); + // Hook dvar 'name' registration Utils::Hook(0x40531C, Dvar_RegisterName, HOOK_CALL).install()->quick(); From 9632d789d8711d6f29662e95b459f972cbe72e12 Mon Sep 17 00:00:00 2001 From: Edo Date: Sun, 7 May 2023 22:45:19 +0100 Subject: [PATCH 14/39] [PlayerMovement]: Remove cheat protections from harmless dvars (#1018) --- src/Components/Modules/PlayerMovement.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Components/Modules/PlayerMovement.cpp b/src/Components/Modules/PlayerMovement.cpp index e933a255..371b9847 100644 --- a/src/Components/Modules/PlayerMovement.cpp +++ b/src/Components/Modules/PlayerMovement.cpp @@ -267,7 +267,7 @@ namespace Components float min, float max, unsigned __int16 /*flags*/, const char* description) { PlayerSpectateSpeedScale = Game::Dvar_RegisterFloat(dvarName, value, - min, max, Game::DVAR_CHEAT | Game::DVAR_CODINFO, description); + min, max, Game::DVAR_CODINFO, description); return PlayerSpectateSpeedScale; } @@ -275,20 +275,20 @@ namespace Components void PlayerMovement::RegisterMovementDvars() { PlayerDuckedSpeedScale = Game::Dvar_RegisterFloat("player_duckedSpeedScale", - 0.65f, 0.0f, 5.0f, Game::DVAR_CHEAT | Game::DVAR_CODINFO, + 0.65f, 0.0f, 5.0f, Game::DVAR_CODINFO, "The scale applied to the player speed when ducking"); PlayerProneSpeedScale = Game::Dvar_RegisterFloat("player_proneSpeedScale", - 0.15f, 0.0f, 5.0f, Game::DVAR_CHEAT | Game::DVAR_CODINFO, + 0.15f, 0.0f, 5.0f, Game::DVAR_CODINFO, "The scale applied to the player speed when crawling"); // 3arc naming convention CGUfoScaler = Game::Dvar_RegisterFloat("cg_ufo_scaler", - 6.0f, 0.001f, 1000.0f, Game::DVAR_CHEAT | Game::DVAR_CODINFO, + 6.0f, 0.001f, 1000.0f, Game::DVAR_CODINFO, "The speed at which ufo camera moves"); CGNoclipScaler = Game::Dvar_RegisterFloat("cg_noclip_scaler", - 3.0f, 0.001f, 1000.0f, Game::DVAR_CHEAT | Game::DVAR_CODINFO, + 3.0f, 0.001f, 1000.0f, Game::DVAR_CODINFO, "The speed at which noclip camera moves"); BGDisableLandingSlowdown = Game::Dvar_RegisterBool("bg_disableLandingSlowdown", From 3c7fbb26e702b336feec1c34c79a32f45f75c6a0 Mon Sep 17 00:00:00 2001 From: Edo Date: Mon, 8 May 2023 00:11:30 +0100 Subject: [PATCH 15/39] [Dvar]: Un-Cheat some more (#1019) --- src/Components/Modules/Dvar.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Components/Modules/Dvar.cpp b/src/Components/Modules/Dvar.cpp index 83f43f83..74d883d0 100644 --- a/src/Components/Modules/Dvar.cpp +++ b/src/Components/Modules/Dvar.cpp @@ -462,6 +462,18 @@ namespace Components // un-cheat jump_height Utils::Hook::Xor(0x4EFA5C, Game::DVAR_CHEAT); + // un-cheat player_breath_fire_delay + Utils::Hook::Xor(0x448646, Game::DVAR_CHEAT); + + // un-cheat player_breath_gasp_scale + Utils::Hook::Xor(0x448678, Game::DVAR_CHEAT); + + // un-cheat player_breath_gasp_lerp + Utils::Hook::Xor(0x4486E4, Game::DVAR_CHEAT); + + // un-cheat player_breath_gasp_time + Utils::Hook::Xor(0x448612, Game::DVAR_CHEAT); + // Hook dvar 'name' registration Utils::Hook(0x40531C, Dvar_RegisterName, HOOK_CALL).install()->quick(); From 67d3cf2bb74c568eb6b8c8aa76ec9a11645deed1 Mon Sep 17 00:00:00 2001 From: Edo Date: Mon, 8 May 2023 13:35:23 +0100 Subject: [PATCH 16/39] [Party]: Use .empty() (#1020) --- src/Components/Modules/Party.cpp | 5 +++-- src/Components/Modules/TextRenderer.cpp | 7 +++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Components/Modules/Party.cpp b/src/Components/Modules/Party.cpp index 8dfad7db..fadefcb1 100644 --- a/src/Components/Modules/Party.cpp +++ b/src/Components/Modules/Party.cpp @@ -9,6 +9,7 @@ #include "Party.hpp" #include "ServerList.hpp" #include "Stats.hpp" +#include "TextRenderer.hpp" #include "Voice.hpp" #include @@ -493,7 +494,7 @@ namespace Components { ConnectError("Invalid map or gametype."); } - else if (Container.info.get("isPrivate") == "1"s && !Dvar::Var("password").get().length()) + else if (Container.info.get("isPrivate") == "1"s && Dvar::Var("password").get().empty()) { ConnectError("A password is required to join this server! Set it at the bottom of the serverlist."); } @@ -524,7 +525,7 @@ namespace Components { if (!Maps::CheckMapInstalled(Container.info.get("mapname"), true)) return; - Container.motd = info.get("sv_motd"); + Container.motd = TextRenderer::StripMaterialTextIcons(info.get("sv_motd")); if (Container.matchType == 1) // Party { diff --git a/src/Components/Modules/TextRenderer.cpp b/src/Components/Modules/TextRenderer.cpp index 9f2b0e2e..91d9ff52 100644 --- a/src/Components/Modules/TextRenderer.cpp +++ b/src/Components/Modules/TextRenderer.cpp @@ -1480,7 +1480,7 @@ namespace Components { char buffer[1000]{}; // Should be more than enough StripAllTextIcons(in.data(), buffer, sizeof(buffer)); - return {buffer}; + return std::string{ buffer }; } int TextRenderer::SEH_PrintStrlenWithCursor(const char* string, const Game::field_t* field) @@ -1558,8 +1558,7 @@ namespace Components { if (r_colorBlind.get()) { - const auto str = std::string(name); - if (str == "g_TeamColor_EnemyTeam") + if (std::strcmp(name, "g_TeamColor_EnemyTeam") == 0) { // Dvar_GetUnpackedColor const auto* colorblindEnemy = g_ColorBlind_EnemyTeam->current.color; @@ -1570,7 +1569,7 @@ namespace Components return false; } - if (str == "g_TeamColor_MyTeam") + if (std::strcmp(name, "g_TeamColor_MyTeam") == 0) { // Dvar_GetUnpackedColor const auto* colorblindAlly = g_ColorBlind_MyTeam->current.color; From 6cd4c2d83f939340274543c4c5fab0d3965dba82 Mon Sep 17 00:00:00 2001 From: Edo Date: Tue, 9 May 2023 15:52:09 +0100 Subject: [PATCH 17/39] [Localization]: Fix (#1021) --- src/Components/Modules/Localization.cpp | 2 +- src/Components/Modules/Weapon.cpp | 4 ++-- src/Components/Modules/Weapon.hpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Components/Modules/Localization.cpp b/src/Components/Modules/Localization.cpp index e7f44f83..a76cad20 100644 --- a/src/Components/Modules/Localization.cpp +++ b/src/Components/Modules/Localization.cpp @@ -118,6 +118,7 @@ namespace Components "/dev/tty0", "/dev/urandom", "Dss0", + "Evan/Eve", "FutureRave", "H3X1C", "Homura", @@ -137,7 +138,6 @@ namespace Components "Dasfonia", "Deity", "Dizzy", - "Evan/Eve" "HardNougat", "INeedGames", "JTAG", diff --git a/src/Components/Modules/Weapon.cpp b/src/Components/Modules/Weapon.cpp index b3f4ee6d..f3842b19 100644 --- a/src/Components/Modules/Weapon.cpp +++ b/src/Components/Modules/Weapon.cpp @@ -548,7 +548,7 @@ namespace Components } } - void Weapon::PlayerCmd_initialWeaponRaise(Game::scr_entref_t entref) + void Weapon::PlayerCmd_InitialWeaponRaise(Game::scr_entref_t entref) { auto* ent = GSC::Script::Scr_GetPlayerEntity(entref); const auto* weapon = Game::Scr_GetString(0); @@ -594,7 +594,7 @@ namespace Components ent->client->ps.weapCommon.weapFlags &= ~Game::PWF_DISABLE_WEAPON_PICKUP; }); - GSC::Script::AddMethod("InitialWeaponRaise", PlayerCmd_initialWeaponRaise); + GSC::Script::AddMethod("InitialWeaponRaise", PlayerCmd_InitialWeaponRaise); } Weapon::Weapon() diff --git a/src/Components/Modules/Weapon.hpp b/src/Components/Modules/Weapon.hpp index acfe3d00..3c3e6e71 100644 --- a/src/Components/Modules/Weapon.hpp +++ b/src/Components/Modules/Weapon.hpp @@ -35,7 +35,7 @@ namespace Components static void WeaponEntCanBeGrabbed_Stub(); - static void PlayerCmd_initialWeaponRaise(Game::scr_entref_t entref); + static void PlayerCmd_InitialWeaponRaise(Game::scr_entref_t entref); static void AddScriptMethods(); }; From a019ff58f2918bbdfaa494835dfb0bb536a7c71a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 May 2023 17:58:43 +0000 Subject: [PATCH 18/39] Bump deps/rapidjson from `949c771` to `0e88d5e` Bumps [deps/rapidjson](https://github.com/Tencent/rapidjson) from `949c771` to `0e88d5e`. - [Release notes](https://github.com/Tencent/rapidjson/releases) - [Commits](https://github.com/Tencent/rapidjson/compare/949c771b03de448bdedea80c44a4a5f65284bfeb...0e88d5e40448616ede258be29e6e337eb99aa104) --- updated-dependencies: - dependency-name: deps/rapidjson dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- deps/rapidjson | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/rapidjson b/deps/rapidjson index 949c771b..0e88d5e4 160000 --- a/deps/rapidjson +++ b/deps/rapidjson @@ -1 +1 @@ -Subproject commit 949c771b03de448bdedea80c44a4a5f65284bfeb +Subproject commit 0e88d5e40448616ede258be29e6e337eb99aa104 From f20c455c80163ff3eb166e22584f1590d04b37cc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 May 2023 18:39:27 +0000 Subject: [PATCH 19/39] Bump deps/GSL from `43d60c5` to `5dc7fae` Bumps [deps/GSL](https://github.com/microsoft/GSL) from `43d60c5` to `5dc7fae`. - [Release notes](https://github.com/microsoft/GSL/releases) - [Commits](https://github.com/microsoft/GSL/compare/43d60c5e3891dab6491a76d0bac554a4a89d57f6...5dc7fae1199e90b875decfae7b91e83d27881c81) --- updated-dependencies: - dependency-name: deps/GSL dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- deps/GSL | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/GSL b/deps/GSL index 43d60c5e..5dc7fae1 160000 --- a/deps/GSL +++ b/deps/GSL @@ -1 +1 @@ -Subproject commit 43d60c5e3891dab6491a76d0bac554a4a89d57f6 +Subproject commit 5dc7fae1199e90b875decfae7b91e83d27881c81 From 1ee38f92fba746caec12e60078d5bfe799940a2d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 May 2023 18:01:32 +0000 Subject: [PATCH 20/39] Bump deps/rapidjson from `0e88d5e` to `2a1f586` Bumps [deps/rapidjson](https://github.com/Tencent/rapidjson) from `0e88d5e` to `2a1f586`. - [Release notes](https://github.com/Tencent/rapidjson/releases) - [Commits](https://github.com/Tencent/rapidjson/compare/0e88d5e40448616ede258be29e6e337eb99aa104...2a1f586ba692ecbbf6d63c8ffbd4d837b1d4a9a4) --- updated-dependencies: - dependency-name: deps/rapidjson dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- deps/rapidjson | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/rapidjson b/deps/rapidjson index 0e88d5e4..2a1f586b 160000 --- a/deps/rapidjson +++ b/deps/rapidjson @@ -1 +1 @@ -Subproject commit 0e88d5e40448616ede258be29e6e337eb99aa104 +Subproject commit 2a1f586ba692ecbbf6d63c8ffbd4d837b1d4a9a4 From 7bac761339744dc00479d5d7aaf50a1ed2f7baf7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 May 2023 18:02:07 +0000 Subject: [PATCH 21/39] Bump deps/iw4-open-formats from `266165d` to `6d70c2e` Bumps [deps/iw4-open-formats](https://github.com/XLabsProject/iw4-open-formats) from `266165d` to `6d70c2e`. - [Release notes](https://github.com/XLabsProject/iw4-open-formats/releases) - [Commits](https://github.com/XLabsProject/iw4-open-formats/compare/266165d21d77dadfe2adb01b7f1bf0fe64832479...6d70c2ecfe3c34d9b3945fd87a90265e63763069) --- updated-dependencies: - dependency-name: deps/iw4-open-formats dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- deps/iw4-open-formats | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/iw4-open-formats b/deps/iw4-open-formats index 266165d2..6d70c2ec 160000 --- a/deps/iw4-open-formats +++ b/deps/iw4-open-formats @@ -1 +1 @@ -Subproject commit 266165d21d77dadfe2adb01b7f1bf0fe64832479 +Subproject commit 6d70c2ecfe3c34d9b3945fd87a90265e63763069 From 7d03e90197df249da9638996c40f349f59fbdffe Mon Sep 17 00:00:00 2001 From: FutureRave Date: Thu, 11 May 2023 12:32:14 +0100 Subject: [PATCH 22/39] [Weapon]: Add very realistic FreezeControlsAllowLook --- src/Components/Modules/ClientCommand.cpp | 8 ++--- src/Components/Modules/GSC/Script.cpp | 2 +- .../Modules/GSC/ScriptExtension.cpp | 11 ------- .../Modules/GSC/ScriptExtension.hpp | 1 - src/Components/Modules/Voice.cpp | 2 +- src/Components/Modules/Weapon.cpp | 30 +++++++++++++++++-- src/Components/Modules/Weapon.hpp | 1 + src/Game/Functions.cpp | 6 ++-- src/Game/Structs.hpp | 8 +++-- 9 files changed, 42 insertions(+), 27 deletions(-) diff --git a/src/Components/Modules/ClientCommand.cpp b/src/Components/Modules/ClientCommand.cpp index ab3765a7..f80f9eb8 100644 --- a/src/Components/Modules/ClientCommand.cpp +++ b/src/Components/Modules/ClientCommand.cpp @@ -488,12 +488,12 @@ namespace Components if (!CheatsOk(ent)) return; - ent->client->flags ^= Game::PF_NOCLIP; + ent->client->flags ^= Game::CF_BIT_NOCLIP; const auto entNum = ent->s.number; Logger::Debug("Noclip toggled for entity {}", entNum); - Game::SV_GameSendServerCommand(entNum, Game::SV_CMD_CAN_IGNORE, VA("%c \"%s\"", 0x65, (ent->client->flags & Game::PF_NOCLIP) ? "GAME_NOCLIPON" : "GAME_NOCLIPOFF")); + Game::SV_GameSendServerCommand(entNum, Game::SV_CMD_CAN_IGNORE, VA("%c \"%s\"", 0x65, (ent->client->flags & Game::CF_BIT_NOCLIP) ? "GAME_NOCLIPON" : "GAME_NOCLIPOFF")); } void ClientCommand::Cmd_UFO_f(Game::gentity_s* ent, [[maybe_unused]] const Command::ServerParams* params) @@ -501,12 +501,12 @@ namespace Components if (!CheatsOk(ent)) return; - ent->client->flags ^= Game::PF_UFO; + ent->client->flags ^= Game::CF_BIT_UFO; const auto entNum = ent->s.number; Logger::Debug("UFO toggled for entity {}", entNum); - Game::SV_GameSendServerCommand(entNum, Game::SV_CMD_CAN_IGNORE, VA("%c \"%s\"", 0x65, (ent->client->flags & Game::PF_UFO) ? "GAME_UFOON" : "GAME_UFOOFF")); + Game::SV_GameSendServerCommand(entNum, Game::SV_CMD_CAN_IGNORE, VA("%c \"%s\"", 0x65, (ent->client->flags & Game::CF_BIT_UFO) ? "GAME_UFOON" : "GAME_UFOOFF")); } ClientCommand::ClientCommand() diff --git a/src/Components/Modules/GSC/Script.cpp b/src/Components/Modules/GSC/Script.cpp index 242f5436..0bcdd1b6 100644 --- a/src/Components/Modules/GSC/Script.cpp +++ b/src/Components/Modules/GSC/Script.cpp @@ -262,7 +262,7 @@ namespace Components::GSC auto* ent = &Game::g_entities[entref.entnum]; if (!ent->client) { - Game::Scr_ObjectError(Utils::String::VA("entity %i is not a player", entref.entnum)); + Game::Scr_ObjectError(Utils::String::VA("entity %hu is not a player", entref.entnum)); return nullptr; } diff --git a/src/Components/Modules/GSC/ScriptExtension.cpp b/src/Components/Modules/GSC/ScriptExtension.cpp index f83bdaae..f5497679 100644 --- a/src/Components/Modules/GSC/ScriptExtension.cpp +++ b/src/Components/Modules/GSC/ScriptExtension.cpp @@ -169,20 +169,9 @@ namespace Components::GSC }); } - void ScriptExtension::AddMethods() - { - // PlayerCmd_AreControlsFrozen GSC function from Black Ops 2 - Script::AddMethod("AreControlsFrozen", [](Game::scr_entref_t entref) // Usage: self AreControlsFrozen(); - { - const auto* ent = Script::Scr_GetPlayerEntity(entref); - Game::Scr_AddBool((ent->client->flags & Game::PF_FROZEN) != 0); - }); - } - ScriptExtension::ScriptExtension() { AddFunctions(); - AddMethods(); Utils::Hook(0x61E92E, VMExecuteInternalStub, HOOK_JUMP).install()->quick(); Utils::Hook::Nop(0x61E933, 1); diff --git a/src/Components/Modules/GSC/ScriptExtension.hpp b/src/Components/Modules/GSC/ScriptExtension.hpp index 18fa1ba3..323777ae 100644 --- a/src/Components/Modules/GSC/ScriptExtension.hpp +++ b/src/Components/Modules/GSC/ScriptExtension.hpp @@ -18,6 +18,5 @@ namespace Components::GSC static void VMExecuteInternalStub(); static void AddFunctions(); - static void AddMethods(); }; } diff --git a/src/Components/Modules/Voice.cpp b/src/Components/Modules/Voice.cpp index 5379eb6c..c7bf5448 100644 --- a/src/Components/Modules/Voice.cpp +++ b/src/Components/Modules/Voice.cpp @@ -391,7 +391,7 @@ namespace Components Events::OnSteamDisconnect(CL_ClearMutedList); Events::OnClientDisconnect(SV_UnmuteClient); - Events::OnClientConnect([](Game::client_s* cl) -> void + Events::OnClientConnect([](const Game::client_s* cl) -> void { if (Chat::IsMuted(cl)) { diff --git a/src/Components/Modules/Weapon.cpp b/src/Components/Modules/Weapon.cpp index f3842b19..2451420c 100644 --- a/src/Components/Modules/Weapon.cpp +++ b/src/Components/Modules/Weapon.cpp @@ -548,7 +548,7 @@ namespace Components } } - void Weapon::PlayerCmd_InitialWeaponRaise(Game::scr_entref_t entref) + void Weapon::PlayerCmd_InitialWeaponRaise(const Game::scr_entref_t entref) { auto* ent = GSC::Script::Scr_GetPlayerEntity(entref); const auto* weapon = Game::Scr_GetString(0); @@ -578,23 +578,47 @@ namespace Components Game::Player_SwitchToWeapon(ent); } + void Weapon::PlayerCmd_FreezeControlsAllowLook(const Game::scr_entref_t entref) + { + const auto* ent = GSC::Script::Scr_GetPlayerEntity(entref); + + if (Game::Scr_GetInt(0)) + { + ent->client->ps.weapCommon.weapFlags |= Game::PWF_DISABLE_WEAPONS; + ent->client->flags |= Game::CF_BIT_DISABLE_USABILITY; + } + else + { + ent->client->ps.weapCommon.weapFlags &= ~Game::PWF_DISABLE_WEAPONS; + ent->client->flags &= ~Game::CF_BIT_DISABLE_USABILITY; + } + } + void Weapon::AddScriptMethods() { - GSC::Script::AddMethod("DisableWeaponPickup", [](Game::scr_entref_t entref) + GSC::Script::AddMethod("DisableWeaponPickup", [](const Game::scr_entref_t entref) { const auto* ent = GSC::Script::Scr_GetPlayerEntity(entref); ent->client->ps.weapCommon.weapFlags |= Game::PWF_DISABLE_WEAPON_PICKUP; }); - GSC::Script::AddMethod("EnableWeaponPickup", [](Game::scr_entref_t entref) + GSC::Script::AddMethod("EnableWeaponPickup", [](const Game::scr_entref_t entref) { const auto* ent = GSC::Script::Scr_GetPlayerEntity(entref); ent->client->ps.weapCommon.weapFlags &= ~Game::PWF_DISABLE_WEAPON_PICKUP; }); + // PlayerCmd_AreControlsFrozen GSC function from Black Ops 2 + GSC::Script::AddMethod("AreControlsFrozen", [](Game::scr_entref_t entref) // Usage: self AreControlsFrozen(); + { + const auto* ent = GSC::Script::Scr_GetPlayerEntity(entref); + Game::Scr_AddBool((ent->client->flags & Game::CF_BIT_FROZEN) != 0); + }); + GSC::Script::AddMethod("InitialWeaponRaise", PlayerCmd_InitialWeaponRaise); + GSC::Script::AddMethod("FreezeControlsAllowLook", PlayerCmd_FreezeControlsAllowLook); } Weapon::Weapon() diff --git a/src/Components/Modules/Weapon.hpp b/src/Components/Modules/Weapon.hpp index 3c3e6e71..30af745b 100644 --- a/src/Components/Modules/Weapon.hpp +++ b/src/Components/Modules/Weapon.hpp @@ -36,6 +36,7 @@ namespace Components static void WeaponEntCanBeGrabbed_Stub(); static void PlayerCmd_InitialWeaponRaise(Game::scr_entref_t entref); + static void PlayerCmd_FreezeControlsAllowLook(Game::scr_entref_t entref); static void AddScriptMethods(); }; diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index 86afc062..05b1efca 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -1156,7 +1156,7 @@ namespace Game int SEH_GetLocalizedTokenReference(char* token, const char* reference, const char* messageType, msgLocErrType_t errType) { static DWORD SEH_GetLocalizedTokenReference_t = 0x629BB0; - auto answer = 0; + auto result = 0; __asm { @@ -1167,11 +1167,11 @@ namespace Game push token call SEH_GetLocalizedTokenReference_t add esp, 0x4 - mov answer, eax + mov result, eax popad } - return answer; + return result; } void Player_SwitchToWeapon(gentity_s* player) diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index 1b33367a..f488d115 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -7140,9 +7140,11 @@ namespace Game enum { - PF_NOCLIP = 1 << 0, - PF_UFO = 1 << 1, - PF_FROZEN = 1 << 2, + CF_BIT_NOCLIP = (1 << 0), + CF_BIT_UFO = (1 << 1), + CF_BIT_FROZEN = (1 << 2), + CF_BIT_DISABLE_USABILITY = (1 << 3), + CF_BIT_NO_KNOCKBACK = (1 << 4), }; enum sessionState_t From e1371a85a0454a60f731e05a9767a39a7b9ffd69 Mon Sep 17 00:00:00 2001 From: Edo Date: Thu, 11 May 2023 16:13:49 +0100 Subject: [PATCH 23/39] [General]: Update workflows (#1027) --- .github/workflows/draft-new-release.yml | 2 +- .github/workflows/release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/draft-new-release.yml b/.github/workflows/draft-new-release.yml index 9609dc02..f3c13068 100644 --- a/.github/workflows/draft-new-release.yml +++ b/.github/workflows/draft-new-release.yml @@ -12,7 +12,7 @@ jobs: name: "Draft a new release" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v3.5.2 - name: Normalize version id: normalize_version diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7ad42f46..fb5e9814 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,7 +12,7 @@ jobs: steps: - name: Check out files if: github.event.pull_request.merged - uses: actions/checkout@v3 + uses: actions/checkout@v3.5.2 with: submodules: false lfs: false From d51fbbdda9ebfc3068826f3c08dce5001d63dcdf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 May 2023 17:58:23 +0000 Subject: [PATCH 24/39] Bump deps/GSL from `5dc7fae` to `afaaa71` Bumps [deps/GSL](https://github.com/microsoft/GSL) from `5dc7fae` to `afaaa71`. - [Release notes](https://github.com/microsoft/GSL/releases) - [Commits](https://github.com/microsoft/GSL/compare/5dc7fae1199e90b875decfae7b91e83d27881c81...afaaa71bcee45d9c90c21f8bd3ba2b12902242e9) --- updated-dependencies: - dependency-name: deps/GSL dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- deps/GSL | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/GSL b/deps/GSL index 5dc7fae1..afaaa71b 160000 --- a/deps/GSL +++ b/deps/GSL @@ -1 +1 @@ -Subproject commit 5dc7fae1199e90b875decfae7b91e83d27881c81 +Subproject commit afaaa71bcee45d9c90c21f8bd3ba2b12902242e9 From d3775d2565e3169628c1f1ff4abb6bd89d5f29b6 Mon Sep 17 00:00:00 2001 From: Edo Date: Fri, 12 May 2023 12:00:04 +0100 Subject: [PATCH 25/39] [Auth]: Small update (#1030) --- src/Components/Modules/Auth.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Components/Modules/Auth.cpp b/src/Components/Modules/Auth.cpp index 4b0ee31a..ef93603f 100644 --- a/src/Components/Modules/Auth.cpp +++ b/src/Components/Modules/Auth.cpp @@ -547,7 +547,6 @@ namespace Components TokenContainer.cancel = true; TokenContainer.generating = false; - // Terminate thread if (TokenContainer.thread.joinable()) { TokenContainer.thread.join(); From 2805c3fb2fa1457471d997d4d610349cd43be981 Mon Sep 17 00:00:00 2001 From: Edo Date: Fri, 12 May 2023 20:11:01 +0100 Subject: [PATCH 26/39] [Network]: Fix potential dead-lock (#1031) --- src/Components/Modules/Network.cpp | 8 ++++++++ src/Components/Modules/QuickPatch.cpp | 25 ------------------------- 2 files changed, 8 insertions(+), 25 deletions(-) diff --git a/src/Components/Modules/Network.cpp b/src/Components/Modules/Network.cpp index cdc0e1db..99c57784 100644 --- a/src/Components/Modules/Network.cpp +++ b/src/Components/Modules/Network.cpp @@ -409,6 +409,14 @@ namespace Components Utils::Hook::Set(0x682170, 0xC3); // Telling LSP that we're playing a private match Utils::Hook::Nop(0x4FD448, 5); // Don't create lsp_socket + // Do not run UPNP stuff at all + Utils::Hook::Set(0x48A135, 0xC3); + Utils::Hook::Set(0x48A151, 0xC3); + Utils::Hook::Nop(0x684080, 5); // Don't spam the console + + // Disable the IWNet IP detection (default 'got ipdetect' flag to 1) + Utils::Hook::Set(0x649D6F0, 1); + OnClientPacket("resolveAddress", []([[maybe_unused]] const Address& address, [[maybe_unused]] const std::string& data) { SendRaw(address, address.getString()); diff --git a/src/Components/Modules/QuickPatch.cpp b/src/Components/Modules/QuickPatch.cpp index c8c900cf..8ea1cafb 100644 --- a/src/Components/Modules/QuickPatch.cpp +++ b/src/Components/Modules/QuickPatch.cpp @@ -369,31 +369,6 @@ namespace Components // remove limit on IWD file loading Utils::Hook::Set(0x642BF3, 0xEB); - // dont run UPNP stuff on main thread - Utils::Hook::Set(0x48A135, 0xC3); - Utils::Hook::Set(0x48A151, 0xC3); - Utils::Hook::Nop(0x684080, 5); // Don't spam the console - - // spawn upnp thread when UPNP_init returns - Utils::Hook::Hook(0x47982B, []() - { - std::thread([] - { - Com_InitThreadData(); - - // check natpmpstate - // state 4 is no more devices to query - while (Utils::Hook::Get(0x66CE200) < 4) - { - Utils::Hook::Call(0x4D7030)(); - Game::Sys_Sleep(500); - } - }).detach(); - }, HOOK_JUMP).install()->quick(); - - // disable the IWNet IP detection (default 'got ipdetect' flag to 1) - Utils::Hook::Set(0x649D6F0, 1); - // Fix stats sleeping Utils::Hook::Set(0x6832BA, 0xEB); Utils::Hook::Set(0x4BD190, 0xC3); From 9e036e51744ca6916d0fcb86e9eae11a32a5f81d Mon Sep 17 00:00:00 2001 From: Edo Date: Fri, 12 May 2023 22:35:31 +0100 Subject: [PATCH 27/39] [Network]: Better patch (#1032) --- src/Components/Modules/Network.cpp | 38 +++++------------------------- src/Components/Modules/Network.hpp | 2 -- src/Game/Common.cpp | 1 + src/Game/Common.hpp | 3 +++ 4 files changed, 10 insertions(+), 34 deletions(-) diff --git a/src/Components/Modules/Network.cpp b/src/Components/Modules/Network.cpp index 99c57784..fe987d0d 100644 --- a/src/Components/Modules/Network.cpp +++ b/src/Components/Modules/Network.cpp @@ -319,33 +319,6 @@ namespace Components } } - int Network::Sys_StringToSockaddr_Hk(const char* s, sockaddr* sadr) - { - hostent* h; - ZeroMemory(sadr, sizeof(*sadr)); - - ((sockaddr_in*)sadr)->sin_family = AF_INET; - ((sockaddr_in*)sadr)->sin_port = 0; - - if (Game::I_isdigit(*s)) - { - // ReSharper disable once CppDeprecatedEntity - *(int*)&((sockaddr_in*)sadr)->sin_addr = static_cast(::inet_addr(s)); - } - else - { - // ReSharper disable once CppDeprecatedEntity - if ((h = ::gethostbyname(s)) == nullptr) - { - return false; - } - - *(int*)&((sockaddr_in*)sadr)->sin_addr = *(int*)h->h_addr_list[0]; - } - - return true; - } - Network::Network() { AssertSize(Game::netadr_t, 20); @@ -376,10 +349,6 @@ namespace Components // Handle client packets Utils::Hook(0x5AA703, CL_HandleCommandStub, HOOK_JUMP).install()->quick(); - // Use the version of Sys_StringToSockaddr made by 3arc - Utils::Hook(0x44E23C, Sys_StringToSockaddr_Hk, HOOK_CALL).install()->quick(); - Utils::Hook(0x64D480, Sys_StringToSockaddr_Hk, HOOK_CALL).install()->quick(); - // Disable unused OOB packets handlers just to be sure Utils::Hook::Set(0x5AA5B6, 0xEB); // CL_SteamServerAuth Utils::Hook::Set(0x5AA69F, 0xEB); // echo @@ -411,8 +380,13 @@ namespace Components // Do not run UPNP stuff at all Utils::Hook::Set(0x48A135, 0xC3); + Utils::Hook::Nop(0x48A135 + 1, 4); + Utils::Hook::Set(0x48A151, 0xC3); - Utils::Hook::Nop(0x684080, 5); // Don't spam the console + Utils::Hook::Nop(0x48A151 + 1, 4); + + // Don't spam the console + Utils::Hook(0x684080, Game::Com_DPrintf, HOOK_CALL).install()->quick(); // Disable the IWNet IP detection (default 'got ipdetect' flag to 1) Utils::Hook::Set(0x649D6F0, 1); diff --git a/src/Components/Modules/Network.hpp b/src/Components/Modules/Network.hpp index 838e9db8..d4382942 100644 --- a/src/Components/Modules/Network.hpp +++ b/src/Components/Modules/Network.hpp @@ -81,8 +81,6 @@ namespace Components static bool CL_HandleCommand(Game::netadr_t* address, const char* command, Game::msg_t* message); static void CL_HandleCommandStub(); - - static int Sys_StringToSockaddr_Hk(const char* s, sockaddr* sadr); }; } diff --git a/src/Game/Common.cpp b/src/Game/Common.cpp index 0b86c1ea..4f92c9d6 100644 --- a/src/Game/Common.cpp +++ b/src/Game/Common.cpp @@ -9,6 +9,7 @@ namespace Game Com_Error_t Com_Error = Com_Error_t(0x4B22D0); Com_Printf_t Com_Printf = Com_Printf_t(0x402500); + Com_DPrintf_t Com_DPrintf = Com_DPrintf_t(0x413490); Com_PrintError_t Com_PrintError = Com_PrintError_t(0x4F8C70); Com_PrintWarning_t Com_PrintWarning = Com_PrintWarning_t(0x4E0200); Com_PrintMessage_t Com_PrintMessage = Com_PrintMessage_t(0x4AA830); diff --git a/src/Game/Common.hpp b/src/Game/Common.hpp index f2d44ab2..22cc1449 100644 --- a/src/Game/Common.hpp +++ b/src/Game/Common.hpp @@ -20,6 +20,9 @@ namespace Game typedef void(*Com_Printf_t)(int channel, const char* fmt, ...); extern Com_Printf_t Com_Printf; + typedef void(*Com_DPrintf_t)(int channel, const char* fmt, ...); + extern Com_DPrintf_t Com_DPrintf; + typedef void(*Com_PrintError_t)(int channel, const char* fmt, ...); extern Com_PrintError_t Com_PrintError; From 8ec644123267e327af3aca1a2d7545273151feb7 Mon Sep 17 00:00:00 2001 From: Louve <33836535+Rackover@users.noreply.github.com> Date: Sun, 14 May 2023 13:21:31 +0200 Subject: [PATCH 28/39] Zb export (#1033) Co-authored-by: Louvenarde Co-authored-by: FutureRave --- deps/iw4-open-formats | 2 +- .../AssetInterfaces/Isnd_alias_list_t.cpp | 18 ++ .../AssetInterfaces/Isnd_alias_list_t.hpp | 3 + src/Components/Modules/ModelSurfs.cpp | 14 +- src/Components/Modules/ZoneBuilder.cpp | 159 ++++++++++++------ src/Components/Modules/ZoneBuilder.hpp | 7 + src/Components/Modules/Zones.cpp | 3 + 7 files changed, 155 insertions(+), 51 deletions(-) diff --git a/deps/iw4-open-formats b/deps/iw4-open-formats index 6d70c2ec..4fee3813 160000 --- a/deps/iw4-open-formats +++ b/deps/iw4-open-formats @@ -1 +1 @@ -Subproject commit 6d70c2ecfe3c34d9b3945fd87a90265e63763069 +Subproject commit 4fee3813071b11a95533ab8be975785ec6262358 diff --git a/src/Components/Modules/AssetInterfaces/Isnd_alias_list_t.cpp b/src/Components/Modules/AssetInterfaces/Isnd_alias_list_t.cpp index 76b21b2b..e753b934 100644 --- a/src/Components/Modules/AssetInterfaces/Isnd_alias_list_t.cpp +++ b/src/Components/Modules/AssetInterfaces/Isnd_alias_list_t.cpp @@ -40,6 +40,24 @@ namespace Assets } } + void Isnd_alias_list_t::dump(Game::XAssetHeader header) + { + Components::ZoneBuilder::GetExporter()->write(Game::XAssetType::ASSET_TYPE_SOUND, header.data); + } + + Isnd_alias_list_t::Isnd_alias_list_t() + { + Components::Command::Add("dumpSound", [this](const Components::Command::Params* param) + { + const auto header = Game::DB_FindXAssetHeader(Game::ASSET_TYPE_SOUND, param->get(1)); + if (header.data) + { + Components::ZoneBuilder::RefreshExporterWorkDirectory(); + this->dump(header); + } + }); + } + void Isnd_alias_list_t::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) { AssertSize(Game::snd_alias_list_t, 12); diff --git a/src/Components/Modules/AssetInterfaces/Isnd_alias_list_t.hpp b/src/Components/Modules/AssetInterfaces/Isnd_alias_list_t.hpp index d7f2337b..8a38cfa1 100644 --- a/src/Components/Modules/AssetInterfaces/Isnd_alias_list_t.hpp +++ b/src/Components/Modules/AssetInterfaces/Isnd_alias_list_t.hpp @@ -10,5 +10,8 @@ namespace Assets void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override; void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; + void dump(Game::XAssetHeader header) override; + + Isnd_alias_list_t(); }; } diff --git a/src/Components/Modules/ModelSurfs.cpp b/src/Components/Modules/ModelSurfs.cpp index e7e888eb..55e30ba1 100644 --- a/src/Components/Modules/ModelSurfs.cpp +++ b/src/Components/Modules/ModelSurfs.cpp @@ -39,7 +39,8 @@ namespace Components Game::XModelSurfs* ModelSurfs::LoadXModelSurfaces(const std::string& name) { Utils::Memory::Allocator allocator; - FileSystem::FileReader model(std::format("models/{}", name)); + const auto path = std::format("models/{}", name); + FileSystem::FileReader model(path); if (!model.exists()) { @@ -57,7 +58,16 @@ namespace Components } #endif - Logger::Error(Game::ERR_FATAL, "Loading model {} failed!", name); + if (ZoneBuilder::IsEnabled()) + { + Logger::Print("Loading model surface {} at path \"{}\" failed!", name, path); + } + else + { + Logger::Error(Game::ERR_FATAL, "Loading model {} failed!", name); + } + + return nullptr; } Game::CModelHeader header; diff --git a/src/Components/Modules/ZoneBuilder.cpp b/src/Components/Modules/ZoneBuilder.cpp index 6a26a07c..240c144a 100644 --- a/src/Components/Modules/ZoneBuilder.cpp +++ b/src/Components/Modules/ZoneBuilder.cpp @@ -18,6 +18,8 @@ namespace Components volatile bool ZoneBuilder::CommandThreadTerminate = false; std::thread ZoneBuilder::CommandThread; + iw4of::api ZoneBuilder::ExporterAPI(GetExporterAPIParams()); + std::string ZoneBuilder::DumpingZone{}; ZoneBuilder::Zone::Zone(const std::string& name) : indexStart(0), externalSize(0), // Reserve 100MB by default. @@ -757,6 +759,23 @@ namespace Components return header; } + void ZoneBuilder::RefreshExporterWorkDirectory() + { + if (ZoneBuilder::DumpingZone.empty()) + { + ExporterAPI.set_work_path(std::format("userraw/dump/stray")); + } + else + { + ExporterAPI.set_work_path(std::format("userraw/dump/{}", ZoneBuilder::DumpingZone)); + } + } + + iw4of::api* ZoneBuilder::GetExporter() + { + return &ExporterAPI; + } + iw4of::params_t ZoneBuilder::Zone::getIW4OfApiParams() { iw4of::params_t params{}; @@ -815,7 +834,7 @@ namespace Components void* data = Utils::Memory::GetAllocator()->allocate(size); std::memcpy(data, *loadDef, size); - image->texture.loadDef = reinterpret_cast(data); + image->texture.loadDef = static_cast(data); return 0; } @@ -857,7 +876,7 @@ namespace Components return GetCurrentThreadId() == Utils::Hook::Get(0x1CDE7FC); } - static Game::XZoneInfo baseZones_old[] = + static Game::XZoneInfo baseZones[] = { { "code_pre_gfx_mp", Game::DB_ZONE_CODE, 0 }, { "localized_code_pre_gfx_mp", Game::DB_ZONE_CODE_LOC, 0 }, @@ -869,17 +888,6 @@ namespace Components { "localized_ui_mp", Game::DB_ZONE_GAME, 0 } }; - - static Game::XZoneInfo baseZones[] = - { - { "defaults", Game::DB_ZONE_CODE, 0 }, - { "techsets", Game::DB_ZONE_CODE, 0 }, - { "common_mp", Game::DB_ZONE_COMMON, 0 }, - { "localized_common_mp", Game::DB_ZONE_COMMON_LOC, 0 }, - { "ui_mp", Game::DB_ZONE_GAME, 0 }, - { "localized_ui_mp", Game::DB_ZONE_GAME, 0 } - }; - void ZoneBuilder::Com_Quitf_t() { ExitProcess(0); @@ -938,15 +946,7 @@ namespace Components Command::Add("quit", ZoneBuilder::Com_Quitf_t); // now load default assets and shaders - if (FastFiles::Exists("defaults") && FastFiles::Exists("techsets")) - { - Game::DB_LoadXAssets(baseZones, ARRAYSIZE(baseZones), 0); - } - else - { - Logger::Warning(Game::CON_CHANNEL_DONT_FILTER, "Missing new init zones (defaults.ff & techsets.ff). You will need to load fastfiles to manually obtain techsets.\n"); - Game::DB_LoadXAssets(baseZones_old, ARRAYSIZE(baseZones_old), 0); - } + Game::DB_LoadXAssets(baseZones, ARRAYSIZE(baseZones), 0); Logger::Print("Waiting for fastiles to load...\n"); while (!Game::Sys_IsDatabaseReady()) @@ -983,6 +983,7 @@ namespace Components 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"); Logger::Print("\t-verifyzone [zone]: loads and verifies the specified zone\n"); + Logger::Print("\t-dumpzone [zone]: loads and dump the specified zone\n"); Logger::Print("\t-listassets [assettype]: lists all loaded assets of the specified type\n"); Logger::Print("\t-quit: quits the program\n"); Logger::Print(" --------------------------------------------------------------------------------\n"); @@ -1097,6 +1098,55 @@ namespace Components return file; } + iw4of::params_t ZoneBuilder::GetExporterAPIParams() + { + iw4of::params_t params{}; + + params.write_only_once = true; + + params.find_other_asset = [](int type, const std::string& name) -> void* + { + if (ZoneBuilder::DumpingZone.empty()) + { + return Game::DB_FindXAssetHeader(static_cast(type), name.data()).data; + } + + // Do not deadlock the DB + return nullptr; + }; + + params.fs_read_file = [](const std::string& filename) -> std::string + { + auto file = FileSystem::File(filename); + if (file.exists()) + { + return file.getBuffer(); + } + + return {}; + }; + + params.get_from_string_table = [](const unsigned int& id) -> std::string + { + return Game::SL_ConvertToString(static_cast(id)); + }; + + params.print = [](iw4of::params_t::print_type t, const std::string& message) -> void + { + switch (t) + { + case iw4of::params_t::P_ERR: + Logger::Error(Game::ERR_FATAL, "{}", message); + break; + case iw4of::params_t::P_WARN: + Logger::Print("{}", message); + break; + } + }; + + return params; + } + ZoneBuilder::ZoneBuilder() { // ReSharper disable CppStaticAssertFailure @@ -1200,7 +1250,7 @@ namespace Components // don't remap techsets Utils::Hook::Nop(0x5BC791, 5); - AssetHandler::OnLoad([](Game::XAssetType type, Game::XAssetHeader /*asset*/, const std::string& name, bool* /*restrict*/) + AssetHandler::OnLoad([](Game::XAssetType type, Game::XAssetHeader asset, const std::string& name, bool* /*restrict*/) { if (!ZoneBuilder::TraceZone.empty() && ZoneBuilder::TraceZone == FastFiles::Current()) { @@ -1209,6 +1259,44 @@ namespace Components OutputDebugStringA(Utils::String::Format("%s\n", name)); #endif } + + if (!ZoneBuilder::DumpingZone.empty()) + { + if (ExporterAPI.is_type_supported(type) && name[0] != ',') + { + ExporterAPI.write(type, asset.data); + Components::Logger::Print("."); + } + } + }); + + Command::Add("dumpzone", [](const Command::Params* params) + { + if (params->size() < 2) return; + + std::string zone = params->get(1); + ZoneBuilder::DumpingZone = zone; + ZoneBuilder::RefreshExporterWorkDirectory(); + + Game::XZoneInfo info; + info.name = zone.data(); + info.allocFlags = Game::DB_ZONE_MOD; + info.freeFlags = 0; + + Logger::Print("Dumping zone '{}'...\n", zone); + + Game::DB_LoadXAssets(&info, 1, true); + AssetHandler::FindOriginalAsset(Game::ASSET_TYPE_RAWFILE, zone.data()); // Lock until zone is loaded + + Logger::Print("Unloading zone '{}'...\n", zone); + info.freeFlags = Game::DB_ZONE_MOD; + info.allocFlags = 0; + info.name = nullptr; + + Game::DB_LoadXAssets(&info, 1, true); + AssetHandler::FindOriginalAsset(Game::ASSET_TYPE_RAWFILE, "default"); // Lock until zone is unloaded + Logger::Print("Zone '{}' dumped", ZoneBuilder::DumpingZone); + ZoneBuilder::DumpingZone = std::string(); }); Command::Add("verifyzone", [](const Command::Params* params) @@ -1627,31 +1715,6 @@ namespace Components header.material->info.name, header.material->info.sortKey & 0xFF, header.material->info.gameFlags & 0xFF, header.material->stateFlags & 0xFF); }, nullptr, false); }); - - Command::Add("iwiDump", [](const Command::Params* params) - { - if (params->size() < 2) return; - - auto path = std::format("{}\\mods\\{}\\images", (*Game::fs_basepath)->current.string, params->get(1)); - auto images = FileSystem::GetSysFileList(path, "iwi", false); - - for (auto i = images.begin(); i != images.end();) - { - *i = std::format("images/{}", *i); - - if (FileSystem::File(*i).exists()) - { - i = images.erase(i); - continue; - } - - ++i; - } - - Logger::Print("------------------- BEGIN IWI DUMP -------------------\n"); - Logger::Print("{}\n", nlohmann::json(images).dump()); - Logger::Print("------------------- END IWI DUMP -------------------\n"); - }); } } diff --git a/src/Components/Modules/ZoneBuilder.hpp b/src/Components/Modules/ZoneBuilder.hpp index 2b5fe4de..c6fb46b6 100644 --- a/src/Components/Modules/ZoneBuilder.hpp +++ b/src/Components/Modules/ZoneBuilder.hpp @@ -137,6 +137,9 @@ namespace Components static std::vector> EndAssetTrace(); static Game::XAssetHeader GetEmptyAssetIfCommon(Game::XAssetType type, const std::string& name, Zone* builder); + static void RefreshExporterWorkDirectory(); + + static iw4of::api* GetExporter(); private: static int StoreTexture(Game::GfxImageLoadDef **loadDef, Game::GfxImage *image); @@ -155,6 +158,8 @@ namespace Components static bool IsThreadMainThreadHook(); static Game::Sys_File Sys_CreateFile_Stub(const char* dir, const char* filename); + static iw4of::params_t GetExporterAPIParams(); + static void Com_Quitf_t(); static void CommandThreadCallback(); @@ -164,5 +169,7 @@ namespace Components static volatile bool CommandThreadTerminate; static std::thread CommandThread; + static iw4of::api ExporterAPI; + static std::string DumpingZone; }; } diff --git a/src/Components/Modules/Zones.cpp b/src/Components/Modules/Zones.cpp index 17226290..89bb812a 100644 --- a/src/Components/Modules/Zones.cpp +++ b/src/Components/Modules/Zones.cpp @@ -2947,6 +2947,9 @@ namespace Components iw4Map->mapEnts = &codolMapEnts; memcpy(&iw4Map->smodelNodeCount, &codolMap->smodelNodeCount, 48); + // unused on IW4 + iw4Map->numLeafSurfaces = 0; + AssetHandler::Relocate(&cancerMap->info.numCPlanes, &iw4Map->planeCount, 8); AssetHandler::Relocate(&cancerMap->numStaticModels, &iw4Map->numStaticModels, 8); AssetHandler::Relocate(&cancerMap->info.numMaterials, &iw4Map->numMaterials, 24); From 457f0b82b37078afa1ebaead96d248629e29e1d9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 14 May 2023 11:23:43 +0000 Subject: [PATCH 29/39] Bump deps/iw4-open-formats from `4fee381` to `acd8015` Bumps [deps/iw4-open-formats](https://github.com/XLabsProject/iw4-open-formats) from `4fee381` to `acd8015`. - [Release notes](https://github.com/XLabsProject/iw4-open-formats/releases) - [Commits](https://github.com/XLabsProject/iw4-open-formats/compare/4fee3813071b11a95533ab8be975785ec6262358...acd8015422cab7cbf5b574651d7cb2cf4ecf486e) --- updated-dependencies: - dependency-name: deps/iw4-open-formats dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- deps/iw4-open-formats | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/iw4-open-formats b/deps/iw4-open-formats index 4fee3813..acd80154 160000 --- a/deps/iw4-open-formats +++ b/deps/iw4-open-formats @@ -1 +1 @@ -Subproject commit 4fee3813071b11a95533ab8be975785ec6262358 +Subproject commit acd8015422cab7cbf5b574651d7cb2cf4ecf486e From 88ffb70dc4201b18c396aca01174f2edcffc85cf Mon Sep 17 00:00:00 2001 From: Edo Date: Sun, 14 May 2023 12:54:23 +0100 Subject: [PATCH 30/39] [ZoneBuilder]: Remove old dump command (#1035) --- src/Components/Loader.cpp | 2 - src/Components/Modules/MapDump.cpp | 464 ----------------------------- src/Components/Modules/MapDump.hpp | 10 - 3 files changed, 476 deletions(-) delete mode 100644 src/Components/Modules/MapDump.cpp delete mode 100644 src/Components/Modules/MapDump.hpp diff --git a/src/Components/Loader.cpp b/src/Components/Loader.cpp index 8f9d9bf5..e21453cf 100644 --- a/src/Components/Loader.cpp +++ b/src/Components/Loader.cpp @@ -27,7 +27,6 @@ #include "Modules/Gamepad.hpp" #include "Modules/IPCPipe.hpp" #include "Modules/Lean.hpp" -#include "Modules/MapDump.hpp" #include "Modules/MapRotation.hpp" #include "Modules/Materials.hpp" #include "Modules/ModList.hpp" @@ -136,7 +135,6 @@ namespace Components Register(new Gamepad()); Register(new Lean()); Register(new Localization()); - Register(new MapDump()); Register(new MapRotation()); Register(new Maps()); Register(new Materials()); diff --git a/src/Components/Modules/MapDump.cpp b/src/Components/Modules/MapDump.cpp deleted file mode 100644 index c4dc4bcc..00000000 --- a/src/Components/Modules/MapDump.cpp +++ /dev/null @@ -1,464 +0,0 @@ -#include -#include "MapDump.hpp" - -namespace Components -{ - class MapDumper - { - public: - MapDumper(Game::GfxWorld* world) : world_(world) - { - } - - void dump() - { - if (!this->world_) return; - - Logger::Print("Exporting '{}'...\n", this->world_->baseName); - - this->parseVertices(); - this->parseFaces(); - this->parseStaticModels(); - - this->write(); - } - - private: - struct Vertex - { - Game::vec3_t coordinate; - Game::vec2_t texture; - Game::vec3_t normal; - }; - - struct Face - { - int a{}; - int b{}; - int c{}; - }; - - struct FaceList - { - std::vector indices{}; - }; - - class File - { - public: - File() {} - - File(const std::string& file) - { - Utils::IO::WriteFile(file, {}); - this->stream_ = std::ofstream(file, std::ofstream::out); - } - - void append(const std::string& str) - { - this->stream_.write(str.data(), str.size()); - } - - private: - std::ofstream stream_{}; - }; - - Game::GfxWorld* world_{}; - std::vector vertices_{}; - std::unordered_map faces_{}; - std::vector facesOrder_{}; - - File object_{}; - File material_{}; - - void transformAxes(Game::vec3_t& vec) const - { - std::swap(vec[0], vec[1]); - std::swap(vec[1], vec[2]); - } - - void parseVertices() - { - Logger::Print("Parsing vertices...\n"); - - for (unsigned int i = 0; i < this->world_->draw.vertexCount; ++i) - { - const auto* vertex = &this->world_->draw.vd.vertices[i]; - - Vertex v{}; - - v.coordinate[0] = vertex->xyz[0]; - v.coordinate[1] = vertex->xyz[1]; - v.coordinate[2] = vertex->xyz[2]; - this->transformAxes(v.coordinate); - - v.texture[0] = vertex->texCoord[0]; - v.texture[1] = -vertex->texCoord[1]; - - Game::Vec3UnpackUnitVec(vertex->normal, &v.normal); - this->transformAxes(v.normal); - - this->vertices_.push_back(v); - } - } - - void parseFaces() - { - Logger::Print("Parsing faces...\n"); - - for (unsigned int i = 0; i < this->world_->dpvs.staticSurfaceCount; ++i) - { - const auto* surface = &this->world_->dpvs.surfaces[i]; - - const unsigned int vertOffset = surface->tris.firstVertex + 1; - const unsigned int indexOffset = surface->tris.baseIndex; - - // Fuck cube maps for now - if(this->findImage(surface->material, "colorMap")->mapType == 5) continue; - - auto& f = this->getFaceList(surface->material); - - for (unsigned short j = 0; j < surface->tris.triCount; ++j) - { - Face face{}; - face.a = this->world_->draw.indices[indexOffset + j * 3 + 0] + vertOffset; - face.b = this->world_->draw.indices[indexOffset + j * 3 + 1] + vertOffset; - face.c = this->world_->draw.indices[indexOffset + j * 3 + 2] + vertOffset; - - f.indices.push_back(face); - } - } - } - - FaceList& getFaceList(Game::Material* material) - { - auto& faceList = this->faces_[material]; - - if (this->facesOrder_.size() < this->faces_.size()) - { - this->facesOrder_.push_back(material); - } - - return faceList; - } - - void performWorldTransformation(const Game::GfxPackedPlacement& placement, Vertex& v) const - { - Game::MatrixVecMultiply(placement.axis, v.normal, v.normal); - Game::Vec3Normalize(v.normal); - - Game::MatrixVecMultiply(placement.axis, v.coordinate, v.coordinate); - v.coordinate[0] = v.coordinate[0] * placement.scale + placement.origin[0]; - v.coordinate[1] = v.coordinate[1] * placement.scale + placement.origin[1]; - v.coordinate[2] = v.coordinate[2] * placement.scale + placement.origin[2]; - } - - std::vector parseSurfaceVertices(const Game::XSurface* surface, const Game::GfxPackedPlacement& placement) - { - std::vector vertices; - - for (unsigned short j = 0; j < surface->vertCount; j++) - { - const auto *vertex = &surface->verts0[j]; - - Vertex v{}; - - v.coordinate[0] = vertex->xyz[0]; - v.coordinate[1] = vertex->xyz[1]; - v.coordinate[2] = vertex->xyz[2]; - - // Why... - Game::Vec2UnpackTexCoords(vertex->texCoord, &v.texture); - std::swap(v.texture[0], v.texture[1]); - v.texture[1] *= -1; - - Game::Vec3UnpackUnitVec(vertex->normal, &v.normal); - - this->performWorldTransformation(placement, v); - this->transformAxes(v.coordinate); - this->transformAxes(v.normal); - - vertices.push_back(v); - } - - return vertices; - } - - std::vector parseSurfaceFaces(const Game::XSurface* surface) const - { - std::vector faces; - - for (unsigned short j = 0; j < surface->triCount; ++j) - { - Face face{}; - face.a = surface->triIndices[j * 3 + 0]; - face.b = surface->triIndices[j * 3 + 1]; - face.c = surface->triIndices[j * 3 + 2]; - - faces.push_back(face); - } - - return faces; - } - - void removeVertex(const int index, std::vector& faces, std::vector& vertices) const - { - vertices.erase(vertices.begin() + index); - - for (auto &face : faces) - { - if (face.a > index) --face.a; - if (face.b > index) --face.b; - if (face.c > index) --face.c; - } - } - - void filterSurfaceVertices(std::vector& faces, std::vector& vertices) const - { - for (auto i = 0; i < int(vertices.size()); ++i) - { - auto referenced = false; - - for (const auto &face : faces) - { - if (face.a == i || face.b == i || face.c == i) - { - referenced = true; - break; - } - } - - if (!referenced) - { - this->removeVertex(i--, faces, vertices); - } - } - } - - void parseStaticModel(Game::GfxStaticModelDrawInst* model) - { - for (unsigned char i = 0; i < model->model->numsurfs; ++i) - { - this->getFaceList(model->model->materialHandles[i]); - } - - const auto* lod = &model->model->lodInfo[model->model->numLods - 1]; - - const auto baseIndex = this->vertices_.size() + 1; - const auto surfIndex = lod->surfIndex; - - assert(lod->modelSurfs->numsurfs <= model->model->numsurfs); - - for (unsigned short i = 0; i < lod->modelSurfs->numsurfs; ++i) - { - // TODO: Something is still wrong about the models. Probably baseTriIndex and baseVertIndex might help - - const auto* surface = &lod->modelSurfs->surfs[i]; - auto faces = this->parseSurfaceFaces(surface); - auto vertices = this->parseSurfaceVertices(surface, model->placement); - this->filterSurfaceVertices(faces, vertices); - - auto& f = this->getFaceList(model->model->materialHandles[i + surfIndex]); - - for (const auto& vertex : vertices) - { - this->vertices_.push_back(vertex); - } - - for (auto face : faces) - { - face.a += baseIndex; - face.b += baseIndex; - face.c += baseIndex; - f.indices.push_back(std::move(face)); - } - } - } - - void parseStaticModels() - { - Logger::Print("Parsing static models...\n"); - - for (unsigned i = 0u; i < this->world_->dpvs.smodelCount; ++i) - { - this->parseStaticModel(this->world_->dpvs.smodelDrawInsts + i); - } - } - - void write() - { - this->object_ = File(Utils::String::VA("raw/mapdump/%s/%s.obj", this->world_->baseName, this->world_->baseName)); - this->material_ = File(Utils::String::VA("raw/mapdump/%s/%s.mtl", this->world_->baseName, this->world_->baseName)); - - this->object_.append("# Generated by IW4x\n"); - this->object_.append("# Credit to SE2Dev for his D3DBSP Tool\n"); - this->object_.append(Utils::String::VA("o %s\n", this->world_->baseName)); - this->object_.append(Utils::String::VA("mtllib %s.mtl\n\n", this->world_->baseName)); - - this->material_.append("# IW4x MTL File\n"); - this->material_.append("# Credit to SE2Dev for his D3DBSP Tool\n"); - - this->writeVertices(); - this->writeFaces(); - - Logger::Print("Writing files...\n"); - - this->object_ = {}; - this->material_ = {}; - } - - void writeVertices() - { - Logger::Print("Writing vertices...\n"); - this->object_.append("# Vertices\n"); - - for (const auto& vertex : this->vertices_) - { - this->object_.append(Utils::String::VA("v %.6f %.6f %.6f\n", vertex.coordinate[0], vertex.coordinate[1], vertex.coordinate[2])); - } - - Logger::Print("Writing texture coordinates...\n"); - this->object_.append("\n# Texture coordinates\n"); - - for (const auto& vertex : this->vertices_) - { - this->object_.append(Utils::String::VA("vt %.6f %.6f\n", vertex.texture[0], vertex.texture[1])); - } - - Logger::Print("Writing normals...\n"); - this->object_.append("\n# Normals\n"); - - for (const auto& vertex : this->vertices_) - { - this->object_.append(Utils::String::VA("vn %.6f %.6f %.6f\n", vertex.normal[0], vertex.normal[1], vertex.normal[2])); - } - - this->object_.append("\n"); - } - - Game::GfxImage* findImage(Game::Material* material, const std::string& type) const - { - Game::GfxImage* image = nullptr; - - const auto hash = Game::R_HashString(type.data()); - - for (char l = 0; l < material->textureCount; ++l) - { - if (material->textureTable[l].nameHash == hash) - { - image = material->textureTable[l].u.image; // Hopefully our map - break; - } - } - - return image; - } - - Game::GfxImage* extractImage(Game::Material* material, const std::string& type) const - { - auto* image = this->findImage(material, type); - - if (!image) - { - return image; - } - - std::string _name = Utils::String::VA("raw/mapdump/%s/textures/%s.png", this->world_->baseName, image->name); - D3DXSaveTextureToFileA(_name.data(), D3DXIFF_PNG, image->texture.map, nullptr); - - return image; - } - - void writeMaterial(Game::Material* material) - { - std::string name = material->info.name; - - const auto pos = name.find_last_of('/'); - if (pos != std::string::npos) - { - name = name.substr(pos + 1); - } - - this->object_.append(Utils::String::VA("usemtl %s\n", name.data())); - this->object_.append("s off\n"); - - auto* colorMap = this->extractImage(material, "colorMap"); - auto* normalMap = this->extractImage(material, "normalMap"); - auto* specularMap = this->extractImage(material, "specularMap"); - - this->material_.append(Utils::String::VA("\nnewmtl %s\n", name.data())); - this->material_.append("Ka 1.0000 1.0000 1.0000\n"); - this->material_.append("Kd 1.0000 1.0000 1.0000\n"); - this->material_.append("illum 1\n"); - this->material_.append(Utils::String::VA("map_Ka textures/%s.png\n", colorMap->name)); - this->material_.append(Utils::String::VA("map_Kd textures/%s.png\n", colorMap->name)); - - if (specularMap) - { - this->material_.append(Utils::String::VA("map_Ks textures/%s.png\n", specularMap->name)); - } - - if (normalMap) - { - this->material_.append(Utils::String::VA("bump textures/%s.png\n", normalMap->name)); - } - } - - void writeFaces() - { - Logger::Print("Writing faces...\n"); - Utils::IO::CreateDir(Utils::String::VA("raw/mapdump/%s/textures", this->world_->baseName)); - - this->material_.append(Utils::String::VA("# Material count: %d\n", this->faces_.size())); - - this->object_.append("# Faces\n"); - - for (const auto& material : this->facesOrder_) - { - this->writeMaterial(material); - - const auto& faces = this->getFaceList(material); - for (const auto& index : faces.indices) - { - const int a = index.a; - const int b = index.b; - const int c = index.c; - - this->object_.append(Utils::String::VA("f %d/%d/%d %d/%d/%d %d/%d/%d\n", a, a, a, b, b, b, c, c, c)); - } - - this->object_.append("\n"); - } - } - }; - - MapDump::MapDump() - { - Command::Add("dumpmap", []() - { - if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled()) - { - Logger::Print("DirectX needs to be enabled, please start a client to use this command!\n"); - return; - } - - Game::GfxWorld* world = nullptr; - Game::DB_EnumXAssets(Game::XAssetType::ASSET_TYPE_GFXWORLD, [](Game::XAssetHeader header, void* world) - { - *reinterpret_cast(world) = header.gfxWorld; - }, &world, false); - - if (world) - { - MapDumper dumper(world); - dumper.dump(); - - Logger::Print("Map '{}' exported!\n", world->baseName); - } - else - { - Logger::Print("No map loaded, unable to dump anything!\n"); - } - }); - } -} diff --git a/src/Components/Modules/MapDump.hpp b/src/Components/Modules/MapDump.hpp deleted file mode 100644 index 2662ce2f..00000000 --- a/src/Components/Modules/MapDump.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -namespace Components -{ - class MapDump : public Component - { - public: - MapDump(); - }; -} From 038680bd094e640d72e82b5ed184bb2ac434aa7e Mon Sep 17 00:00:00 2001 From: Edo Date: Sun, 14 May 2023 13:07:24 +0100 Subject: [PATCH 31/39] Revert "[ZoneBuilder]: Remove old dump command" (#1036) --- src/Components/Loader.cpp | 2 + src/Components/Modules/MapDump.cpp | 464 +++++++++++++++++++++++++++++ src/Components/Modules/MapDump.hpp | 10 + 3 files changed, 476 insertions(+) create mode 100644 src/Components/Modules/MapDump.cpp create mode 100644 src/Components/Modules/MapDump.hpp diff --git a/src/Components/Loader.cpp b/src/Components/Loader.cpp index e21453cf..8f9d9bf5 100644 --- a/src/Components/Loader.cpp +++ b/src/Components/Loader.cpp @@ -27,6 +27,7 @@ #include "Modules/Gamepad.hpp" #include "Modules/IPCPipe.hpp" #include "Modules/Lean.hpp" +#include "Modules/MapDump.hpp" #include "Modules/MapRotation.hpp" #include "Modules/Materials.hpp" #include "Modules/ModList.hpp" @@ -135,6 +136,7 @@ namespace Components Register(new Gamepad()); Register(new Lean()); Register(new Localization()); + Register(new MapDump()); Register(new MapRotation()); Register(new Maps()); Register(new Materials()); diff --git a/src/Components/Modules/MapDump.cpp b/src/Components/Modules/MapDump.cpp new file mode 100644 index 00000000..c4dc4bcc --- /dev/null +++ b/src/Components/Modules/MapDump.cpp @@ -0,0 +1,464 @@ +#include +#include "MapDump.hpp" + +namespace Components +{ + class MapDumper + { + public: + MapDumper(Game::GfxWorld* world) : world_(world) + { + } + + void dump() + { + if (!this->world_) return; + + Logger::Print("Exporting '{}'...\n", this->world_->baseName); + + this->parseVertices(); + this->parseFaces(); + this->parseStaticModels(); + + this->write(); + } + + private: + struct Vertex + { + Game::vec3_t coordinate; + Game::vec2_t texture; + Game::vec3_t normal; + }; + + struct Face + { + int a{}; + int b{}; + int c{}; + }; + + struct FaceList + { + std::vector indices{}; + }; + + class File + { + public: + File() {} + + File(const std::string& file) + { + Utils::IO::WriteFile(file, {}); + this->stream_ = std::ofstream(file, std::ofstream::out); + } + + void append(const std::string& str) + { + this->stream_.write(str.data(), str.size()); + } + + private: + std::ofstream stream_{}; + }; + + Game::GfxWorld* world_{}; + std::vector vertices_{}; + std::unordered_map faces_{}; + std::vector facesOrder_{}; + + File object_{}; + File material_{}; + + void transformAxes(Game::vec3_t& vec) const + { + std::swap(vec[0], vec[1]); + std::swap(vec[1], vec[2]); + } + + void parseVertices() + { + Logger::Print("Parsing vertices...\n"); + + for (unsigned int i = 0; i < this->world_->draw.vertexCount; ++i) + { + const auto* vertex = &this->world_->draw.vd.vertices[i]; + + Vertex v{}; + + v.coordinate[0] = vertex->xyz[0]; + v.coordinate[1] = vertex->xyz[1]; + v.coordinate[2] = vertex->xyz[2]; + this->transformAxes(v.coordinate); + + v.texture[0] = vertex->texCoord[0]; + v.texture[1] = -vertex->texCoord[1]; + + Game::Vec3UnpackUnitVec(vertex->normal, &v.normal); + this->transformAxes(v.normal); + + this->vertices_.push_back(v); + } + } + + void parseFaces() + { + Logger::Print("Parsing faces...\n"); + + for (unsigned int i = 0; i < this->world_->dpvs.staticSurfaceCount; ++i) + { + const auto* surface = &this->world_->dpvs.surfaces[i]; + + const unsigned int vertOffset = surface->tris.firstVertex + 1; + const unsigned int indexOffset = surface->tris.baseIndex; + + // Fuck cube maps for now + if(this->findImage(surface->material, "colorMap")->mapType == 5) continue; + + auto& f = this->getFaceList(surface->material); + + for (unsigned short j = 0; j < surface->tris.triCount; ++j) + { + Face face{}; + face.a = this->world_->draw.indices[indexOffset + j * 3 + 0] + vertOffset; + face.b = this->world_->draw.indices[indexOffset + j * 3 + 1] + vertOffset; + face.c = this->world_->draw.indices[indexOffset + j * 3 + 2] + vertOffset; + + f.indices.push_back(face); + } + } + } + + FaceList& getFaceList(Game::Material* material) + { + auto& faceList = this->faces_[material]; + + if (this->facesOrder_.size() < this->faces_.size()) + { + this->facesOrder_.push_back(material); + } + + return faceList; + } + + void performWorldTransformation(const Game::GfxPackedPlacement& placement, Vertex& v) const + { + Game::MatrixVecMultiply(placement.axis, v.normal, v.normal); + Game::Vec3Normalize(v.normal); + + Game::MatrixVecMultiply(placement.axis, v.coordinate, v.coordinate); + v.coordinate[0] = v.coordinate[0] * placement.scale + placement.origin[0]; + v.coordinate[1] = v.coordinate[1] * placement.scale + placement.origin[1]; + v.coordinate[2] = v.coordinate[2] * placement.scale + placement.origin[2]; + } + + std::vector parseSurfaceVertices(const Game::XSurface* surface, const Game::GfxPackedPlacement& placement) + { + std::vector vertices; + + for (unsigned short j = 0; j < surface->vertCount; j++) + { + const auto *vertex = &surface->verts0[j]; + + Vertex v{}; + + v.coordinate[0] = vertex->xyz[0]; + v.coordinate[1] = vertex->xyz[1]; + v.coordinate[2] = vertex->xyz[2]; + + // Why... + Game::Vec2UnpackTexCoords(vertex->texCoord, &v.texture); + std::swap(v.texture[0], v.texture[1]); + v.texture[1] *= -1; + + Game::Vec3UnpackUnitVec(vertex->normal, &v.normal); + + this->performWorldTransformation(placement, v); + this->transformAxes(v.coordinate); + this->transformAxes(v.normal); + + vertices.push_back(v); + } + + return vertices; + } + + std::vector parseSurfaceFaces(const Game::XSurface* surface) const + { + std::vector faces; + + for (unsigned short j = 0; j < surface->triCount; ++j) + { + Face face{}; + face.a = surface->triIndices[j * 3 + 0]; + face.b = surface->triIndices[j * 3 + 1]; + face.c = surface->triIndices[j * 3 + 2]; + + faces.push_back(face); + } + + return faces; + } + + void removeVertex(const int index, std::vector& faces, std::vector& vertices) const + { + vertices.erase(vertices.begin() + index); + + for (auto &face : faces) + { + if (face.a > index) --face.a; + if (face.b > index) --face.b; + if (face.c > index) --face.c; + } + } + + void filterSurfaceVertices(std::vector& faces, std::vector& vertices) const + { + for (auto i = 0; i < int(vertices.size()); ++i) + { + auto referenced = false; + + for (const auto &face : faces) + { + if (face.a == i || face.b == i || face.c == i) + { + referenced = true; + break; + } + } + + if (!referenced) + { + this->removeVertex(i--, faces, vertices); + } + } + } + + void parseStaticModel(Game::GfxStaticModelDrawInst* model) + { + for (unsigned char i = 0; i < model->model->numsurfs; ++i) + { + this->getFaceList(model->model->materialHandles[i]); + } + + const auto* lod = &model->model->lodInfo[model->model->numLods - 1]; + + const auto baseIndex = this->vertices_.size() + 1; + const auto surfIndex = lod->surfIndex; + + assert(lod->modelSurfs->numsurfs <= model->model->numsurfs); + + for (unsigned short i = 0; i < lod->modelSurfs->numsurfs; ++i) + { + // TODO: Something is still wrong about the models. Probably baseTriIndex and baseVertIndex might help + + const auto* surface = &lod->modelSurfs->surfs[i]; + auto faces = this->parseSurfaceFaces(surface); + auto vertices = this->parseSurfaceVertices(surface, model->placement); + this->filterSurfaceVertices(faces, vertices); + + auto& f = this->getFaceList(model->model->materialHandles[i + surfIndex]); + + for (const auto& vertex : vertices) + { + this->vertices_.push_back(vertex); + } + + for (auto face : faces) + { + face.a += baseIndex; + face.b += baseIndex; + face.c += baseIndex; + f.indices.push_back(std::move(face)); + } + } + } + + void parseStaticModels() + { + Logger::Print("Parsing static models...\n"); + + for (unsigned i = 0u; i < this->world_->dpvs.smodelCount; ++i) + { + this->parseStaticModel(this->world_->dpvs.smodelDrawInsts + i); + } + } + + void write() + { + this->object_ = File(Utils::String::VA("raw/mapdump/%s/%s.obj", this->world_->baseName, this->world_->baseName)); + this->material_ = File(Utils::String::VA("raw/mapdump/%s/%s.mtl", this->world_->baseName, this->world_->baseName)); + + this->object_.append("# Generated by IW4x\n"); + this->object_.append("# Credit to SE2Dev for his D3DBSP Tool\n"); + this->object_.append(Utils::String::VA("o %s\n", this->world_->baseName)); + this->object_.append(Utils::String::VA("mtllib %s.mtl\n\n", this->world_->baseName)); + + this->material_.append("# IW4x MTL File\n"); + this->material_.append("# Credit to SE2Dev for his D3DBSP Tool\n"); + + this->writeVertices(); + this->writeFaces(); + + Logger::Print("Writing files...\n"); + + this->object_ = {}; + this->material_ = {}; + } + + void writeVertices() + { + Logger::Print("Writing vertices...\n"); + this->object_.append("# Vertices\n"); + + for (const auto& vertex : this->vertices_) + { + this->object_.append(Utils::String::VA("v %.6f %.6f %.6f\n", vertex.coordinate[0], vertex.coordinate[1], vertex.coordinate[2])); + } + + Logger::Print("Writing texture coordinates...\n"); + this->object_.append("\n# Texture coordinates\n"); + + for (const auto& vertex : this->vertices_) + { + this->object_.append(Utils::String::VA("vt %.6f %.6f\n", vertex.texture[0], vertex.texture[1])); + } + + Logger::Print("Writing normals...\n"); + this->object_.append("\n# Normals\n"); + + for (const auto& vertex : this->vertices_) + { + this->object_.append(Utils::String::VA("vn %.6f %.6f %.6f\n", vertex.normal[0], vertex.normal[1], vertex.normal[2])); + } + + this->object_.append("\n"); + } + + Game::GfxImage* findImage(Game::Material* material, const std::string& type) const + { + Game::GfxImage* image = nullptr; + + const auto hash = Game::R_HashString(type.data()); + + for (char l = 0; l < material->textureCount; ++l) + { + if (material->textureTable[l].nameHash == hash) + { + image = material->textureTable[l].u.image; // Hopefully our map + break; + } + } + + return image; + } + + Game::GfxImage* extractImage(Game::Material* material, const std::string& type) const + { + auto* image = this->findImage(material, type); + + if (!image) + { + return image; + } + + std::string _name = Utils::String::VA("raw/mapdump/%s/textures/%s.png", this->world_->baseName, image->name); + D3DXSaveTextureToFileA(_name.data(), D3DXIFF_PNG, image->texture.map, nullptr); + + return image; + } + + void writeMaterial(Game::Material* material) + { + std::string name = material->info.name; + + const auto pos = name.find_last_of('/'); + if (pos != std::string::npos) + { + name = name.substr(pos + 1); + } + + this->object_.append(Utils::String::VA("usemtl %s\n", name.data())); + this->object_.append("s off\n"); + + auto* colorMap = this->extractImage(material, "colorMap"); + auto* normalMap = this->extractImage(material, "normalMap"); + auto* specularMap = this->extractImage(material, "specularMap"); + + this->material_.append(Utils::String::VA("\nnewmtl %s\n", name.data())); + this->material_.append("Ka 1.0000 1.0000 1.0000\n"); + this->material_.append("Kd 1.0000 1.0000 1.0000\n"); + this->material_.append("illum 1\n"); + this->material_.append(Utils::String::VA("map_Ka textures/%s.png\n", colorMap->name)); + this->material_.append(Utils::String::VA("map_Kd textures/%s.png\n", colorMap->name)); + + if (specularMap) + { + this->material_.append(Utils::String::VA("map_Ks textures/%s.png\n", specularMap->name)); + } + + if (normalMap) + { + this->material_.append(Utils::String::VA("bump textures/%s.png\n", normalMap->name)); + } + } + + void writeFaces() + { + Logger::Print("Writing faces...\n"); + Utils::IO::CreateDir(Utils::String::VA("raw/mapdump/%s/textures", this->world_->baseName)); + + this->material_.append(Utils::String::VA("# Material count: %d\n", this->faces_.size())); + + this->object_.append("# Faces\n"); + + for (const auto& material : this->facesOrder_) + { + this->writeMaterial(material); + + const auto& faces = this->getFaceList(material); + for (const auto& index : faces.indices) + { + const int a = index.a; + const int b = index.b; + const int c = index.c; + + this->object_.append(Utils::String::VA("f %d/%d/%d %d/%d/%d %d/%d/%d\n", a, a, a, b, b, b, c, c, c)); + } + + this->object_.append("\n"); + } + } + }; + + MapDump::MapDump() + { + Command::Add("dumpmap", []() + { + if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled()) + { + Logger::Print("DirectX needs to be enabled, please start a client to use this command!\n"); + return; + } + + Game::GfxWorld* world = nullptr; + Game::DB_EnumXAssets(Game::XAssetType::ASSET_TYPE_GFXWORLD, [](Game::XAssetHeader header, void* world) + { + *reinterpret_cast(world) = header.gfxWorld; + }, &world, false); + + if (world) + { + MapDumper dumper(world); + dumper.dump(); + + Logger::Print("Map '{}' exported!\n", world->baseName); + } + else + { + Logger::Print("No map loaded, unable to dump anything!\n"); + } + }); + } +} diff --git a/src/Components/Modules/MapDump.hpp b/src/Components/Modules/MapDump.hpp new file mode 100644 index 00000000..2662ce2f --- /dev/null +++ b/src/Components/Modules/MapDump.hpp @@ -0,0 +1,10 @@ +#pragma once + +namespace Components +{ + class MapDump : public Component + { + public: + MapDump(); + }; +} From c3dfd6bd0c1bd834d60d52a4205392c49c7f92ef Mon Sep 17 00:00:00 2001 From: Edo Date: Sun, 14 May 2023 13:24:55 +0100 Subject: [PATCH 32/39] [ScriptExtension]: Do not lookup null pointers (#1037) --- src/Components/Modules/GSC/ScriptExtension.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Components/Modules/GSC/ScriptExtension.cpp b/src/Components/Modules/GSC/ScriptExtension.cpp index f5497679..e68220ae 100644 --- a/src/Components/Modules/GSC/ScriptExtension.cpp +++ b/src/Components/Modules/GSC/ScriptExtension.cpp @@ -28,9 +28,15 @@ namespace Components::GSC void ScriptExtension::GetReplacedPos(const char* pos) { - if (ReplacedFunctions.contains(pos)) + if (!pos) { - ReplacedPos = ReplacedFunctions[pos]; + // This seems to happen often and there should not be pointers to NULL in our map + return; + } + + if (const auto itr = ReplacedFunctions.find(pos); itr != ReplacedFunctions.end()) + { + ReplacedPos = itr->second; } } From 2e27fca19fd13b308f2219d94ea036d301cac405 Mon Sep 17 00:00:00 2001 From: Edo Date: Sun, 14 May 2023 17:42:42 +0100 Subject: [PATCH 33/39] [Node]: Reduce console spam on debug (#1039) --- src/Components/Modules/Node.cpp | 22 +++++++++++++++++----- src/Components/Modules/Node.hpp | 6 +++--- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/Components/Modules/Node.cpp b/src/Components/Modules/Node.cpp index 2e655361..3fa2217a 100644 --- a/src/Components/Modules/Node.cpp +++ b/src/Components/Modules/Node.cpp @@ -15,12 +15,12 @@ namespace Components bool Node::WasIngame = false; - bool Node::Entry::isValid() + bool Node::Entry::isValid() const { return (this->lastResponse.has_value() && !this->lastResponse->elapsed(NODE_HALFLIFE * 2)); } - bool Node::Entry::isDead() + bool Node::Entry::isDead() const { if (!this->lastResponse.has_value()) { @@ -37,7 +37,7 @@ namespace Components return false; } - bool Node::Entry::requiresRequest() + bool Node::Entry::requiresRequest() const { return (!this->isDead() && (!this->lastRequest.has_value() || this->lastRequest->elapsed(NODE_HALFLIFE))); } @@ -49,7 +49,9 @@ namespace Components Session::Send(this->address, "nodeListRequest"); Node::SendList(this->address); +#ifdef NODE_SYSTEM_DEBUG Logger::Debug("Sent request to {}", this->address.getString()); +#endif } void Node::Entry::reset() @@ -217,7 +219,9 @@ namespace Components Proto::Node::List list; if (!list.ParseFromString(data)) return; +#ifdef NODE_SYSTEM_DEBUG Logger::Debug("Received response from {}", address.getString()); +#endif std::lock_guard _(Node::Mutex); @@ -235,12 +239,16 @@ namespace Components { if (!Dedicated::IsEnabled() && ServerList::IsOnlineList() && !ServerList::UseMasterServer && list.protocol() == PROTOCOL) { +#ifdef NODE_SYSTEM_DEBUG Logger::Debug("Inserting {} into the serverlist", address.getString()); +#endif ServerList::InsertRequest(address); } else { +#ifdef NODE_SYSTEM_DEBUG Logger::Debug("Dropping serverlist insertion for {}", address.getString()); +#endif } for (auto& node : Node::Nodes) @@ -304,7 +312,7 @@ namespace Components { Scheduler::Once([=] { -#ifdef DEBUG_NODE +#ifdef NODE_SYSTEM_DEBUG Logger::Debug("Sending {} nodeListResponse length to {}\n", nodeListData.length(), address.getCString()); #endif Session::Send(address, "nodeListResponse", nodeListData); @@ -359,7 +367,11 @@ namespace Components Command::Add("addnode", [](const Command::Params* params) { if (params->size() < 2) return; - Node::Add({ params->get(1) }); + auto address = Network::Address{ params->get(1) }; + if (address.isValid()) + { + Node::Add(address); + } }); } diff --git a/src/Components/Modules/Node.hpp b/src/Components/Modules/Node.hpp index 35623d52..b585df3f 100644 --- a/src/Components/Modules/Node.hpp +++ b/src/Components/Modules/Node.hpp @@ -24,10 +24,10 @@ namespace Components std::optional lastRequest; std::optional lastResponse; - bool isValid(); - bool isDead(); + [[nodiscard]] bool isValid() const; + [[nodiscard]] bool isDead() const; - bool requiresRequest(); + [[nodiscard]] bool requiresRequest() const; void sendRequest(); void reset(); From ba60e3e063dd64922b25718ed3110ee4ae1653dc Mon Sep 17 00:00:00 2001 From: Edo Date: Sun, 14 May 2023 18:17:16 +0100 Subject: [PATCH 34/39] [CHANGELOG]: Clarify entry (#1040) --- CHANGELOG.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42c37a22..48c1c431 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -139,10 +139,10 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0. - Clients can unprotect "saved" Dvars using the command line argument `-unprotect-dvars` (#694) - Clients can protect all Dvars from being modified by the server using the command line argument `-protect-dvars` (#823) -- Add helpful information to script-related errors (#721) -- Add command line `-disable-mongoose` to disable IW4x's built-in webserver (#728) -- Add command line `-disable-rate-limit-check` to disable the rate check on RCon requests (#769) -- Muted clients GUID is saved to the `muted-users.json` file in the `userraw` folder (#732) +- Add helpful information to script-related errors. Must set `developer` Dvar to "2" and `developer_script` Dvar to "1" (#721) +- Add command line `-disable-mongoose` argument to disable IW4x's built-in webserver (#728) +- Add command line `-disable-rate-limit-check` argument to disable the rate check on RCon requests (#769) +- GUID of muted clients is saved to the `muted-users.json` file in the `userraw` folder (#732) - Add `sv_nextMap` Dvar (#736) - Add `elifdef` and `elifndef` directives to the menu preprocessor (#747) - Add `r_drawRunners` Dvar (#758) @@ -171,7 +171,7 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0. - Fix bug where demo playback would stop when opening a laptop based killstreak (#699) - Fix bug where mod download speed was inexplicably slow (#707) - Fix bug where `g_hardcore` could not be set by servers (#708) -- Fix bots "user cmd angles" (#707) +- Fix "user cmd angles" for test clients (#707) - Fix bug where `FileRead` GSC function could return buffers that are too big (#767) - Fix bug where the `OnPlayerSay` GSC function would cause issues (#776) From ffef0d6172bee37f58f180ba02ed250dfb2e53d4 Mon Sep 17 00:00:00 2001 From: Edo Date: Sun, 14 May 2023 21:56:56 +0100 Subject: [PATCH 35/39] [ServerList]: Fix crash on empty server list (#1041) --- src/Components/Modules/ServerInfo.cpp | 2 +- src/Components/Modules/ServerList.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Components/Modules/ServerInfo.cpp b/src/Components/Modules/ServerInfo.cpp index 164bc52a..824ead48 100644 --- a/src/Components/Modules/ServerInfo.cpp +++ b/src/Components/Modules/ServerInfo.cpp @@ -54,7 +54,7 @@ namespace Components auto* serverInfo = ServerList::GetCurrentServer(); - if (info) + if (info && serverInfo) { Dvar::Var("uiSi_ServerName").set(serverInfo->hostname); Dvar::Var("uiSi_MaxClients").set(serverInfo->clients); diff --git a/src/Components/Modules/ServerList.cpp b/src/Components/Modules/ServerList.cpp index efabd032..d4252115 100644 --- a/src/Components/Modules/ServerList.cpp +++ b/src/Components/Modules/ServerList.cpp @@ -176,13 +176,13 @@ namespace Components { CurrentServer = index; - auto* info = GetCurrentServer(); + auto* serverInfo = GetCurrentServer(); - if (info) + if (serverInfo) { UIServerSelected.set(true); - UIServerSelectedMap.set(info->mapname); - Dvar::Var("ui_serverSelectedGametype").set(info->gametype); + UIServerSelectedMap.set(serverInfo->mapname); + Dvar::Var("ui_serverSelectedGametype").set(serverInfo->gametype); } else { From d0bb7840cb95da20705eb5827051c86d8336beb6 Mon Sep 17 00:00:00 2001 From: Edo Date: Sun, 14 May 2023 23:00:21 +0100 Subject: [PATCH 36/39] [General]: Remove broken patch (#1038) --- src/Components/Modules/Security.cpp | 7 ------- src/Components/Modules/Security.hpp | 2 -- 2 files changed, 9 deletions(-) diff --git a/src/Components/Modules/Security.cpp b/src/Components/Modules/Security.cpp index 974849bb..240407db 100644 --- a/src/Components/Modules/Security.cpp +++ b/src/Components/Modules/Security.cpp @@ -29,12 +29,6 @@ namespace Components return size; } - int Security::SV_CanReplaceServerCommand_Hk([[maybe_unused]] Game::client_s* client, [[maybe_unused]] const char* cmd) - { - // This is a fix copied from V2. As I don't have time to investigate, let's simply trust them - return -1; - } - long Security::AtolAdjustPlayerLimit(const char* string) { return std::min(std::atol(string), 18); @@ -140,7 +134,6 @@ namespace Components // Exploit fixes Utils::Hook(0x414D92, Msg_ReadBitsCompressCheckSV, HOOK_CALL).install()->quick(); // SV_ExecuteClientCommands Utils::Hook(0x4A9F56, Msg_ReadBitsCompressCheckCL, HOOK_CALL).install()->quick(); // CL_ParseServerMessage - Utils::Hook(0x407376, SV_CanReplaceServerCommand_Hk, HOOK_CALL).install()->quick(); // SV_CanReplaceServerCommand Utils::Hook::Set(0x412370, 0xC3); // SV_SteamAuthClient Utils::Hook::Set(0x5A8C70, 0xC3); // CL_HandleRelayPacket diff --git a/src/Components/Modules/Security.hpp b/src/Components/Modules/Security.hpp index 1dcb5227..861a7ad2 100644 --- a/src/Components/Modules/Security.hpp +++ b/src/Components/Modules/Security.hpp @@ -11,8 +11,6 @@ namespace Components static int Msg_ReadBitsCompressCheckCL(const unsigned char* from, unsigned char* to, int size); private: - static int SV_CanReplaceServerCommand_Hk(Game::client_s* client, const char* cmd); - static long AtolAdjustPlayerLimit(const char* string); static void SelectStringTableEntryInDvar_Stub(); From 57d04e5a59bc6ccaa759bd596d1dedff6e49fe05 Mon Sep 17 00:00:00 2001 From: Edo Date: Mon, 15 May 2023 23:27:37 +0100 Subject: [PATCH 37/39] [Events]: User modern concurrency container (#1042) --- .gitmodules | 2 +- deps/mongoose | 2 +- src/Components/Loader.cpp | 1 + src/Components/Loader.hpp | 1 - src/Components/Modules/Bans.cpp | 1 + src/Components/Modules/Bots.cpp | 1 + src/Components/Modules/CardTitles.cpp | 1 + src/Components/Modules/Chat.cpp | 1 + src/Components/Modules/ClanTags.cpp | 2 + src/Components/Modules/Debug.cpp | 1 + src/Components/Modules/Dedicated.cpp | 1 + src/Components/Modules/Download.cpp | 1 + src/Components/Modules/Elevators.cpp | 2 + src/Components/Modules/Events.cpp | 149 ++++++--- src/Components/Modules/Events.hpp | 38 +-- src/Components/Modules/Friends.cpp | 1 + src/Components/Modules/GSC/IO.cpp | 3 + src/Components/Modules/GSC/Script.cpp | 16 +- src/Components/Modules/GSC/ScriptError.cpp | 282 +++++++++--------- src/Components/Modules/GSC/ScriptError.hpp | 6 +- .../Modules/GSC/ScriptExtension.cpp | 3 + src/Components/Modules/GSC/UserInfo.cpp | 2 + src/Components/Modules/Logger.cpp | 2 + src/Components/Modules/MapRotation.cpp | 2 + src/Components/Modules/PlayerMovement.cpp | 2 + src/Components/Modules/RCon.cpp | 1 + src/Components/Modules/Renderer.cpp | 2 + src/Components/Modules/ServerList.cpp | 1 + src/Components/Modules/StartupMessages.cpp | 2 + src/Components/Modules/UIFeeder.cpp | 2 + src/Components/Modules/Voice.cpp | 2 + src/Utils/Utils.hpp | 6 - 32 files changed, 323 insertions(+), 216 deletions(-) diff --git a/.gitmodules b/.gitmodules index 912d4f5f..95e898f6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -17,7 +17,7 @@ [submodule "deps/mongoose"] path = deps/mongoose url = https://github.com/cesanta/mongoose.git - branch = 7.8 + branch = 7.9 [submodule "deps/protobuf"] path = deps/protobuf url = https://github.com/google/protobuf.git diff --git a/deps/mongoose b/deps/mongoose index 0a265e79..4236405b 160000 --- a/deps/mongoose +++ b/deps/mongoose @@ -1 +1 @@ -Subproject commit 0a265e79a67d7bfcdca27f2ccb98ccb474677ec6 +Subproject commit 4236405b90e051310aadda818e21c811e404b4d8 diff --git a/src/Components/Loader.cpp b/src/Components/Loader.cpp index 8f9d9bf5..fc09bb18 100644 --- a/src/Components/Loader.cpp +++ b/src/Components/Loader.cpp @@ -21,6 +21,7 @@ #include "Modules/Discovery.hpp" #include "Modules/Download.hpp" #include "Modules/Elevators.hpp" +#include "Modules/Events.hpp" #include "Modules/Exception.hpp" #include "Modules/FastFiles.hpp" #include "Modules/Friends.hpp" diff --git a/src/Components/Loader.hpp b/src/Components/Loader.hpp index d4282cdc..41c14b78 100644 --- a/src/Components/Loader.hpp +++ b/src/Components/Loader.hpp @@ -73,7 +73,6 @@ namespace Components #include "Modules/AssetHandler.hpp" #include "Modules/Dedicated.hpp" -#include "Modules/Events.hpp" #include "Modules/FileSystem.hpp" #include "Modules/Localization.hpp" #include "Modules/Maps.hpp" diff --git a/src/Components/Modules/Bans.cpp b/src/Components/Modules/Bans.cpp index 69cc4e6e..eefcc2a6 100644 --- a/src/Components/Modules/Bans.cpp +++ b/src/Components/Modules/Bans.cpp @@ -1,5 +1,6 @@ #include #include "Bans.hpp" +#include "Events.hpp" namespace Components { diff --git a/src/Components/Modules/Bots.cpp b/src/Components/Modules/Bots.cpp index ee8c6397..099948ab 100644 --- a/src/Components/Modules/Bots.cpp +++ b/src/Components/Modules/Bots.cpp @@ -2,6 +2,7 @@ #include "Bots.hpp" #include "ClanTags.hpp" +#include "Events.hpp" #include "GSC/Script.hpp" diff --git a/src/Components/Modules/CardTitles.cpp b/src/Components/Modules/CardTitles.cpp index 3ff49ffb..686e3974 100644 --- a/src/Components/Modules/CardTitles.cpp +++ b/src/Components/Modules/CardTitles.cpp @@ -1,5 +1,6 @@ #include #include "CardTitles.hpp" +#include "Events.hpp" #include "ServerCommands.hpp" namespace Components diff --git a/src/Components/Modules/Chat.cpp b/src/Components/Modules/Chat.cpp index 3ace57fc..7e0b0290 100644 --- a/src/Components/Modules/Chat.cpp +++ b/src/Components/Modules/Chat.cpp @@ -1,5 +1,6 @@ #include #include "Chat.hpp" +#include "Events.hpp" #include "PlayerName.hpp" #include "TextRenderer.hpp" #include "Voice.hpp" diff --git a/src/Components/Modules/ClanTags.cpp b/src/Components/Modules/ClanTags.cpp index 8e049e3c..d75dcf6d 100644 --- a/src/Components/Modules/ClanTags.cpp +++ b/src/Components/Modules/ClanTags.cpp @@ -1,5 +1,7 @@ #include + #include "ClanTags.hpp" +#include "Events.hpp" #include "PlayerName.hpp" #include "ServerCommands.hpp" diff --git a/src/Components/Modules/Debug.cpp b/src/Components/Modules/Debug.cpp index 768bb510..bfd45bf2 100644 --- a/src/Components/Modules/Debug.cpp +++ b/src/Components/Modules/Debug.cpp @@ -1,5 +1,6 @@ #include #include "Debug.hpp" +#include "Events.hpp" #include "TextRenderer.hpp" #include "Game/Engine/ScopedCriticalSection.hpp" diff --git a/src/Components/Modules/Dedicated.cpp b/src/Components/Modules/Dedicated.cpp index e2e5b2e8..a758e58c 100644 --- a/src/Components/Modules/Dedicated.cpp +++ b/src/Components/Modules/Dedicated.cpp @@ -3,6 +3,7 @@ #include "CardTitles.hpp" #include "ClanTags.hpp" +#include "Events.hpp" #include "Party.hpp" #include "ServerCommands.hpp" diff --git a/src/Components/Modules/Download.cpp b/src/Components/Modules/Download.cpp index ae0d1c6c..41433c9c 100644 --- a/src/Components/Modules/Download.cpp +++ b/src/Components/Modules/Download.cpp @@ -3,6 +3,7 @@ #include #include "Download.hpp" +#include "Events.hpp" #include "MapRotation.hpp" #include "Party.hpp" #include "ServerInfo.hpp" diff --git a/src/Components/Modules/Elevators.cpp b/src/Components/Modules/Elevators.cpp index f6cc4464..54b618bf 100644 --- a/src/Components/Modules/Elevators.cpp +++ b/src/Components/Modules/Elevators.cpp @@ -1,5 +1,7 @@ #include + #include "Elevators.hpp" +#include "Events.hpp" namespace Components { diff --git a/src/Components/Modules/Events.cpp b/src/Components/Modules/Events.cpp index 8d889a10..41ce5ded 100644 --- a/src/Components/Modules/Events.cpp +++ b/src/Components/Modules/Events.cpp @@ -1,54 +1,79 @@ #include +#include "Events.hpp" namespace Components { - Utils::Signal Events::ClientDisconnectSignal; - Utils::Signal Events::ClientConnectSignal; - Utils::Signal Events::SteamDisconnectSignal; - Utils::Signal Events::ShutdownSystemSignal; - Utils::Signal Events::ClientInitSignal; - Utils::Signal Events::ServerInitSignal; - Utils::Signal Events::DvarInitSignal; - Utils::Signal Events::NetworkInitSignal; + Utils::Concurrency::Container Events::ClientDisconnectTasks_; + Utils::Concurrency::Container Events::ClientConnectTasks_; + Utils::Concurrency::Container Events::SteamDisconnectTasks_; + Utils::Concurrency::Container Events::ShutdownSystemTasks_; + Utils::Concurrency::Container Events::ClientInitTasks_; + Utils::Concurrency::Container Events::ServerInitTasks_; + Utils::Concurrency::Container Events::DvarInitTasks_; + Utils::Concurrency::Container Events::NetworkInitTasks_; - void Events::OnClientDisconnect(const Utils::Slot& callback) + void Events::OnClientDisconnect(const std::function& callback) { - ClientDisconnectSignal.connect(callback); + ClientDisconnectTasks_.access([&callback](ClientCallback& tasks) + { + tasks.emplace_back(callback); + }); } - void Events::OnClientConnect(const Utils::Slot& callback) + void Events::OnClientConnect(const std::function& callback) { - ClientConnectSignal.connect(callback); + ClientConnectTasks_.access([&callback](ClientConnectCallback& tasks) + { + tasks.emplace_back(callback); + }); } - void Events::OnSteamDisconnect(const Utils::Slot& callback) + void Events::OnSteamDisconnect(const std::function& callback) { - SteamDisconnectSignal.connect(callback); + SteamDisconnectTasks_.access([&callback](Callback& tasks) + { + tasks.emplace_back(callback); + }); } - void Events::OnVMShutdown(const Utils::Slot& callback) + void Events::OnVMShutdown(const std::function& callback) { - ShutdownSystemSignal.connect(callback); + ShutdownSystemTasks_.access([&callback](Callback& tasks) + { + tasks.emplace_back(callback); + }); } - void Events::OnClientInit(const Utils::Slot& callback) + void Events::OnClientInit(const std::function& callback) { - ClientInitSignal.connect(callback); + ClientInitTasks_.access([&callback](Callback& tasks) + { + tasks.emplace_back(callback); + }); } - void Events::OnSVInit(const Utils::Slot& callback) + void Events::OnSVInit(const std::function& callback) { - ServerInitSignal.connect(callback); + ServerInitTasks_.access([&callback](Callback& tasks) + { + tasks.emplace_back(callback); + }); } - void Events::OnDvarInit(const Utils::Slot& callback) + void Events::OnDvarInit(const std::function& callback) { - DvarInitSignal.connect(callback); + DvarInitTasks_.access([&callback](Callback& tasks) + { + tasks.emplace_back(callback); + }); } - void Events::OnNetworkInit(const Utils::Slot& callback) + void Events::OnNetworkInit(const std::function& callback) { - NetworkInitSignal.connect(callback); + NetworkInitTasks_.access([&callback](Callback& tasks) + { + tasks.emplace_back(callback); + }); } /* @@ -57,60 +82,112 @@ namespace Components */ void Events::ClientDisconnect_Hk(const int clientNum) { - ClientDisconnectSignal(clientNum); + ClientDisconnectTasks_.access([&clientNum](ClientCallback& tasks) + { + for (const auto& func : tasks) + { + func(clientNum); + } + }); Utils::Hook::Call(0x4AA430)(clientNum); // ClientDisconnect } void Events::SV_UserinfoChanged_Hk(Game::client_s* cl) { - ClientConnectSignal(cl); + ClientConnectTasks_.access([&cl](ClientConnectCallback& tasks) + { + for (const auto& func : tasks) + { + func(cl); + } + }); Utils::Hook::Call(0x401950)(cl); // SV_UserinfoChanged } void Events::SteamDisconnect_Hk() { - SteamDisconnectSignal(); + SteamDisconnectTasks_.access([](Callback& tasks) + { + for (const auto& func : tasks) + { + func(); + } + }); Utils::Hook::Call(0x467CC0)(); // LiveSteam_Client_SteamDisconnect } void Events::Scr_ShutdownSystem_Hk(unsigned char sys) { - ShutdownSystemSignal(); + ShutdownSystemTasks_.access([](Callback& tasks) + { + for (const auto& func : tasks) + { + func(); + } + }); Utils::Hook::Call(0x421EE0)(sys); // Scr_ShutdownSystem } void Events::CL_InitOnceForAllClients_HK() { - ClientInitSignal(); - ClientInitSignal.clear(); + ClientInitTasks_.access([](Callback& tasks) + { + for (const auto& func : tasks) + { + func(); + } + + tasks = {}; // Only called once. Clear + }); Utils::Hook::Call(0x404CA0)(); // CL_InitOnceForAllClients } void Events::SV_Init_Hk() { - ServerInitSignal(); - ServerInitSignal.clear(); + ServerInitTasks_.access([](Callback& tasks) + { + for (const auto& func : tasks) + { + func(); + } + + tasks = {}; // Only called once. Clear + }); Utils::Hook::Call(0x474320)(); // SV_InitGameMode } void Events::Com_InitDvars_Hk() { - DvarInitSignal(); - DvarInitSignal.clear(); + DvarInitTasks_.access([](Callback& tasks) + { + for (const auto& func : tasks) + { + func(); + } + + tasks = {}; // Only called once. Clear + }); Utils::Hook::Call(0x60AD10)(); // Com_InitDvars } void Events::NetworkStart() { - NetworkInitSignal(); - NetworkInitSignal.clear(); + NetworkInitTasks_.access([](Callback& tasks) + { + for (const auto& func : tasks) + { + func(); + } + + tasks = {}; // Only called once. Clear + }); } __declspec(naked) void Events::NET_OpenSocks_Hk() diff --git a/src/Components/Modules/Events.hpp b/src/Components/Modules/Events.hpp index 439ad120..1803cc96 100644 --- a/src/Components/Modules/Events.hpp +++ b/src/Components/Modules/Events.hpp @@ -5,42 +5,42 @@ namespace Components class Events : public Component { public: - typedef void(ClientCallback)(int clientNum); - typedef void(ClientConnectCallback)(Game::client_s* cl); - typedef void(Callback)(); + using Callback = std::vector>; + using ClientConnectCallback = std::vector>; + using ClientCallback = std::vector>; Events(); // Server side - static void OnClientDisconnect(const Utils::Slot& callback); + static void OnClientDisconnect(const std::function& callback); // Server side - static void OnClientConnect(const Utils::Slot& callback); + static void OnClientConnect(const std::function& callback); // Client side - static void OnSteamDisconnect(const Utils::Slot& callback); + static void OnSteamDisconnect(const std::function& callback); - static void OnVMShutdown(const Utils::Slot& callback); + static void OnVMShutdown(const std::function& callback); - static void OnClientInit(const Utils::Slot& callback); + static void OnClientInit(const std::function& callback); // Client & Server (triggered once) - static void OnSVInit(const Utils::Slot& callback); + static void OnSVInit(const std::function& callback); // Client & Server (triggered once) - static void OnDvarInit(const Utils::Slot& callback); + static void OnDvarInit(const std::function& callback); - static void OnNetworkInit(const Utils::Slot& callback); + static void OnNetworkInit(const std::function& callback); private: - static Utils::Signal ClientDisconnectSignal; - static Utils::Signal ClientConnectSignal; - static Utils::Signal SteamDisconnectSignal; - static Utils::Signal ShutdownSystemSignal; - static Utils::Signal ClientInitSignal; - static Utils::Signal ServerInitSignal; - static Utils::Signal DvarInitSignal; - static Utils::Signal NetworkInitSignal; + static Utils::Concurrency::Container ClientDisconnectTasks_; + static Utils::Concurrency::Container ClientConnectTasks_; + static Utils::Concurrency::Container SteamDisconnectTasks_; + static Utils::Concurrency::Container ShutdownSystemTasks_; + static Utils::Concurrency::Container ClientInitTasks_; + static Utils::Concurrency::Container ServerInitTasks_; + static Utils::Concurrency::Container DvarInitTasks_; + static Utils::Concurrency::Container NetworkInitTasks_; static void ClientDisconnect_Hk(int clientNum); static void SV_UserinfoChanged_Hk(Game::client_s* cl); diff --git a/src/Components/Modules/Friends.cpp b/src/Components/Modules/Friends.cpp index 8f884641..90cf83c7 100644 --- a/src/Components/Modules/Friends.cpp +++ b/src/Components/Modules/Friends.cpp @@ -5,6 +5,7 @@ #include #pragma warning(pop) +#include "Events.hpp" #include "Friends.hpp" #include "Materials.hpp" #include "Node.hpp" diff --git a/src/Components/Modules/GSC/IO.cpp b/src/Components/Modules/GSC/IO.cpp index 662bc079..be8c2a53 100644 --- a/src/Components/Modules/GSC/IO.cpp +++ b/src/Components/Modules/GSC/IO.cpp @@ -1,4 +1,7 @@ #include + +#include + #include "IO.hpp" #include "Script.hpp" diff --git a/src/Components/Modules/GSC/Script.cpp b/src/Components/Modules/GSC/Script.cpp index 0bcdd1b6..521789d0 100644 --- a/src/Components/Modules/GSC/Script.cpp +++ b/src/Components/Modules/GSC/Script.cpp @@ -166,12 +166,12 @@ namespace Components::GSC if (pName != nullptr) { const auto name = Utils::String::ToLower(*pName); - for (const auto& func : CustomScrFunctions) + for (const auto& funcs : CustomScrFunctions) { - if (Utils::Contains(&func.aliases, name)) + if (std::ranges::find(funcs.aliases, name) != funcs.aliases.end()) { - *type = func.type; - return func.actionFunc; + *type = funcs.type; + return funcs.actionFunc; } } } @@ -193,12 +193,12 @@ namespace Components::GSC if (pName != nullptr) { const auto name = Utils::String::ToLower(*pName); - for (const auto& meth : CustomScrMethods) + for (const auto& meths : CustomScrMethods) { - if (Utils::Contains(&meth.aliases, name)) + if (std::ranges::find(meths.aliases, name) != meths.aliases.end()) { - *type = meth.type; - return meth.actionFunc; + *type = meths.type; + return meths.actionFunc; } } } diff --git a/src/Components/Modules/GSC/ScriptError.cpp b/src/Components/Modules/GSC/ScriptError.cpp index 3a197a5a..fe41ab90 100644 --- a/src/Components/Modules/GSC/ScriptError.cpp +++ b/src/Components/Modules/GSC/ScriptError.cpp @@ -9,10 +9,10 @@ namespace Components::GSC { using namespace Utils::String; - int ScriptError::developer_; + int ScriptError::Developer_; - Game::scrParserGlob_t ScriptError::scrParserGlob; - Game::scrParserPub_t ScriptError::scrParserPub; + Game::scrParserGlob_t ScriptError::ScrParserGlob; + Game::scrParserPub_t ScriptError::ScrParserPub; int ScriptError::Scr_IsInOpcodeMemory(const char* pos) { @@ -27,7 +27,7 @@ namespace Components::GSC Game::OpcodeLookup* opcodeLookup; Game::SourceLookup* sourcePosLookup; - if (!developer_) + if (!Developer_) { return; } @@ -48,83 +48,83 @@ namespace Components::GSC type &= ~Game::SOURCE_TYPE_BREAKPOINT; } - assert(scrParserGlob.opcodeLookup); - assert(scrParserGlob.sourcePosLookup); + assert(ScrParserGlob.opcodeLookup); + assert(ScrParserGlob.sourcePosLookup); assert(Game::scrCompilePub->opcodePos); - auto size = sizeof(Game::OpcodeLookup) * (scrParserGlob.opcodeLookupLen + 1); - if (size > scrParserGlob.opcodeLookupMaxSize) + auto size = sizeof(Game::OpcodeLookup) * (ScrParserGlob.opcodeLookupLen + 1); + if (size > ScrParserGlob.opcodeLookupMaxSize) { - if (scrParserGlob.opcodeLookupMaxSize >= Game::MAX_OPCODE_LOOKUP_SIZE) + if (ScrParserGlob.opcodeLookupMaxSize >= Game::MAX_OPCODE_LOOKUP_SIZE) { Game::Sys_Error("MAX_OPCODE_LOOKUP_SIZE exceeded"); } - Game::Z_VirtualCommit((char*)scrParserGlob.opcodeLookup + scrParserGlob.opcodeLookupMaxSize, 0x20000); - scrParserGlob.opcodeLookupMaxSize += 0x20000; - assert(size <= scrParserGlob.opcodeLookupMaxSize); + Game::Z_VirtualCommit((char*)ScrParserGlob.opcodeLookup + ScrParserGlob.opcodeLookupMaxSize, 0x20000); + ScrParserGlob.opcodeLookupMaxSize += 0x20000; + assert(size <= ScrParserGlob.opcodeLookupMaxSize); } - size = sizeof(Game::SourceLookup) * (scrParserGlob.sourcePosLookupLen + 1); - if (size > scrParserGlob.sourcePosLookupMaxSize) + size = sizeof(Game::SourceLookup) * (ScrParserGlob.sourcePosLookupLen + 1); + if (size > ScrParserGlob.sourcePosLookupMaxSize) { - if (scrParserGlob.sourcePosLookupMaxSize >= Game::MAX_SOURCEPOS_LOOKUP_SIZE) + if (ScrParserGlob.sourcePosLookupMaxSize >= Game::MAX_SOURCEPOS_LOOKUP_SIZE) { Game::Sys_Error("MAX_SOURCEPOS_LOOKUP_SIZE exceeded"); } - Game::Z_VirtualCommit((char*)scrParserGlob.sourcePosLookup + scrParserGlob.sourcePosLookupMaxSize, 0x20000); - scrParserGlob.sourcePosLookupMaxSize += 0x20000; - assert(size <= scrParserGlob.sourcePosLookupMaxSize); + Game::Z_VirtualCommit((char*)ScrParserGlob.sourcePosLookup + ScrParserGlob.sourcePosLookupMaxSize, 0x20000); + ScrParserGlob.sourcePosLookupMaxSize += 0x20000; + assert(size <= ScrParserGlob.sourcePosLookupMaxSize); } - if (scrParserGlob.currentCodePos == Game::scrCompilePub->opcodePos) + if (ScrParserGlob.currentCodePos == Game::scrCompilePub->opcodePos) { - assert(scrParserGlob.currentSourcePosCount); - --scrParserGlob.opcodeLookupLen; - opcodeLookup = &scrParserGlob.opcodeLookup[scrParserGlob.opcodeLookupLen]; - assert(opcodeLookup->sourcePosIndex + scrParserGlob.currentSourcePosCount == scrParserGlob.sourcePosLookupLen); - assert(opcodeLookup->codePos == (char*)scrParserGlob.currentCodePos); + assert(ScrParserGlob.currentSourcePosCount); + --ScrParserGlob.opcodeLookupLen; + opcodeLookup = &ScrParserGlob.opcodeLookup[ScrParserGlob.opcodeLookupLen]; + assert(opcodeLookup->sourcePosIndex + ScrParserGlob.currentSourcePosCount == ScrParserGlob.sourcePosLookupLen); + assert(opcodeLookup->codePos == (char*)ScrParserGlob.currentCodePos); } else { - scrParserGlob.currentSourcePosCount = 0; - scrParserGlob.currentCodePos = Game::scrCompilePub->opcodePos; - opcodeLookup = &scrParserGlob.opcodeLookup[scrParserGlob.opcodeLookupLen]; - opcodeLookup->sourcePosIndex = scrParserGlob.sourcePosLookupLen; - opcodeLookup->codePos = scrParserGlob.currentCodePos; + ScrParserGlob.currentSourcePosCount = 0; + ScrParserGlob.currentCodePos = Game::scrCompilePub->opcodePos; + opcodeLookup = &ScrParserGlob.opcodeLookup[ScrParserGlob.opcodeLookupLen]; + opcodeLookup->sourcePosIndex = ScrParserGlob.sourcePosLookupLen; + opcodeLookup->codePos = ScrParserGlob.currentCodePos; } - auto sourcePosLookupIndex = scrParserGlob.currentSourcePosCount + opcodeLookup->sourcePosIndex; - sourcePosLookup = &scrParserGlob.sourcePosLookup[sourcePosLookupIndex]; + auto sourcePosLookupIndex = ScrParserGlob.currentSourcePosCount + opcodeLookup->sourcePosIndex; + sourcePosLookup = &ScrParserGlob.sourcePosLookup[sourcePosLookupIndex]; sourcePosLookup->sourcePos = sourcePos; if (sourcePos == static_cast(-1)) { - assert(scrParserGlob.delayedSourceIndex == -1); + assert(ScrParserGlob.delayedSourceIndex == -1); assert(type & Game::SOURCE_TYPE_BREAKPOINT); - scrParserGlob.delayedSourceIndex = static_cast(sourcePosLookupIndex); + ScrParserGlob.delayedSourceIndex = static_cast(sourcePosLookupIndex); } else if (sourcePos == static_cast(-2)) { - scrParserGlob.threadStartSourceIndex = static_cast(sourcePosLookupIndex); + ScrParserGlob.threadStartSourceIndex = static_cast(sourcePosLookupIndex); } - else if (scrParserGlob.delayedSourceIndex >= 0 && (type & Game::SOURCE_TYPE_BREAKPOINT)) + else if (ScrParserGlob.delayedSourceIndex >= 0 && (type & Game::SOURCE_TYPE_BREAKPOINT)) { - scrParserGlob.sourcePosLookup[scrParserGlob.delayedSourceIndex].sourcePos = sourcePos; - scrParserGlob.delayedSourceIndex = -1; + ScrParserGlob.sourcePosLookup[ScrParserGlob.delayedSourceIndex].sourcePos = sourcePos; + ScrParserGlob.delayedSourceIndex = -1; } sourcePosLookup->type |= type; - ++scrParserGlob.currentSourcePosCount; - opcodeLookup->sourcePosCount = static_cast(scrParserGlob.currentSourcePosCount); - ++scrParserGlob.opcodeLookupLen; - ++scrParserGlob.sourcePosLookupLen; + ++ScrParserGlob.currentSourcePosCount; + opcodeLookup->sourcePosCount = static_cast(ScrParserGlob.currentSourcePosCount); + ++ScrParserGlob.opcodeLookupLen; + ++ScrParserGlob.sourcePosLookupLen; } void ScriptError::RemoveOpcodePos() { - if (!developer_) + if (!Developer_) { return; } @@ -135,35 +135,35 @@ namespace Components::GSC return; } - assert(scrParserGlob.opcodeLookup); - assert(scrParserGlob.sourcePosLookup); + assert(ScrParserGlob.opcodeLookup); + assert(ScrParserGlob.sourcePosLookup); assert(Game::scrCompilePub->opcodePos); - assert(scrParserGlob.sourcePosLookupLen); + assert(ScrParserGlob.sourcePosLookupLen); - --scrParserGlob.sourcePosLookupLen; - assert(scrParserGlob.opcodeLookupLen); + --ScrParserGlob.sourcePosLookupLen; + assert(ScrParserGlob.opcodeLookupLen); - --scrParserGlob.opcodeLookupLen; - assert(scrParserGlob.currentSourcePosCount); - --scrParserGlob.currentSourcePosCount; + --ScrParserGlob.opcodeLookupLen; + assert(ScrParserGlob.currentSourcePosCount); + --ScrParserGlob.currentSourcePosCount; - auto* opcodeLookup = &scrParserGlob.opcodeLookup[scrParserGlob.opcodeLookupLen]; + auto* opcodeLookup = &ScrParserGlob.opcodeLookup[ScrParserGlob.opcodeLookupLen]; - assert(scrParserGlob.currentCodePos == Game::scrCompilePub->opcodePos); - assert(opcodeLookup->sourcePosIndex + scrParserGlob.currentSourcePosCount == scrParserGlob.sourcePosLookupLen); - assert(opcodeLookup->codePos == (char*)scrParserGlob.currentCodePos); + assert(ScrParserGlob.currentCodePos == Game::scrCompilePub->opcodePos); + assert(opcodeLookup->sourcePosIndex + ScrParserGlob.currentSourcePosCount == ScrParserGlob.sourcePosLookupLen); + assert(opcodeLookup->codePos == (char*)ScrParserGlob.currentCodePos); - if (!scrParserGlob.currentSourcePosCount) + if (!ScrParserGlob.currentSourcePosCount) { - scrParserGlob.currentCodePos = nullptr; + ScrParserGlob.currentCodePos = nullptr; } - opcodeLookup->sourcePosCount = static_cast(scrParserGlob.currentSourcePosCount); + opcodeLookup->sourcePosCount = static_cast(ScrParserGlob.currentSourcePosCount); } void ScriptError::AddThreadStartOpcodePos(unsigned int sourcePos) { - if (!developer_) + if (!Developer_) { return; } @@ -174,12 +174,12 @@ namespace Components::GSC } else { - assert(scrParserGlob.threadStartSourceIndex >= 0); - auto* sourcePosLookup = &scrParserGlob.sourcePosLookup[scrParserGlob.threadStartSourceIndex]; + assert(ScrParserGlob.threadStartSourceIndex >= 0); + auto* sourcePosLookup = &ScrParserGlob.sourcePosLookup[ScrParserGlob.threadStartSourceIndex]; sourcePosLookup->sourcePos = sourcePos; assert(!sourcePosLookup->type); sourcePosLookup->type = 8; - scrParserGlob.threadStartSourceIndex = -1; + ScrParserGlob.threadStartSourceIndex = -1; } } @@ -188,35 +188,35 @@ namespace Components::GSC const char* startLine; int col; - assert(developer_); - return Scr_GetLineNumInternal(scrParserPub.sourceBufferLookup[bufferIndex].sourceBuf, sourcePos, &startLine, &col, nullptr); + assert(Developer_); + return Scr_GetLineNumInternal(ScrParserPub.sourceBufferLookup[bufferIndex].sourceBuf, sourcePos, &startLine, &col, nullptr); } unsigned int ScriptError::Scr_GetPrevSourcePos(const char* codePos, unsigned int index) { - return scrParserGlob.sourcePosLookup[index + Scr_GetPrevSourcePosOpcodeLookup(codePos)->sourcePosIndex].sourcePos; + return ScrParserGlob.sourcePosLookup[index + Scr_GetPrevSourcePosOpcodeLookup(codePos)->sourcePosIndex].sourcePos; } Game::OpcodeLookup* ScriptError::Scr_GetPrevSourcePosOpcodeLookup(const char* codePos) { assert(Scr_IsInOpcodeMemory(codePos)); - assert(scrParserGlob.opcodeLookup); + assert(ScrParserGlob.opcodeLookup); unsigned int low = 0; - unsigned int high = scrParserGlob.opcodeLookupLen - 1; + unsigned int high = ScrParserGlob.opcodeLookupLen - 1; while (low <= high) { unsigned int middle = (high + low) >> 1; - if (codePos < scrParserGlob.opcodeLookup[middle].codePos) + if (codePos < ScrParserGlob.opcodeLookup[middle].codePos) { high = middle - 1; } else { low = middle + 1; - if (low == scrParserGlob.opcodeLookupLen || codePos < scrParserGlob.opcodeLookup[low].codePos) + if (low == ScrParserGlob.opcodeLookupLen || codePos < ScrParserGlob.opcodeLookup[low].codePos) { - return &scrParserGlob.opcodeLookup[middle]; + return &ScrParserGlob.opcodeLookup[middle]; } } } @@ -279,16 +279,16 @@ namespace Components::GSC unsigned int bufferIndex; assert(Scr_IsInOpcodeMemory(codePos)); - assert(scrParserPub.sourceBufferLookupLen > 0); + assert(ScrParserPub.sourceBufferLookupLen > 0); - for (bufferIndex = scrParserPub.sourceBufferLookupLen - 1; bufferIndex; --bufferIndex) + for (bufferIndex = ScrParserPub.sourceBufferLookupLen - 1; bufferIndex; --bufferIndex) { - if (!scrParserPub.sourceBufferLookup[bufferIndex].codePos) + if (!ScrParserPub.sourceBufferLookup[bufferIndex].codePos) { continue; } - if (scrParserPub.sourceBufferLookup[bufferIndex].codePos > codePos) + if (ScrParserPub.sourceBufferLookup[bufferIndex].codePos > codePos) { continue; } @@ -313,7 +313,7 @@ namespace Components::GSC return; } - if (!developer_) + if (!Developer_) { if (Scr_IsInOpcodeMemory(codePos - 1)) { @@ -326,7 +326,7 @@ namespace Components::GSC if (Game::scrVarPub->programBuffer && Scr_IsInOpcodeMemory(codePos)) { auto bufferIndex = Scr_GetSourceBuffer(codePos - 1); - Scr_PrintSourcePos(channel, scrParserPub.sourceBufferLookup[bufferIndex].buf, scrParserPub.sourceBufferLookup[bufferIndex].sourceBuf, Scr_GetPrevSourcePos(codePos - 1, index)); + Scr_PrintSourcePos(channel, ScrParserPub.sourceBufferLookup[bufferIndex].buf, ScrParserPub.sourceBufferLookup[bufferIndex].sourceBuf, Scr_GetPrevSourcePos(codePos - 1, index)); return; } } @@ -362,7 +362,7 @@ namespace Components::GSC assert(filename); auto lineNum = Scr_GetLineInfo(buf, sourcePos, &col, line, nullptr); - Game::Com_PrintMessage(channel, VA("(file '%s'%s, line %d)\n", filename, scrParserGlob.saveSourceBufferLookup ? " (savegame)" : "", lineNum + 1), 0); + Game::Com_PrintMessage(channel, VA("(file '%s'%s, line %d)\n", filename, ScrParserGlob.saveSourceBufferLookup ? " (savegame)" : "", lineNum + 1), 0); Game::Com_PrintMessage(channel, VA("%s\n", line), 0); for (auto i = 0; i < col; ++i) @@ -400,7 +400,7 @@ namespace Components::GSC bool abort_on_error; const char* dialogMessageSeparator; - if (!developer_) + if (!Developer_) { assert(Scr_IsInOpcodeMemory(codePos)); if (!(*Game::com_developer)->current.enabled) @@ -462,7 +462,7 @@ namespace Components::GSC Game::Com_PrintError(Game::CON_CHANNEL_PARSERSCRIPT, "\n"); Game::Com_PrintError(Game::CON_CHANNEL_PARSERSCRIPT, "******* script compile error *******\n"); - if (!developer_ || !scrParserPub.sourceBuf) + if (!Developer_ || !ScrParserPub.sourceBuf) { Game::Com_PrintError(Game::CON_CHANNEL_PARSERSCRIPT, "%s\n", text); line[0] = '\0'; @@ -472,12 +472,12 @@ namespace Components::GSC } else { - assert(scrParserPub.sourceBuf); + assert(ScrParserPub.sourceBuf); Game::Com_PrintError(Game::CON_CHANNEL_PARSERSCRIPT, "%s: ", text); - Scr_PrintSourcePos(Game::CON_CHANNEL_PARSERSCRIPT, scrParserPub.scriptfilename, scrParserPub.sourceBuf, sourcePos); - auto lineNumber = Scr_GetLineInfo(scrParserPub.sourceBuf, sourcePos, &col, line, nullptr); - Game::Com_Error(Game::ERR_SCRIPT_DROP, "\x15" "script compile error\n%s\n%s(%d):\n %s\n(see console for details)\n", text, scrParserPub.scriptfilename, lineNumber, line); + Scr_PrintSourcePos(Game::CON_CHANNEL_PARSERSCRIPT, ScrParserPub.scriptfilename, ScrParserPub.sourceBuf, sourcePos); + const auto lineNumber = Scr_GetLineInfo(ScrParserPub.sourceBuf, sourcePos, &col, line, nullptr); + Game::Com_Error(Game::ERR_SCRIPT_DROP, "\x15" "script compile error\n%s\n%s(%d):\n %s\n(see console for details)\n", text, ScrParserPub.scriptfilename, lineNumber, line); } } } @@ -504,7 +504,7 @@ namespace Components::GSC Game::Com_Printf(Game::CON_CHANNEL_PARSERSCRIPT, "************************************\n"); - Scr_GetTextSourcePos(scrParserPub.sourceBuf, codePos, line); + Scr_GetTextSourcePos(ScrParserPub.sourceBuf, codePos, line); Game::Com_Error(Game::ERR_SCRIPT_DROP, "\x15" "script compile error\n%s\n%s\n(see console for details)\n", text, line); } @@ -513,10 +513,10 @@ namespace Components::GSC { int col; - if (developer_ && codePos && codePos != Game::g_EndPos && Game::scrVarPub->programBuffer && Scr_IsInOpcodeMemory(codePos)) + if (Developer_ && codePos && codePos != Game::g_EndPos && Game::scrVarPub->programBuffer && Scr_IsInOpcodeMemory(codePos)) { auto bufferIndex = Scr_GetSourceBuffer(codePos - 1); - Scr_GetLineInfo(scrParserPub.sourceBufferLookup[bufferIndex].sourceBuf, Scr_GetPrevSourcePos(codePos - 1, 0), &col, line, nullptr); + Scr_GetLineInfo(ScrParserPub.sourceBufferLookup[bufferIndex].sourceBuf, Scr_GetPrevSourcePos(codePos - 1, 0), &col, line, nullptr); } else { @@ -526,68 +526,68 @@ namespace Components::GSC void ScriptError::Scr_InitOpcodeLookup() { - assert(!scrParserGlob.opcodeLookup); - assert(!scrParserGlob.sourcePosLookup); - assert(!scrParserPub.sourceBufferLookup); + assert(!ScrParserGlob.opcodeLookup); + assert(!ScrParserGlob.sourcePosLookup); + assert(!ScrParserPub.sourceBufferLookup); - if (!developer_) + if (!Developer_) { return; } - scrParserGlob.delayedSourceIndex = -1; - scrParserGlob.opcodeLookupMaxSize = 0; - scrParserGlob.opcodeLookupLen = 0; - scrParserGlob.opcodeLookup = static_cast(Game::Z_VirtualReserve(Game::MAX_OPCODE_LOOKUP_SIZE)); + ScrParserGlob.delayedSourceIndex = -1; + ScrParserGlob.opcodeLookupMaxSize = 0; + ScrParserGlob.opcodeLookupLen = 0; + ScrParserGlob.opcodeLookup = static_cast(Game::Z_VirtualReserve(Game::MAX_OPCODE_LOOKUP_SIZE)); - scrParserGlob.sourcePosLookupMaxSize = 0; - scrParserGlob.sourcePosLookupLen = 0; - scrParserGlob.sourcePosLookup = static_cast(Game::Z_VirtualReserve(Game::MAX_SOURCEPOS_LOOKUP_SIZE)); - scrParserGlob.currentCodePos = nullptr; - scrParserGlob.currentSourcePosCount = 0; - scrParserGlob.sourceBufferLookupMaxSize = 0; + ScrParserGlob.sourcePosLookupMaxSize = 0; + ScrParserGlob.sourcePosLookupLen = 0; + ScrParserGlob.sourcePosLookup = static_cast(Game::Z_VirtualReserve(Game::MAX_SOURCEPOS_LOOKUP_SIZE)); + ScrParserGlob.currentCodePos = nullptr; + ScrParserGlob.currentSourcePosCount = 0; + ScrParserGlob.sourceBufferLookupMaxSize = 0; - scrParserPub.sourceBufferLookupLen = 0; - scrParserPub.sourceBufferLookup = static_cast(Game::Z_VirtualReserve(Game::MAX_SOURCEBUF_LOOKUP_SIZE)); + ScrParserPub.sourceBufferLookupLen = 0; + ScrParserPub.sourceBufferLookup = static_cast(Game::Z_VirtualReserve(Game::MAX_SOURCEBUF_LOOKUP_SIZE)); } void ScriptError::Scr_ShutdownOpcodeLookup() { - if (scrParserGlob.opcodeLookup) + if (ScrParserGlob.opcodeLookup) { - Z_VirtualFree(scrParserGlob.opcodeLookup); - scrParserGlob.opcodeLookup = nullptr; + Z_VirtualFree(ScrParserGlob.opcodeLookup); + ScrParserGlob.opcodeLookup = nullptr; } - if (scrParserGlob.sourcePosLookup) + if (ScrParserGlob.sourcePosLookup) { - Z_VirtualFree(scrParserGlob.sourcePosLookup); - scrParserGlob.sourcePosLookup = nullptr; + Z_VirtualFree(ScrParserGlob.sourcePosLookup); + ScrParserGlob.sourcePosLookup = nullptr; } - if (scrParserPub.sourceBufferLookup) + if (ScrParserPub.sourceBufferLookup) { - for (unsigned int i = 0; i < scrParserPub.sourceBufferLookupLen; ++i) + for (unsigned int i = 0; i < ScrParserPub.sourceBufferLookupLen; ++i) { - Game::Engine::Hunk_FreeDebugMem(scrParserPub.sourceBufferLookup[i].buf); + Game::Engine::Hunk_FreeDebugMem(ScrParserPub.sourceBufferLookup[i].buf); } - Z_VirtualFree(scrParserPub.sourceBufferLookup); - scrParserPub.sourceBufferLookup = nullptr; + Z_VirtualFree(ScrParserPub.sourceBufferLookup); + ScrParserPub.sourceBufferLookup = nullptr; } - if (scrParserGlob.saveSourceBufferLookup) + if (ScrParserGlob.saveSourceBufferLookup) { - for (unsigned int i = 0; i < scrParserGlob.saveSourceBufferLookupLen; ++i) + for (unsigned int i = 0; i < ScrParserGlob.saveSourceBufferLookupLen; ++i) { - if (scrParserGlob.saveSourceBufferLookup[i].sourceBuf) + if (ScrParserGlob.saveSourceBufferLookup[i].sourceBuf) { - Game::Engine::Hunk_FreeDebugMem(scrParserGlob.saveSourceBufferLookup[i].buf); + Game::Engine::Hunk_FreeDebugMem(ScrParserGlob.saveSourceBufferLookup[i].buf); } } - Game::Engine::Hunk_FreeDebugMem(scrParserGlob.saveSourceBufferLookup); - scrParserGlob.saveSourceBufferLookup = nullptr; + Game::Engine::Hunk_FreeDebugMem(ScrParserGlob.saveSourceBufferLookup); + ScrParserGlob.saveSourceBufferLookup = nullptr; } } @@ -612,39 +612,39 @@ namespace Components::GSC Game::SourceBufferInfo* ScriptError::Scr_GetNewSourceBuffer() { - assert(scrParserPub.sourceBufferLookup); + assert(ScrParserPub.sourceBufferLookup); - auto size = sizeof(Game::SourceBufferInfo) * (scrParserPub.sourceBufferLookupLen + 1); - if (size > scrParserGlob.sourceBufferLookupMaxSize) + auto size = sizeof(Game::SourceBufferInfo) * (ScrParserPub.sourceBufferLookupLen + 1); + if (size > ScrParserGlob.sourceBufferLookupMaxSize) { - if (scrParserGlob.sourceBufferLookupMaxSize >= Game::MAX_SOURCEBUF_LOOKUP_SIZE) + if (ScrParserGlob.sourceBufferLookupMaxSize >= Game::MAX_SOURCEBUF_LOOKUP_SIZE) { Game::Sys_Error("MAX_SOURCEBUF_LOOKUP_SIZE exceeded"); } - Game::Z_VirtualCommit((char*)scrParserPub.sourceBufferLookup + scrParserGlob.sourceBufferLookupMaxSize, 0x20000); - scrParserGlob.sourceBufferLookupMaxSize += 0x20000; - assert(size <= scrParserGlob.sourceBufferLookupMaxSize); + Game::Z_VirtualCommit((char*)ScrParserPub.sourceBufferLookup + ScrParserGlob.sourceBufferLookupMaxSize, 0x20000); + ScrParserGlob.sourceBufferLookupMaxSize += 0x20000; + assert(size <= ScrParserGlob.sourceBufferLookupMaxSize); } - return &scrParserPub.sourceBufferLookup[scrParserPub.sourceBufferLookupLen++]; + return &ScrParserPub.sourceBufferLookup[ScrParserPub.sourceBufferLookupLen++]; } void ScriptError::Scr_AddSourceBufferInternal(const char* extFilename, const char* codePos, char* sourceBuf, int len, bool doEolFixup, bool archive) { int i; - if (!scrParserPub.sourceBufferLookup) + if (!ScrParserPub.sourceBufferLookup) { - scrParserPub.sourceBuf = nullptr; + ScrParserPub.sourceBuf = nullptr; return; } assert((len >= -1)); assert((len >= 0) || !sourceBuf); - auto strLen = std::strlen(extFilename) + 1; - auto newLen = strLen + len + 2; + const auto strLen = std::strlen(extFilename) + 1; + const auto newLen = strLen + len + 2; auto* buf = static_cast(Game::Engine::Hunk_AllocDebugMem(static_cast(newLen))); // Scr_AddSourceBufferInternal strcpy(buf, extFilename); @@ -689,7 +689,7 @@ namespace Components::GSC if (sourceBuf2) { - scrParserPub.sourceBuf = sourceBuf2; + ScrParserPub.sourceBuf = sourceBuf2; } } @@ -749,12 +749,12 @@ namespace Components::GSC { char* sourceBuf; - if (archive && scrParserGlob.saveSourceBufferLookup) + if (archive && ScrParserGlob.saveSourceBufferLookup) { - assert(scrParserGlob.saveSourceBufferLookupLen > 0); - --scrParserGlob.saveSourceBufferLookupLen; + assert(ScrParserGlob.saveSourceBufferLookupLen > 0); + --ScrParserGlob.saveSourceBufferLookupLen; - const auto* saveSourceBuffer = scrParserGlob.saveSourceBufferLookup + scrParserGlob.saveSourceBufferLookupLen; + const auto* saveSourceBuffer = ScrParserGlob.saveSourceBufferLookup + ScrParserGlob.saveSourceBufferLookupLen; const auto len = saveSourceBuffer->len; assert(len >= -1); @@ -808,7 +808,7 @@ namespace Components::GSC sprintf_s(extFilename, "%s.gsc", Game::SL_ConvertToString(static_cast(name))); - const auto* oldSourceBuf = scrParserPub.sourceBuf; + const auto* oldSourceBuf = ScrParserPub.sourceBuf; const auto* sourceBuffer = Scr_AddSourceBuffer(Game::SL_ConvertToString(static_cast(name)), extFilename, Game::TempMalloc(0), true); if (!sourceBuffer) @@ -820,8 +820,8 @@ namespace Components::GSC Game::scrAnimPub->animTreeNames = 0; Game::scrCompilePub->far_function_count = 0; - const auto* oldFilename = scrParserPub.scriptfilename; - scrParserPub.scriptfilename = extFilename; + const auto* oldFilename = ScrParserPub.scriptfilename; + ScrParserPub.scriptfilename = extFilename; Game::scrCompilePub->in_ptr = "+"; Game::scrCompilePub->in_ptr_valid = false; @@ -837,8 +837,8 @@ namespace Components::GSC Game::RemoveVariable(Game::scrCompilePub->scriptsCount, name); - scrParserPub.scriptfilename = oldFilename; - scrParserPub.sourceBuf = oldSourceBuf; + ScrParserPub.scriptfilename = oldFilename; + ScrParserPub.sourceBuf = oldSourceBuf; Game::scrAnimPub->animTreeNames = oldAnimTreeNames; @@ -848,7 +848,7 @@ namespace Components::GSC void ScriptError::Scr_Settings_Hk([[maybe_unused]] int developer, int developer_script, int abort_on_error) { assert(!abort_on_error || developer); - developer_ = (*Game::com_developer)->current.enabled; + Developer_ = (*Game::com_developer)->current.enabled; Game::scrVarPub->developer_script = developer_script != 0; Game::scrVmPub->abort_on_error = abort_on_error != 0; } diff --git a/src/Components/Modules/GSC/ScriptError.hpp b/src/Components/Modules/GSC/ScriptError.hpp index 3cc61caa..181e6752 100644 --- a/src/Components/Modules/GSC/ScriptError.hpp +++ b/src/Components/Modules/GSC/ScriptError.hpp @@ -14,10 +14,10 @@ namespace Components::GSC private: // Replacement for variables not present in currently available structs - static int developer_; + static int Developer_; - static Game::scrParserGlob_t scrParserGlob; - static Game::scrParserPub_t scrParserPub; + static Game::scrParserGlob_t ScrParserGlob; + static Game::scrParserPub_t ScrParserPub; static void AddOpcodePos(unsigned int sourcePos, int type); static void RemoveOpcodePos(); diff --git a/src/Components/Modules/GSC/ScriptExtension.cpp b/src/Components/Modules/GSC/ScriptExtension.cpp index e68220ae..a45ffd72 100644 --- a/src/Components/Modules/GSC/ScriptExtension.cpp +++ b/src/Components/Modules/GSC/ScriptExtension.cpp @@ -1,4 +1,7 @@ #include + +#include + #include "ScriptExtension.hpp" #include "Script.hpp" diff --git a/src/Components/Modules/GSC/UserInfo.cpp b/src/Components/Modules/GSC/UserInfo.cpp index aede628b..d31e5e9b 100644 --- a/src/Components/Modules/GSC/UserInfo.cpp +++ b/src/Components/Modules/GSC/UserInfo.cpp @@ -1,6 +1,8 @@ #include #include +#include + #include "Script.hpp" #include "UserInfo.hpp" diff --git a/src/Components/Modules/Logger.cpp b/src/Components/Modules/Logger.cpp index 033f377b..d575efe3 100644 --- a/src/Components/Modules/Logger.cpp +++ b/src/Components/Modules/Logger.cpp @@ -1,5 +1,7 @@ #include + #include "Console.hpp" +#include "Events.hpp" namespace Components { diff --git a/src/Components/Modules/MapRotation.cpp b/src/Components/Modules/MapRotation.cpp index 0d8f463a..e244c6b4 100644 --- a/src/Components/Modules/MapRotation.cpp +++ b/src/Components/Modules/MapRotation.cpp @@ -1,4 +1,6 @@ #include + +#include "Events.hpp" #include "MapRotation.hpp" #include "Party.hpp" diff --git a/src/Components/Modules/PlayerMovement.cpp b/src/Components/Modules/PlayerMovement.cpp index 371b9847..010fd8a7 100644 --- a/src/Components/Modules/PlayerMovement.cpp +++ b/src/Components/Modules/PlayerMovement.cpp @@ -1,4 +1,6 @@ #include + +#include "Events.hpp" #include "PlayerMovement.hpp" #include "GSC/Script.hpp" diff --git a/src/Components/Modules/RCon.cpp b/src/Components/Modules/RCon.cpp index d7074420..52a5cc25 100644 --- a/src/Components/Modules/RCon.cpp +++ b/src/Components/Modules/RCon.cpp @@ -1,6 +1,7 @@ #include #include +#include "Events.hpp" #include "RCon.hpp" #include "Party.hpp" diff --git a/src/Components/Modules/Renderer.cpp b/src/Components/Modules/Renderer.cpp index 4eed9557..086a9446 100644 --- a/src/Components/Modules/Renderer.cpp +++ b/src/Components/Modules/Renderer.cpp @@ -1,5 +1,7 @@ #include +#include "Events.hpp" + namespace Components { Utils::Signal Renderer::BackendFrameSignal; diff --git a/src/Components/Modules/ServerList.cpp b/src/Components/Modules/ServerList.cpp index d4252115..06823b2e 100644 --- a/src/Components/Modules/ServerList.cpp +++ b/src/Components/Modules/ServerList.cpp @@ -2,6 +2,7 @@ #include #include "Discovery.hpp" +#include "Events.hpp" #include "Node.hpp" #include "Party.hpp" #include "ServerList.hpp" diff --git a/src/Components/Modules/StartupMessages.cpp b/src/Components/Modules/StartupMessages.cpp index 09bae507..fba6dbba 100644 --- a/src/Components/Modules/StartupMessages.cpp +++ b/src/Components/Modules/StartupMessages.cpp @@ -1,4 +1,6 @@ #include + +#include "Events.hpp" #include "StartupMessages.hpp" namespace Components diff --git a/src/Components/Modules/UIFeeder.cpp b/src/Components/Modules/UIFeeder.cpp index e7d43c38..2db429de 100644 --- a/src/Components/Modules/UIFeeder.cpp +++ b/src/Components/Modules/UIFeeder.cpp @@ -1,4 +1,6 @@ #include + +#include "Events.hpp" #include "UIFeeder.hpp" namespace Components diff --git a/src/Components/Modules/Voice.cpp b/src/Components/Modules/Voice.cpp index c7bf5448..7d7fd1cf 100644 --- a/src/Components/Modules/Voice.cpp +++ b/src/Components/Modules/Voice.cpp @@ -1,5 +1,7 @@ #include + #include "Chat.hpp" +#include "Events.hpp" #include "Voice.hpp" namespace Components diff --git a/src/Utils/Utils.hpp b/src/Utils/Utils.hpp index 252def02..d75e1130 100644 --- a/src/Utils/Utils.hpp +++ b/src/Utils/Utils.hpp @@ -67,12 +67,6 @@ namespace Utils } } - template - bool Contains(const std::vector* haystack, T needle) - { - return std::ranges::find(*haystack, needle) != haystack->end(); - } - template using Slot = std::function; template class Signal From ca7ae836e98731986814e710568a1a227cd975b1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 May 2023 17:58:04 +0000 Subject: [PATCH 38/39] Bump deps/pdcurses from `f2d31a2` to `0eb254a` Bumps [deps/pdcurses](https://github.com/wmcbrine/PDCurses) from `f2d31a2` to `0eb254a`. - [Release notes](https://github.com/wmcbrine/PDCurses/releases) - [Commits](https://github.com/wmcbrine/PDCurses/compare/f2d31a2633eb042f7bf1f79cba81522915a04579...0eb254ae43cdd1f532d515accac59377087883f6) --- updated-dependencies: - dependency-name: deps/pdcurses dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- deps/pdcurses | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/pdcurses b/deps/pdcurses index f2d31a26..0eb254ae 160000 --- a/deps/pdcurses +++ b/deps/pdcurses @@ -1 +1 @@ -Subproject commit f2d31a2633eb042f7bf1f79cba81522915a04579 +Subproject commit 0eb254ae43cdd1f532d515accac59377087883f6 From 260f371e0be75d6558517603cec88e7db7f70c5e Mon Sep 17 00:00:00 2001 From: Edo Date: Wed, 17 May 2023 13:11:27 +0100 Subject: [PATCH 39/39] [CHANGELOG]: Prepare for new release (#1044) --- CHANGELOG.md | 166 ++++++++++++++++++++++++++++----------------------- 1 file changed, 90 insertions(+), 76 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48c1c431..df7b9f42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,19 @@ 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/). +## r4299 - 2023-05-17 + +### Added + +- Add `dumpZone` ZoneBuilder command (#1033) +- Add `FreezeControlsAllowLook` GSC method (#1026) + +### Fixed + +- The sound fix was removed as the bug no longer happens (#1007) +- Fix crash when the opening the "server info" menu on an empty server list (#1041) +- Fix patch that was causing the game thread to deadlock (#1038) + ## r4251 - 2023-05-03 ### Added @@ -48,6 +61,7 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0. ### Security - Check the address of the sender for the `print` OOB packet (#969) +- Check the address of the sender for the `voice` OOB packet (#973) ### Fixed @@ -191,7 +205,7 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0. - Add `IsSprinting` GSC method (#587) - Add `StorageLoad` GSC function (#595) - Add `bg_climbAnything` Dvar (#663) -- Add ClanTag support for bots (#645) +- Add "ClanTag" support for bots (#645) - Add `sv_randomBotNames` Dvar (#665) - Add support for parsing localized strings files (.str & .json) (#621) - Add `callvote` menus (#613) @@ -305,7 +319,7 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0. - Add `DisableWeaponPickup` GSC method (#329) - Add `EnableWeaponPickup` GSC method (#329) - Add `protect-saved-dvars` command line argument (#335) -- Add `clanName` dvar. Can be edited in the `barracks` menu (#361) +- Add `clanName` dvar. Can be edited in the "barracks" menu (#361) - Add DLC9 containing classic maps from CoD4: Backlot, Chinatown, Winter Crash, Pipeline and Downpour. - Add to the iw4x-rawfiles `common_scripts\iw4x_utility` GSC script, it contains the scripts-based solution for the removed GSC built-in methods. @@ -345,10 +359,10 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0. ### Added -- Add SetName GSC method (#288) -- Add ResetName GSC method (#288) -- Add OnPlayerSay GSC function (#265) -- Add Give client command (works with weapons only) (#292) +- Add `SetName` GSC method (#288) +- Add `ResetName` GSC method (#288) +- Add `OnPlayerSay` GSC function (#265) +- Add `Give` client command (works with weapons only) (#292) - Add `sv_disableChat` Dvar (#290) - Add `addMap` command (#302) - Add `addGametype` command (#302) @@ -379,7 +393,7 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0. ### Added -- Add IsArray GSC function (#248) +- Add `IsArray` GSC function (#248) - Keybind fields in menus work with controller keys (#255) ### Changed @@ -402,14 +416,14 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0. ### Added -- Add ToUpper GSC Function (#216) -- Add StrICmp GSC Function (#216) -- Add IsEndStr GSC Function (#216) -- Add DropAllBots GSC Function (#174) +- Add `ToUpper` GSC Function (#216) +- Add `StrICmp` GSC Function (#216) +- Add `IsEndStr` GSC Function (#216) +- Add `DropAllBots` GSC Function (#174) - Add GSC entity field `entityflags` (#228) - Add GSC client field `clientflags` (#228) -- Add bg_surfacePenetration Dvar (#241) -- Add bg_bulletRange Dvar (#241) +- Add `bg_surfacePenetration` Dvar (#241) +- Add `bg_bulletRange Dvar` (#241) ### Changed @@ -423,8 +437,8 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0. - Fixed issue with mouse acceleration when polling rate is greater than 125Hz (#230) - Fixed issue with player speed caused by sprinting from the prone position (#232) -- Fixed client crash when cg_chatHeight was set to 0 (#237) -- Fixed GSC function Scr_TableLookupIStringByRow (#162) +- Fixed client crash when `cg_chatHeight` was set to 0 (#237) +- Fixed GSC function `Scr_TableLookupIStringByRow` (#162) ### Known issues @@ -438,46 +452,46 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0. - Add controller support (#75) - Add aim assist for controllers (#75) -- Unlock camera_thirdPersonCrosshairOffset Dvar (#68) +- Unlock `camera_thirdPersonCrosshairOffset` Dvar (#68) - Add support for building custom Fonts with Zonebuilder (#88) - Add colorblind friendly team colors (#101) -- Add emojis based on titlecards and emblems to use in the chat and server names Example: `:nuke:` (#130) +- Add emojis based on title cards and emblems to use in the chat and server names Example: `:nuke:` (#130) - Upon leaving a server 'archive' dvars (saved in the config file) will be reset to the value they had prior to joining the server (#134) -- Implement muteClient command for the game chat (#159) -- Implement unmute command for the game chat (#159) -- Add sv_allowAimAssist Dvar (#75) -- Add sv_allowColoredNames (#130) -- Add sv_randomMapRotation Dvar (#146) -- Add rcon_log_requests Dvar (#195) -- Add player_duckedSpeedScale Dvar (#141) -- Add player_proneSpeedScale Dvar (#141) -- Add cg_ufo_scaler Dvar (#158) -- Add cg_noclip_scaler Dvar (#158) -- Add bg_bouncesAllAngles Dvar (#158) -- Add bg_rocketJump Dvar (#158) -- Add bg_elevators Dvar (#156) -- Implement noclip client command (#152) -- Implement ufo client command (#152) -- Implement God client command (#152) -- Implement demigod client command (#152) -- Implement notarget client command (#152) -- Add noclip GSC Function (#152) -- Add ufo GSC Function (#152) -- Add God GSC Function (#152) -- Add demigod GSC Function (#152) -- Add notarget GSC Function (#152) -- Add replaceFunc GSC Function (#144) +- Add `muteClient` command for the game chat (#159) +- Add `unmute` command for the game chat (#159) +- Add `sv_allowAimAssist` Dvar (#75) +- Add `sv_allowColoredNames` (#130) +- Add `sv_randomMapRotation` Dvar (#146) +- Add `rcon_log_requests` Dvar (#195) +- Add `player_duckedSpeedScale` Dvar (#141) +- Add `player_proneSpeedScale` Dvar (#141) +- Add `cg_ufo_scaler` Dvar (#158) +- Add `cg_noclip_scaler` Dvar (#158) +- Add `bg_bouncesAllAngles` Dvar (#158) +- Add `bg_rocketJump` Dvar (#158) +- Add `bg_elevators` Dvar (#156) +- Add `noclip` client command (#152) +- Add `ufo` client command (#152) +- Add `God` client command (#152) +- Add `demigod` client command (#152) +- Add `notarget` client command (#152) +- Add `noclip` GSC Function (#152) +- Add `ufo` GSC Function (#152) +- Add `God` GSC Function (#152) +- Add `demigod` GSC Function (#152) +- Add `notarget` GSC Function (#152) +- Add `replaceFunc` GSC Function (#144) ### Changed -- Renamed sv_enableBounces to bg_bounces (#158) -- Renamed g_playerCollision to bg_playerEjection (#158) -- Renamed g_playerEjection to bg_playerCollision (#158) -- Setviewpos client command works outside private matches (#163) -- Ufo client command works outside of private matches (#152) -- Noclip client command works outside of private matches (#152) +- Renamed `sv_enableBounces` to bg_bounces (#158) +- Renamed `g_playerCollision` to bg_playerEjection (#158) +- Renamed `g_playerEjection` to bg_playerCollision (#158) +- `setviewpos` client command works outside private matches (#163) +- `ufo` client command works outside of private matches (#152) +- `noclip` client command works outside of private matches (#152) - If a player name is less than 3 characters server will change it to `Unknown Soldier` (#130) -- scr_player_forceautoassign Dvar is false by default +- `scr_player_forceautoassign` Dvar is false by default ### Fixed @@ -485,7 +499,7 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0. - Fixes and improvements to Zonebuilder - Fixed issue where the game froze following base game script throwing an error (#74) - Fixed RCon on party servers (#91 - #95) -- Fixed slow motion during final killcams (#111 - #107) +- Fixed slow motion during final kill cams (#111 - #107) - Fixed sound issue that causes the game to freeze (#106) - Fixed issue where materials strings found in hostnames, player names, chat etc. caused the game to crash (#113) - Fixed issue with servers displaying an invalid player count (#113) @@ -500,29 +514,29 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0. ### Added -- Add host information to /info endpoint (request) -- Add fileWrite GSC Function (#36) -- Add fileRead GSC Function (#36) -- Add fileExists GSC Function (#36) -- Add fileRemove GSC Function (#36) -- Add botMovement GSC Function (#46) -- Add botAction GSC Function (#46) -- Add botWeapon GSC Function (#46) -- Add botStop GSC Function (#46) -- Add isBot GSC Function (#46) -- Add setPing GSC Function (#46) -- Add GetSystemTime and GetSystemTimeMilliseconds GSC Functions (#46) -- Add PrintConsole GSC Function (#46) -- Add Exec GSC Function (#46) -- Add getIP GSC Method (#36) -- Add getPing GSC Method (#36) -- Add scr_intermissionTime GSC Function (#25) -- Add g_playerCollision Dvar (#36) -- Add g_playerEjection Dvar (#36) -- Add r_specularCustomMaps Dvar (#36) -- Unlock safeArea_horizontal and safeArea_vertical Dvars (#42) -- Unlock cg_fovscale Dvar (#47) -- Add g_antilag Dvar (#61) +- Add host information to `/info` endpoint (request) +- Add `fileWrite` GSC Function (#36) +- Add `fileRead` GSC Function (#36) +- Add `fileExists` GSC Function (#36) +- Add `fileRemove` GSC Function (#36) +- Add `botMovement` GSC Function (#46) +- Add `botAction` GSC Function (#46) +- Add `botWeapon` GSC Function (#46) +- Add `botStop` GSC Function (#46) +- Add `isBot` GSC Function (#46) +- Add `setPing` GSC Function (#46) +- Add `GetSystemTime` and `GetSystemTimeMilliseconds` GSC Functions (#46) +- Add `PrintConsole` GSC Function (#46) +- Add `Exec` GSC Function (#46) +- Add `getIP` GSC Method (#36) +- Add `getPing` GSC Method (#36) +- Add `scr_intermissionTime` Dvar (#25) +- Add `g_playerCollision` Dvar (#36) +- Add `g_playerEjection` Dvar (#36) +- Add `r_specularCustomMaps` Dvar (#36) +- Unlock `safeArea_horizontal` and `safeArea_vertical` Dvars (#42) +- Unlock `cg_fovscale` Dvar (#47) +- Add `g_antilag` Dvar (#61) ### Changed @@ -534,7 +548,7 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0. - Fixed a node system related crash (#45) - Fixed an issue that made dedicated servers crash when info was requested during map rotation (#43) -- Fixed an issue where the game was trying to decrypt gsc files which caused it to crash when loading mods (#35) +- Fixed an issue where the game was trying to decrypt GSC files which caused it to crash when loading mods (#35) - Fixed an issue causing the game to crash when Steam was running in the background (#56) - Fixed slow download speed when using fast download @@ -550,8 +564,8 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0. ### Added -- Implement unbanclient command. -- Implement /serverlist api endpoint on dedicated servers +- Add `unbanClient` command. +- Add `/serverlist` api endpoint on dedicated servers - Add dvar to control the server query rate (net_serverQueryLimit & net_serverFrames) ### Changed @@ -565,7 +579,7 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0. - Fix multiple vulnerability's - Fix lag spikes on lower end PCs - Fix invalid name check -- Fix openLink command crash issue +- Fix `openLink` command crash issue - Fix lobby server map downloading - Fix steam integration