diff --git a/deps/mongoose b/deps/mongoose index 06b6bf61..845e6082 160000 --- a/deps/mongoose +++ b/deps/mongoose @@ -1 +1 @@ -Subproject commit 06b6bf6185067506a851a2efadf94599ad1cb880 +Subproject commit 845e608280419460c6b4f52854db7600e2728535 diff --git a/deps/protobuf b/deps/protobuf index dfe0c9ad..401e07d3 160000 --- a/deps/protobuf +++ b/deps/protobuf @@ -1 +1 @@ -Subproject commit dfe0c9ad3836dc3756a908fa0e4aee1c2b3f2ce1 +Subproject commit 401e07d3726e91659228dff8ed9f7cb02026c47e diff --git a/premake5.lua b/premake5.lua index b4d92202..90a6df9a 100644 --- a/premake5.lua +++ b/premake5.lua @@ -132,7 +132,7 @@ workspace "iw4x" -- Pre-compiled header pchheader "STDInclude.hpp" -- must be exactly same as used in #include directives pchsource "src/STDInclude.cpp" -- real path - buildoptions { "/Zm91 -Zm91" } + buildoptions { "/Zm200" } filter "files:**.pb.*" flags { "NoPCH", diff --git a/src/Components/Loader.cpp b/src/Components/Loader.cpp index 34c1eb07..4c4db163 100644 --- a/src/Components/Loader.cpp +++ b/src/Components/Loader.cpp @@ -26,6 +26,7 @@ namespace Components Loader::Register(new Command()); Loader::Register(new Console()); Loader::Register(new IPCPipe()); + Loader::Register(new ModList()); Loader::Register(new Network()); Loader::Register(new Theatre()); Loader::Register(new Download()); @@ -51,7 +52,6 @@ namespace Components Loader::Register(new MusicalTalent()); Loader::Register(new StructuredData()); Loader::Register(new ConnectProtocol()); - Loader::Register(new ModList()); } void Loader::Uninitialize() diff --git a/src/Components/Loader.hpp b/src/Components/Loader.hpp index 68a37a3e..96bc62e5 100644 --- a/src/Components/Loader.hpp +++ b/src/Components/Loader.hpp @@ -38,6 +38,7 @@ namespace Components #include "Modules\Command.hpp" #include "Modules\Console.hpp" #include "Modules\IPCPipe.hpp" +#include "Modules\ModList.hpp" #include "Modules\Network.hpp" #include "Modules\Theatre.hpp" #include "Modules\Node.hpp" @@ -67,4 +68,3 @@ namespace Components #include "Modules\MusicalTalent.hpp" #include "Modules\StructuredData.hpp" #include "Modules\ConnectProtocol.hpp" -#include "Modules\ModList.hpp" diff --git a/src/Components/Modules/Auth.cpp b/src/Components/Modules/Auth.cpp index c2e4bbbf..b3c90e2c 100644 --- a/src/Components/Modules/Auth.cpp +++ b/src/Components/Modules/Auth.cpp @@ -140,8 +140,7 @@ namespace Components unsigned int Auth::GetKeyHash() { Auth::LoadKey(); - std::string key = Auth::GuidKey.GetPublicKey(); - return (Utils::Cryptography::JenkinsOneAtATime::Compute(key.data(), key.size())); + return (Utils::Cryptography::JenkinsOneAtATime::Compute(Auth::GuidKey.GetPublicKey())); } void Auth::StoreKey() @@ -337,7 +336,7 @@ namespace Components } // Check if guid matches the certificate - else if (id != (Utils::Cryptography::JenkinsOneAtATime::Compute(response.publickey().data(), response.publickey().size()) & ~0x80000000)) + else if (id != (Utils::Cryptography::JenkinsOneAtATime::Compute(response.publickey()) & ~0x80000000)) { info->state = Auth::STATE_INVALID; Game::SV_KickClientError(client, "XUID doesn't match the certificate!"); diff --git a/src/Components/Modules/Playlist.cpp b/src/Components/Modules/Playlist.cpp index b3be1494..0db1f466 100644 --- a/src/Components/Modules/Playlist.cpp +++ b/src/Components/Modules/Playlist.cpp @@ -48,7 +48,7 @@ namespace Components std::string compressedList = Utils::Compression::ZLib::Compress(Playlist::CurrentPlaylistBuffer); Proto::Party::Playlist list; - list.set_hash(Utils::Cryptography::JenkinsOneAtATime::Compute(compressedList.data(), compressedList.size())); + list.set_hash(Utils::Cryptography::JenkinsOneAtATime::Compute(compressedList)); list.set_buffer(compressedList); Network::SendCommand(address, "playlistResponse", list.SerializeAsString()); @@ -72,7 +72,7 @@ namespace Components { // Generate buffer and hash std::string compressedData(list.buffer()); - unsigned int hash = Utils::Cryptography::JenkinsOneAtATime::Compute(compressedData.data(), compressedData.size()); + unsigned int hash = Utils::Cryptography::JenkinsOneAtATime::Compute(compressedData); //Validate hashes if (hash != list.hash()) diff --git a/src/Components/Modules/QuickPatch.cpp b/src/Components/Modules/QuickPatch.cpp index 6bedf7e2..ee8c01f8 100644 --- a/src/Components/Modules/QuickPatch.cpp +++ b/src/Components/Modules/QuickPatch.cpp @@ -323,6 +323,16 @@ namespace Components // developer_Script 1 Utils::Hook::Set(0x60AE2B, true); + + // Constantly draw the mini console + Utils::Hook::Set(0x412A45, 0xEB); + Renderer::OnFrame([] () + { + if (*reinterpret_cast(0x62E4BAC)) + { + Game::Con_DrawMiniConsole(0, 2, 4, (Game::CL_IsCgameInitialized() ? 1.0f : 0.4f)); + } + }); #endif } diff --git a/src/Components/Modules/ServerInfo.cpp b/src/Components/Modules/ServerInfo.cpp index 02f72e30..52fcb18a 100644 --- a/src/Components/Modules/ServerInfo.cpp +++ b/src/Components/Modules/ServerInfo.cpp @@ -117,9 +117,7 @@ namespace Components info.Set("shortversion", VERSION_STR); info.Set("mapname", Dvar::Var("mapname").Get()); info.Set("isPrivate", (Dvar::Var("g_password").Get().empty() ? "0" : "1")); - - std::string time = Utils::VA("%u", Game::Com_Milliseconds()); - info.Set("checksum", Utils::VA("%X", Utils::Cryptography::JenkinsOneAtATime::Compute(time.data(), time.size()))); + info.Set("checksum", Utils::VA("%X", Utils::Cryptography::JenkinsOneAtATime::Compute(Utils::VA("%u", Game::Com_Milliseconds())))); // Ensure mapname is set if (info.Get("mapname").empty()) diff --git a/src/Components/Modules/StringTable.cpp b/src/Components/Modules/StringTable.cpp index f574cdda..b2c5cbe0 100644 --- a/src/Components/Modules/StringTable.cpp +++ b/src/Components/Modules/StringTable.cpp @@ -2,6 +2,7 @@ namespace Components { + Utils::Memory::Allocator StringTable::MemAllocator; std::map StringTable::StringTableMap; int StringTable::Hash(const char* data) @@ -27,19 +28,18 @@ namespace Components { Utils::CSV parsedTable(rawTable.GetBuffer(), false, false); - table = Utils::Memory::AllocateArray(1); + table = StringTable::MemAllocator.AllocateArray(1); if (table) { - table->name = Utils::Memory::DuplicateString(filename); + table->name = StringTable::MemAllocator.DuplicateString(filename); table->columnCount = parsedTable.GetColumns(); table->rowCount = parsedTable.GetRows(); - table->values = Utils::Memory::AllocateArray(table->columnCount * table->rowCount); + table->values = StringTable::MemAllocator.AllocateArray(table->columnCount * table->rowCount); if (!table->values) { - Utils::Memory::Free(table); return nullptr; } @@ -49,7 +49,7 @@ namespace Components { Game::StringTableCell* cell = &table->values[i * table->columnCount + j]; cell->hash = StringTable::Hash(parsedTable.GetElementAt(i, j).data()); - cell->string = Utils::Memory::DuplicateString(parsedTable.GetElementAt(i, j)); + cell->string = StringTable::MemAllocator.DuplicateString(parsedTable.GetElementAt(i, j)); //if (!cell->string) cell->string = ""; // We have to assume it allocated successfully } } @@ -86,28 +86,7 @@ namespace Components StringTable::~StringTable() { - for (auto i = StringTable::StringTableMap.begin(); i != StringTable::StringTableMap.end(); ++i) - { - Game::StringTable* table = i->second; - if (table) - { - if (table->values) - { - for (int j = 0; j < table->rowCount * table->columnCount; ++j) - { - if (table->values[j].string) - { - Utils::Memory::Free(table->values[j].string); - } - } - - Utils::Memory::Free(table->values); - } - - Utils::Memory::Free(table); - } - } - StringTable::StringTableMap.clear(); + StringTable::MemAllocator.Free(); } } diff --git a/src/Components/Modules/StringTable.hpp b/src/Components/Modules/StringTable.hpp index 4bdd083f..7bb87652 100644 --- a/src/Components/Modules/StringTable.hpp +++ b/src/Components/Modules/StringTable.hpp @@ -8,6 +8,7 @@ namespace Components const char* GetName() { return "StringTable"; }; private: + static Utils::Memory::Allocator MemAllocator; static std::map StringTableMap; static int Hash(const char* data); diff --git a/src/Components/Modules/StructuredData.cpp b/src/Components/Modules/StructuredData.cpp index dbe00701..38c885e3 100644 --- a/src/Components/Modules/StructuredData.cpp +++ b/src/Components/Modules/StructuredData.cpp @@ -2,7 +2,7 @@ namespace Components { - StructuredData* StructuredData::Singleton = nullptr; + Utils::Memory::Allocator StructuredData::MemAllocator; const char* StructuredData::EnumTranslation[ENUM_MAX] = { @@ -43,7 +43,7 @@ namespace Components unsigned int indexCount = dataEnum->numIndices + entries.size(); // Allocate new entries - Game::StructuredDataEnumEntry* indices = StructuredData::GetSingleton()->MemAllocator.AllocateArray(indexCount); + Game::StructuredDataEnumEntry* indices = StructuredData::MemAllocator.AllocateArray(indexCount); memcpy(indices, dataEnum->indices, sizeof(Game::StructuredDataEnumEntry) * dataEnum->numIndices); for (unsigned int i = 0; i < entries.size(); ++i) @@ -71,7 +71,7 @@ namespace Components } indices[pos].index = i + lastIndex; - indices[pos].key = StructuredData::GetSingleton()->MemAllocator.DuplicateString(entries[i]); + indices[pos].key = StructuredData::MemAllocator.DuplicateString(entries[i]); } // Apply our patches @@ -79,23 +79,11 @@ namespace Components dataEnum->indices = indices; } - StructuredData* StructuredData::GetSingleton() - { - if (!StructuredData::Singleton) - { - Logger::Error("StructuredData singleton is null!"); - } - - return StructuredData::Singleton; - } - StructuredData::StructuredData() { // Only execute this when building zones if (!ZoneBuilder::IsEnabled()) return; - StructuredData::Singleton = this; - AssetHandler::OnLoad([] (Game::XAssetType type, Game::XAssetHeader asset, std::string filename, bool* restrict) { // Only intercept playerdatadef loading @@ -169,7 +157,7 @@ namespace Components if (patchDefinitions.empty()) return; // Reallocate the definition - Game::StructuredDataDef* newData = StructuredData::GetSingleton()->MemAllocator.AllocateArray(data->count + patchDefinitions.size()); + Game::StructuredDataDef* newData = StructuredData::MemAllocator.AllocateArray(data->count + patchDefinitions.size()); memcpy(&newData[patchDefinitions.size()], data->data, sizeof Game::StructuredDataDef * data->count); // Prepare the buffers @@ -179,7 +167,7 @@ namespace Components newData[i].version = (patchDefinitions.size() - i) + 155; // Reallocate the enum array - Game::StructuredDataEnum* newEnums = StructuredData::GetSingleton()->MemAllocator.AllocateArray(data->data->numEnums); + Game::StructuredDataEnum* newEnums = StructuredData::MemAllocator.AllocateArray(data->data->numEnums); memcpy(newEnums, data->data->enums, sizeof Game::StructuredDataEnum * data->data->numEnums); newData[i].enums = newEnums; } @@ -220,6 +208,6 @@ namespace Components StructuredData::~StructuredData() { - StructuredData::Singleton = nullptr; + StructuredData::MemAllocator.Free(); } } diff --git a/src/Components/Modules/StructuredData.hpp b/src/Components/Modules/StructuredData.hpp index b3d0e6ea..09b0b113 100644 --- a/src/Components/Modules/StructuredData.hpp +++ b/src/Components/Modules/StructuredData.hpp @@ -27,11 +27,7 @@ namespace Components private: static void PatchPlayerDataEnum(Game::StructuredDataDef* data, PlayerDataType type, std::vector& entries); - static StructuredData* GetSingleton(); - - Utils::Memory::Allocator MemAllocator; - - static StructuredData* Singleton; + static Utils::Memory::Allocator MemAllocator; static const char* EnumTranslation[ENUM_MAX]; }; diff --git a/src/Components/Modules/Weapon.cpp b/src/Components/Modules/Weapon.cpp index 47e0e52f..00b98e9f 100644 --- a/src/Components/Modules/Weapon.cpp +++ b/src/Components/Modules/Weapon.cpp @@ -24,5 +24,8 @@ namespace Components Utils::Hook::Nop(0x408228, 5); // find asset header Utils::Hook::Nop(0x408230, 5); // is asset default Utils::Hook::Nop(0x40823A, 2); // jump + + // Skip double loading for fs_game + Utils::Hook::Set(0x4081FD, 0xEB); } } diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index 550d4025..893838e8 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -23,6 +23,8 @@ namespace Game Com_Milliseconds_t Com_Milliseconds = (Com_Milliseconds_t)0x42A660; Com_ParseExt_t Com_ParseExt = (Com_ParseExt_t)0x474D60; + Con_DrawMiniConsole_t Con_DrawMiniConsole = (Con_DrawMiniConsole_t)0x464F30; + DB_EnumXAssets_t DB_EnumXAssets = (DB_EnumXAssets_t)0x4B76D0; DB_FindXAssetHeader_t DB_FindXAssetHeader = (DB_FindXAssetHeader_t)0x407930; DB_GetXAssetNameHandler_t* DB_GetXAssetNameHandlers = (DB_GetXAssetNameHandler_t*)0x799328; diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 2a7ca459..9a53a202 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -45,6 +45,9 @@ namespace Game typedef char* (__cdecl * Com_ParseExt_t)(const char **data_p); extern Com_ParseExt_t Com_ParseExt; + typedef char* (__cdecl * Con_DrawMiniConsole_t)(int localClientNum, int xPos, int yPos, float alpha); + extern Con_DrawMiniConsole_t Con_DrawMiniConsole; + typedef void(__cdecl * DB_EnumXAssets_t)(XAssetType type, void(*)(XAssetHeader, void *), void* userdata, bool overrides); extern DB_EnumXAssets_t DB_EnumXAssets; diff --git a/src/Utils/Cryptography.cpp b/src/Utils/Cryptography.cpp index 48c2505d..11bcc10b 100644 --- a/src/Utils/Cryptography.cpp +++ b/src/Utils/Cryptography.cpp @@ -167,6 +167,11 @@ namespace Utils #pragma region JenkinsOneAtATime + unsigned int JenkinsOneAtATime::Compute(std::string data) + { + return JenkinsOneAtATime::Compute(data.data(), data.size()); + } + unsigned int JenkinsOneAtATime::Compute(const char *key, size_t len) { unsigned int hash, i; diff --git a/src/Utils/Cryptography.hpp b/src/Utils/Cryptography.hpp index bebab3dd..df076140 100644 --- a/src/Utils/Cryptography.hpp +++ b/src/Utils/Cryptography.hpp @@ -300,6 +300,7 @@ namespace Utils class JenkinsOneAtATime { public: + static unsigned int Compute(std::string data); static unsigned int Compute(const char *key, size_t len); }; } diff --git a/src/Utils/Memory.cpp b/src/Utils/Memory.cpp index 8e788c7e..04b2aeb1 100644 --- a/src/Utils/Memory.cpp +++ b/src/Utils/Memory.cpp @@ -6,6 +6,8 @@ namespace Utils { void* data = new char[length]; + assert(data != nullptr); + if (data) { ZeroMemory(data, length); @@ -23,7 +25,10 @@ namespace Utils void Memory::Free(void* data) { - delete[] data; + if (data) + { + delete[] data; + } } void Memory::Free(const void* data) diff --git a/src/Utils/Memory.hpp b/src/Utils/Memory.hpp index ebe34333..68ca4661 100644 --- a/src/Utils/Memory.hpp +++ b/src/Utils/Memory.hpp @@ -14,6 +14,11 @@ namespace Utils this->RefMemory.clear(); } ~Allocator() + { + this->Free(); + } + + void Free() { for (auto i = this->RefMemory.begin(); i != this->RefMemory.end(); ++i) {